From 6d2e82b254fef19f51a45cf92c62e2b8d3ce3c6c Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Tue, 12 Aug 2025 07:49:05 +0900 Subject: [PATCH 001/585] update rotate operation doc --- compiler/rustc_codegen_gcc/src/intrinsic/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index eb0a5336a1f1..82275d8833a4 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -493,9 +493,10 @@ fn codegen_intrinsic_call( } sym::bitreverse => self.bit_reverse(width, args[0].immediate()), sym::rotate_left | sym::rotate_right => { - // TODO(antoyo): implement using algorithm from: + // Using optimized branchless algorithm from: // https://blog.regehr.org/archives/1063 - // for other platforms. + // This implementation uses the pattern (x<>(-n&(width-1))) + // which generates efficient code for other platforms. let is_left = name == sym::rotate_left; let val = args[0].immediate(); let raw_shift = args[1].immediate(); From 92c2bda4239f071c192e8487cd5fd374b9943a7d Mon Sep 17 00:00:00 2001 From: tinnamchoi Date: Wed, 20 Aug 2025 03:38:05 +0800 Subject: [PATCH 002/585] [std][BTree] Create tests for keys which can be `==` without being identical --- .../alloc/src/collections/btree/map/tests.rs | 30 ++++++++++++++++++- library/alloctests/testing/ord_chaos.rs | 30 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 79879d31d3df..085834df9a68 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -11,7 +11,7 @@ use crate::rc::Rc; use crate::string::{String, ToString}; use crate::testing::crash_test::{CrashTestDummy, Panic}; -use crate::testing::ord_chaos::{Cyclic3, Governed, Governor}; +use crate::testing::ord_chaos::{Cyclic3, Governed, Governor, IdBased}; use crate::testing::rng::DeterministicRng; // Minimum number of elements to insert, to guarantee a tree with 2 levels, @@ -2587,3 +2587,31 @@ fn cursor_peek_prev_agrees_with_cursor_mut() { let prev = cursor.peek_prev(); assert_matches!(prev, Some((&3, _))); } + +#[test] +fn test_id_based_insert() { + let mut lhs = BTreeMap::new(); + let mut rhs = BTreeMap::new(); + + lhs.insert(IdBased { id: 0, name: "lhs_k".to_string() }, "lhs_v".to_string()); + rhs.insert(IdBased { id: 0, name: "rhs_k".to_string() }, "rhs_v".to_string()); + + for (k, v) in rhs.into_iter() { + lhs.insert(k, v); + } + + assert_eq!(lhs.pop_first().unwrap().0.name, "lhs_k".to_string()); +} + +#[test] +fn test_id_based_append() { + let mut lhs = BTreeMap::new(); + let mut rhs = BTreeMap::new(); + + lhs.insert(IdBased { id: 0, name: "lhs_k".to_string() }, "lhs_v".to_string()); + rhs.insert(IdBased { id: 0, name: "rhs_k".to_string() }, "rhs_v".to_string()); + + lhs.append(&mut rhs); + + assert_eq!(lhs.pop_first().unwrap().0.name, "lhs_k".to_string()); +} diff --git a/library/alloctests/testing/ord_chaos.rs b/library/alloctests/testing/ord_chaos.rs index 55e1ae5e3dea..f90ba1c69921 100644 --- a/library/alloctests/testing/ord_chaos.rs +++ b/library/alloctests/testing/ord_chaos.rs @@ -2,6 +2,8 @@ use std::cmp::Ordering::{self, *}; use std::ptr; +use crate::string::String; + // Minimal type with an `Ord` implementation violating transitivity. #[derive(Debug)] pub(crate) enum Cyclic3 { @@ -79,3 +81,31 @@ fn eq(&self, other: &Self) -> bool { } impl Eq for Governed<'_, T> {} + +// Comparison based only on the ID, the name is ignored. +#[derive(Debug)] +pub(crate) struct IdBased { + pub id: u32, + #[allow(dead_code)] + pub name: String, +} + +impl PartialEq for IdBased { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl Eq for IdBased {} + +impl PartialOrd for IdBased { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for IdBased { + fn cmp(&self, other: &Self) -> Ordering { + self.id.cmp(&other.id) + } +} From ffd8320d9e19dc43906bce6226e3adb928c74556 Mon Sep 17 00:00:00 2001 From: tinnamchoi Date: Wed, 20 Aug 2025 02:43:38 +0800 Subject: [PATCH 003/585] [std][BTree] Fix behavior of `::append` to match documentation and `::insert` --- library/alloc/src/collections/btree/append.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index 091376d5d685..3569e6551dc0 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -107,6 +107,11 @@ impl Iterator for MergeIter /// If two keys are equal, returns the key-value pair from the right source. fn next(&mut self) -> Option<(K, V)> { let (a_next, b_next) = self.0.nexts(|a: &(K, V), b: &(K, V)| K::cmp(&a.0, &b.0)); - b_next.or(a_next) + match (a_next, b_next) { + (Some((a_k, _)), Some((_, b_v))) => Some((a_k, b_v)), + (Some(a), None) => Some(a), + (None, Some(b)) => Some(b), + (None, None) => None, + } } } From c541a2da14e57db73495987f07bbbc5a6a67c147 Mon Sep 17 00:00:00 2001 From: tinnamchoi Date: Wed, 20 Aug 2025 02:52:58 +0800 Subject: [PATCH 004/585] [std][BTree] Update tests --- library/alloc/src/collections/btree/map/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 085834df9a68..a61a2da172d1 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -2137,9 +2137,9 @@ fn test_append_drop_leak() { let mut left = BTreeMap::new(); let mut right = BTreeMap::new(); left.insert(a.spawn(Panic::Never), ()); - left.insert(b.spawn(Panic::InDrop), ()); // first duplicate key, dropped during append + left.insert(b.spawn(Panic::Never), ()); left.insert(c.spawn(Panic::Never), ()); - right.insert(b.spawn(Panic::Never), ()); + right.insert(b.spawn(Panic::InDrop), ()); // first duplicate key, dropped during append right.insert(c.spawn(Panic::Never), ()); catch_unwind(move || left.append(&mut right)).unwrap_err(); From 084e6e7320342b603834af97d4e1f521c249fc2f Mon Sep 17 00:00:00 2001 From: tinnamchoi Date: Wed, 20 Aug 2025 13:52:42 +0800 Subject: [PATCH 005/585] [std][BTree] Update doc-comment --- library/alloc/src/collections/btree/append.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index 3569e6551dc0..66ea22e75247 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -104,7 +104,7 @@ impl Iterator for MergeIter { type Item = (K, V); - /// If two keys are equal, returns the key-value pair from the right source. + /// If two keys are equal, returns the key from the left and the value from the right. fn next(&mut self) -> Option<(K, V)> { let (a_next, b_next) = self.0.nexts(|a: &(K, V), b: &(K, V)| K::cmp(&a.0, &b.0)); match (a_next, b_next) { From 002a09ae9ed008e07c2bccc2fca0779968c07931 Mon Sep 17 00:00:00 2001 From: tinnamchoi Date: Thu, 21 Aug 2025 19:03:07 +0800 Subject: [PATCH 006/585] [std][BTree] Update `::append` docs --- library/alloc/src/collections/btree/map.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index c4e599222e50..654859f49823 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1160,6 +1160,10 @@ pub fn retain(&mut self, mut f: F) /// /// If a key from `other` is already present in `self`, the respective /// value from `self` will be overwritten with the respective value from `other`. + /// Similar to [`insert`], though, the key is not overwritten, + /// which matters for types that can be `==` without being identical. + /// + /// [`insert`]: BTreeMap::insert /// /// # Examples /// From 35270f855720c700b9b064d0c07e2edcd0d5ad60 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Thu, 4 Sep 2025 04:07:46 +0000 Subject: [PATCH 007/585] Prepare for merging from rust-lang/rust This updates the rust-version file to 9385c64c95d971329e62917adc4349c8ccdbafe0. --- library/compiler-builtins/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version index 8489eacfcda2..7420b6200967 100644 --- a/library/compiler-builtins/rust-version +++ b/library/compiler-builtins/rust-version @@ -1 +1 @@ -d36f964125163c2e698de5559efefb8217b8b7f0 +9385c64c95d971329e62917adc4349c8ccdbafe0 From 04909ba40ab9bb7982c6009a21fb3b500c04c41b Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Fri, 5 Sep 2025 12:54:37 +0300 Subject: [PATCH 008/585] libm: define and implement `trait NarrowingDiv` for unsigned integer division New utility in `libm::support`: - `trait NarrowingDiv` for dividing `u2N / uN` when the quotient fits in `uN` - a reasonable implementation of that for primitives up to `u256 / u128` This is the inverse operation of unsigned widening multiplication: let xy: u256 = u128::widen_mul(x, y); assert_eq!(xy.checked_narrowing_div_rem(y), Some((x, 0))); // unless y == 0 The trait API is based on x86's `div`-instruction: quotient overflow happens exactly when the high half of the dividend is greater or equal to the divisor, which includes division by zero. --- .../libm-test/benches/icount.rs | 13 +- .../libm/src/math/support/big/tests.rs | 26 +++ .../libm/src/math/support/int_traits.rs | 3 + .../math/support/int_traits/narrowing_div.rs | 176 ++++++++++++++++++ .../libm/src/math/support/mod.rs | 3 +- 5 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/support/int_traits/narrowing_div.rs diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index 02ee13f804f1..0b85771225dd 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -111,6 +111,17 @@ fn icount_bench_u128_widen_mul(cases: Vec<(u128, u128)>) { } } +#[library_benchmark] +#[bench::linspace(setup_u128_mul())] +fn icount_bench_u256_narrowing_div(cases: Vec<(u128, u128)>) { + use libm::support::NarrowingDiv; + for (x, y) in cases.iter().copied() { + let x = black_box(x.widen_hi()); + let y = black_box(y); + black_box(x.checked_narrowing_div_rem(y)); + } +} + #[library_benchmark] #[bench::linspace(setup_u256_add())] fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { @@ -145,7 +156,7 @@ fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) { library_benchmark_group!( name = icount_bench_u128_group; - benchmarks = icount_bench_u128_widen_mul, icount_bench_u256_add, icount_bench_u256_sub, icount_bench_u256_shl, icount_bench_u256_shr + benchmarks = icount_bench_u128_widen_mul, icount_bench_u256_narrowing_div, icount_bench_u256_add, icount_bench_u256_sub, icount_bench_u256_shl, icount_bench_u256_shr ); #[library_benchmark] diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs index d54706c72607..0c32f445c136 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -3,6 +3,7 @@ use std::{eprintln, format}; use super::{HInt, MinInt, i256, u256}; +use crate::support::{Int as _, NarrowingDiv}; const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; @@ -336,3 +337,28 @@ fn i256_shifts() { x = y; } } +#[test] +fn div_u256_by_u128() { + for j in i8::MIN..=i8::MAX { + let y: u128 = (j as i128).rotate_right(4).unsigned(); + if y == 0 { + continue; + } + for i in i8::MIN..=i8::MAX { + let x: u128 = (i as i128).rotate_right(4).unsigned(); + let xy = x.widen_mul(y); + assert_eq!(xy.checked_narrowing_div_rem(y), Some((x, 0))); + if y != 1 { + assert_eq!((xy + u256::ONE).checked_narrowing_div_rem(y), Some((x, 1))); + } + if x != 0 { + assert_eq!( + (xy - u256::ONE).checked_narrowing_div_rem(y), + Some((x - 1, y - 1)) + ); + } + let r = ((y as f64) * 0.12345) as u128; + assert_eq!((xy + r.widen()).checked_narrowing_div_rem(y), Some((x, r))); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index 9d8826dfed3f..f1aa1e5b9b4d 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -1,5 +1,8 @@ use core::{cmp, fmt, ops}; +mod narrowing_div; +pub use narrowing_div::NarrowingDiv; + /// Minimal integer implementations needed on all integer types, including wide integers. #[allow(dead_code)] // Some constants are only used with tests pub trait MinInt: diff --git a/library/compiler-builtins/libm/src/math/support/int_traits/narrowing_div.rs b/library/compiler-builtins/libm/src/math/support/int_traits/narrowing_div.rs new file mode 100644 index 000000000000..3da0843cc540 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/int_traits/narrowing_div.rs @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +use crate::support::{CastInto, DInt, HInt, Int, MinInt, u256}; + +/// Trait for unsigned division of a double-wide integer +/// when the quotient doesn't overflow. +/// +/// This is the inverse of widening multiplication: +/// - for any `x` and nonzero `y`: `x.widen_mul(y).checked_narrowing_div_rem(y) == Some((x, 0))`, +/// - and for any `r in 0..y`: `x.carrying_mul(y, r).checked_narrowing_div_rem(y) == Some((x, r))`, +#[allow(dead_code)] +pub trait NarrowingDiv: DInt + MinInt { + /// Computes `(self / n, self % n))` + /// + /// # Safety + /// The caller must ensure that `self.hi() < n`, or equivalently, + /// that the quotient does not overflow. + unsafe fn unchecked_narrowing_div_rem(self, n: Self::H) -> (Self::H, Self::H); + + /// Returns `Some((self / n, self % n))` when `self.hi() < n`. + fn checked_narrowing_div_rem(self, n: Self::H) -> Option<(Self::H, Self::H)> { + if self.hi() < n { + Some(unsafe { self.unchecked_narrowing_div_rem(n) }) + } else { + None + } + } +} + +// For primitive types we can just use the standard +// division operators in the double-wide type. +macro_rules! impl_narrowing_div_primitive { + ($D:ident) => { + impl NarrowingDiv for $D { + unsafe fn unchecked_narrowing_div_rem(self, n: Self::H) -> (Self::H, Self::H) { + if self.hi() >= n { + unsafe { core::hint::unreachable_unchecked() } + } + ((self / n.widen()).cast(), (self % n.widen()).cast()) + } + } + }; +} + +// Extend division from `u2N / uN` to `u4N / u2N` +// This is not the most efficient algorithm, but it is +// relatively simple. +macro_rules! impl_narrowing_div_recurse { + ($D:ident) => { + impl NarrowingDiv for $D { + unsafe fn unchecked_narrowing_div_rem(self, n: Self::H) -> (Self::H, Self::H) { + if self.hi() >= n { + unsafe { core::hint::unreachable_unchecked() } + } + + // Normalize the divisor by shifting the most significant one + // to the leading position. `n != 0` is implied by `self.hi() < n` + let lz = n.leading_zeros(); + let a = self << lz; + let b = n << lz; + + let ah = a.hi(); + let (a0, a1) = a.lo().lo_hi(); + // SAFETY: For both calls, `b.leading_zeros() == 0` by the above shift. + // SAFETY: `ah < b` follows from `self.hi() < n` + let (q1, r) = unsafe { div_three_digits_by_two(a1, ah, b) }; + // SAFETY: `r < b` is given as the postcondition of the previous call + let (q0, r) = unsafe { div_three_digits_by_two(a0, r, b) }; + + // Undo the earlier normalization for the remainder + (Self::H::from_lo_hi(q0, q1), r >> lz) + } + } + }; +} + +impl_narrowing_div_primitive!(u16); +impl_narrowing_div_primitive!(u32); +impl_narrowing_div_primitive!(u64); +impl_narrowing_div_primitive!(u128); +impl_narrowing_div_recurse!(u256); + +/// Implement `u3N / u2N`-division on top of `u2N / uN`-division. +/// +/// Returns the quotient and remainder of `(a * R + a0) / n`, +/// where `R = (1 << U::BITS)` is the digit size. +/// +/// # Safety +/// Requires that `n.leading_zeros() == 0` and `a < n`. +unsafe fn div_three_digits_by_two(a0: U, a: U::D, n: U::D) -> (U, U::D) +where + U: HInt, + U::D: Int + NarrowingDiv, +{ + if n.leading_zeros() > 0 || a >= n { + unsafe { core::hint::unreachable_unchecked() } + } + + // n = n1R + n0 + let (n0, n1) = n.lo_hi(); + // a = a2R + a1 + let (a1, a2) = a.lo_hi(); + + let mut q; + let mut r; + let mut wrap; + // `a < n` is guaranteed by the caller, but `a2 == n1 && a1 < n0` is possible + if let Some((q0, r1)) = a.checked_narrowing_div_rem(n1) { + q = q0; + // a = qn1 + r1, where 0 <= r1 < n1 + + // Include the remainder with the low bits: + // r = a0 + r1R + r = U::D::from_lo_hi(a0, r1); + + // Subtract the contribution of the divisor low bits with the estimated quotient + let d = q.widen_mul(n0); + (r, wrap) = r.overflowing_sub(d); + + // Since `q` is the quotient of dividing with a slightly smaller divisor, + // it may be an overapproximation, but is never too small, and similarly, + // `r` is now either the correct remainder ... + if !wrap { + return (q, r); + } + // ... or the remainder went "negative" (by as much as `d = qn0 < RR`) + // and we have to adjust. + q -= U::ONE; + } else { + debug_assert!(a2 == n1 && a1 < n0); + // Otherwise, `a2 == n1`, and the estimated quotient would be + // `R + (a1 % n1)`, but the correct quotient can't overflow. + // We'll start from `q = R = (1 << U::BITS)`, + // so `r = aR + a0 - qn = (a - n)R + a0` + r = U::D::from_lo_hi(a0, a1.wrapping_sub(n0)); + // Since `a < n`, the first decrement is always needed: + q = U::MAX; /* R - 1 */ + } + + (r, wrap) = r.overflowing_add(n); + if wrap { + return (q, r); + } + + // If the remainder still didn't wrap, we need another step. + q -= U::ONE; + (r, wrap) = r.overflowing_add(n); + // Since `n >= RR/2`, at least one of the two `r += n` must have wrapped. + debug_assert!(wrap, "estimated quotient should be off by at most two"); + (q, r) +} + +#[cfg(test)] +mod test { + use super::{HInt, NarrowingDiv}; + + #[test] + fn inverse_mul() { + for x in 0..=u8::MAX { + for y in 1..=u8::MAX { + let xy = x.widen_mul(y); + assert_eq!(xy.checked_narrowing_div_rem(y), Some((x, 0))); + assert_eq!( + (xy + (y - 1) as u16).checked_narrowing_div_rem(y), + Some((x, y - 1)) + ); + if y > 1 { + assert_eq!((xy + 1).checked_narrowing_div_rem(y), Some((x, 1))); + assert_eq!( + (xy + (y - 2) as u16).checked_narrowing_div_rem(y), + Some((x, y - 2)) + ); + } + } + } + } +} diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index b2d7bd8d5567..7b529eb760b7 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -28,7 +28,8 @@ pub use hex_float::hf128; #[allow(unused_imports)] pub use hex_float::{hf32, hf64}; -pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +#[allow(unused_imports)] +pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt, NarrowingDiv}; /// Hint to the compiler that the current path is cold. pub fn cold_path() { From 641fc3f0926672c670be847f93152ef65402af4b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 30 May 2025 02:01:41 +0000 Subject: [PATCH 009/585] symcheck: Allow checking a standalone archive Provide an option to check without invoking Cargo first. --- .../crates/symbol-check/src/main.rs | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/crates/symbol-check/src/main.rs b/library/compiler-builtins/crates/symbol-check/src/main.rs index 4e94552331a0..3f45c77f006e 100644 --- a/library/compiler-builtins/crates/symbol-check/src/main.rs +++ b/library/compiler-builtins/crates/symbol-check/src/main.rs @@ -24,6 +24,10 @@ `compiler_builtins*.rlib` files will be checked. If TARGET is not specified, the host target is used. + + check ARCHIVE_PATHS ... + +Run the same checks on the given set of paths, without invoking Cargo. "; fn main() { @@ -33,12 +37,14 @@ fn main() { match &args_ref[1..] { ["build-and-check", target, "--", args @ ..] if !args.is_empty() => { - check_cargo_args(args); run_build_and_check(target, args); } ["build-and-check", "--", args @ ..] if !args.is_empty() => { - check_cargo_args(args); - run_build_and_check(&host_target(), args); + let target = &host_target(); + run_build_and_check(target, args); + } + ["check", paths @ ..] if !paths.is_empty() => { + check_paths(paths); } _ => { println!("{USAGE}"); @@ -47,22 +53,25 @@ fn main() { } } -/// Make sure `--target` isn't passed to avoid confusion (since it should be proivded only once, -/// positionally). -fn check_cargo_args(args: &[&str]) { +fn run_build_and_check(target: &str, args: &[&str]) { + // Make sure `--target` isn't passed to avoid confusion (since it should be + // proivded only once, positionally). for arg in args { assert!( !arg.contains("--target"), "target must be passed positionally. {USAGE}" ); } + + let paths = exec_cargo_with_args(target, args); + check_paths(&paths); } -fn run_build_and_check(target: &str, args: &[&str]) { - let paths = exec_cargo_with_args(target, args); +fn check_paths>(paths: &[P]) { for path in paths { + let path = path.as_ref(); println!("Checking {}", path.display()); - let archive = Archive::from_path(&path); + let archive = Archive::from_path(path); verify_no_duplicates(&archive); verify_core_symbols(&archive); From b2aa2200aab4d77b73ea40374a7090886d80d7ec Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 7 Sep 2025 04:42:44 -0400 Subject: [PATCH 010/585] symcheck: Support both archives and object files If parsing as an archive is unsuccessful, try parsing as an object instead before erroring out. --- .../crates/symbol-check/src/main.rs | 80 ++++++++++++------- 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/library/compiler-builtins/crates/symbol-check/src/main.rs b/library/compiler-builtins/crates/symbol-check/src/main.rs index 3f45c77f006e..7d0b7e90addb 100644 --- a/library/compiler-builtins/crates/symbol-check/src/main.rs +++ b/library/compiler-builtins/crates/symbol-check/src/main.rs @@ -7,9 +7,10 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; -use object::read::archive::{ArchiveFile, ArchiveMember}; +use object::read::archive::ArchiveFile; use object::{ - File as ObjFile, Object, ObjectSection, ObjectSymbol, Symbol, SymbolKind, SymbolScope, + File as ObjFile, Object, ObjectSection, ObjectSymbol, Result as ObjResult, Symbol, SymbolKind, + SymbolScope, }; use serde_json::Value; @@ -25,9 +26,10 @@ If TARGET is not specified, the host target is used. - check ARCHIVE_PATHS ... + check PATHS ... -Run the same checks on the given set of paths, without invoking Cargo. +Run the same checks on the given set of paths, without invoking Cargo. Paths +may be either archives or object files. "; fn main() { @@ -71,7 +73,7 @@ fn check_paths>(paths: &[P]) { for path in paths { let path = path.as_ref(); println!("Checking {}", path.display()); - let archive = Archive::from_path(path); + let archive = BinFile::from_path(path); verify_no_duplicates(&archive); verify_core_symbols(&archive); @@ -174,7 +176,7 @@ struct SymInfo { } impl SymInfo { - fn new(sym: &Symbol, obj: &ObjFile, member: &ArchiveMember) -> Self { + fn new(sym: &Symbol, obj: &ObjFile, obj_path: &str) -> Self { // Include the section name if possible. Fall back to the `Section` debug impl if not. let section = sym.section(); let section_name = sym @@ -196,7 +198,7 @@ fn new(sym: &Symbol, obj: &ObjFile, member: &ArchiveMember) -> Self { is_weak: sym.is_weak(), is_common: sym.is_common(), address: sym.address(), - object: String::from_utf8_lossy(member.name()).into_owned(), + object: obj_path.to_owned(), } } } @@ -206,7 +208,7 @@ fn new(sym: &Symbol, obj: &ObjFile, member: &ArchiveMember) -> Self { /// Note that this will also locate cases where a symbol is weakly defined in more than one place. /// Technically there are no linker errors that will come from this, but it keeps our binary more /// straightforward and saves some distribution size. -fn verify_no_duplicates(archive: &Archive) { +fn verify_no_duplicates(archive: &BinFile) { let mut syms = BTreeMap::::new(); let mut dups = Vec::new(); let mut found_any = false; @@ -263,7 +265,7 @@ fn verify_no_duplicates(archive: &Archive) { } /// Ensure that there are no references to symbols from `core` that aren't also (somehow) defined. -fn verify_core_symbols(archive: &Archive) { +fn verify_core_symbols(archive: &BinFile) { let mut defined = BTreeSet::new(); let mut undefined = Vec::new(); let mut has_symbols = false; @@ -298,39 +300,63 @@ fn verify_core_symbols(archive: &Archive) { } /// Thin wrapper for owning data used by `object`. -struct Archive { +struct BinFile { + path: PathBuf, data: Vec, } -impl Archive { +impl BinFile { fn from_path(path: &Path) -> Self { Self { + path: path.to_owned(), data: fs::read(path).expect("reading file failed"), } } - fn file(&self) -> ArchiveFile<'_> { - ArchiveFile::parse(self.data.as_slice()).expect("archive parse failed") + fn as_archive_file(&self) -> ObjResult> { + ArchiveFile::parse(self.data.as_slice()) } - /// For a given archive, do something with each object file. - fn for_each_object(&self, mut f: impl FnMut(ObjFile, &ArchiveMember)) { - let archive = self.file(); + fn as_obj_file(&self) -> ObjResult> { + ObjFile::parse(self.data.as_slice()) + } - for member in archive.members() { - let member = member.expect("failed to access member"); - let obj_data = member - .data(self.data.as_slice()) - .expect("failed to access object"); - let obj = ObjFile::parse(obj_data).expect("failed to parse object"); - f(obj, &member); + /// For a given archive, do something with each object file. For an object file, do + /// something once. + fn for_each_object(&self, mut f: impl FnMut(ObjFile, &str)) { + // Try as an archive first. + let as_archive = self.as_archive_file(); + if let Ok(archive) = as_archive { + for member in archive.members() { + let member = member.expect("failed to access member"); + let obj_data = member + .data(self.data.as_slice()) + .expect("failed to access object"); + let obj = ObjFile::parse(obj_data).expect("failed to parse object"); + f(obj, &String::from_utf8_lossy(member.name())); + } + + return; } + + // Fall back to parsing as an object file. + let as_obj = self.as_obj_file(); + if let Ok(obj) = as_obj { + f(obj, &self.path.to_string_lossy()); + return; + } + + panic!( + "failed to parse as either archive or object file: {:?}, {:?}", + as_archive.unwrap_err(), + as_obj.unwrap_err(), + ); } - /// For a given archive, do something with each symbol. - fn for_each_symbol(&self, mut f: impl FnMut(Symbol, &ObjFile, &ArchiveMember)) { - self.for_each_object(|obj, member| { - obj.symbols().for_each(|sym| f(sym, &obj, member)); + /// D something with each symbol in an archive or object file. + fn for_each_symbol(&self, mut f: impl FnMut(Symbol, &ObjFile, &str)) { + self.for_each_object(|obj, obj_path| { + obj.symbols().for_each(|sym| f(sym, &obj, obj_path)); }); } } From 3220121a33fd49b676d18e82895ea4f0dac3a01c Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Thu, 11 Sep 2025 05:22:44 +0900 Subject: [PATCH 011/585] ci: Use nextest on PowerPC64LE and s390x See https://github.com/taiki-e/install-action/issues/1056 for the context. --- library/compiler-builtins/.github/workflows/main.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 3afadbfe8941..16f958c881d3 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -132,10 +132,7 @@ jobs: rustup default "$channel" rustup target add "${{ matrix.target }}" - # Our scripts use nextest if possible. This is skipped on the native ppc - # and s390x runners since install-action doesn't support them. - uses: taiki-e/install-action@nextest - if: "!(matrix.os == 'ubuntu-24.04-ppc64le' || matrix.os == 'ubuntu-24.04-s390x')" - uses: Swatinem/rust-cache@v2 with: From bc57021f09e3c3e92e6f4d75f6a4f1af6dca9f7d Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sat, 13 Sep 2025 18:55:11 +0200 Subject: [PATCH 012/585] doc: Document that `os_version_check.c` is implemented in `std` Since https://github.com/rust-lang/rust/pull/138944. --- library/compiler-builtins/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/README.md b/library/compiler-builtins/compiler-builtins/README.md index 2d92b7651f98..a12bd2ee7349 100644 --- a/library/compiler-builtins/compiler-builtins/README.md +++ b/library/compiler-builtins/compiler-builtins/README.md @@ -374,7 +374,7 @@ Miscellaneous functionality that is not used by Rust. - ~~i386/fp_mode.c~~ - ~~int_util.c~~ - ~~loongarch/fp_mode.c~~ -- ~~os_version_check.c~~ +- ~~os_version_check.c~~ (implemented in `std` instead) - ~~riscv/fp_mode.c~~ - ~~riscv/restore.S~~ (callee-saved registers) - ~~riscv/save.S~~ (callee-saved registers) From 2b228ce31075811028c9447d2387ca037e4ac9ee Mon Sep 17 00:00:00 2001 From: bluurryy <164359728+bluurryy@users.noreply.github.com> Date: Sun, 21 Sep 2025 01:42:06 +0200 Subject: [PATCH 013/585] Implement `Allocator` for `&mut A` where `A: Allocator + ?Sized` --- library/core/src/alloc/mod.rs | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 9d608d5e83c4..680b1ec105a2 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -421,3 +421,58 @@ unsafe fn shrink( unsafe { (**self).shrink(ptr, old_layout, new_layout) } } } + +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl Allocator for &mut A +where + A: Allocator + ?Sized, +{ + #[inline] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate(layout) + } + + #[inline] + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate_zeroed(layout) + } + + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).deallocate(ptr, layout) } + } + + #[inline] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).shrink(ptr, old_layout, new_layout) } + } +} From ee1b36a2434dadd44d580aa4114d3c6c2eb6afd2 Mon Sep 17 00:00:00 2001 From: cyrgani <85427285+cyrgani@users.noreply.github.com> Date: Mon, 22 Sep 2025 20:51:08 +0200 Subject: [PATCH 014/585] Remove usage of the to-be-deprecated `core::f32`, `core::f64` items Needed for https://github.com/rust-lang/rust/pull/146882. --- .../libm-test/src/precision.rs | 2 -- .../compiler-builtins/libm/src/math/atan.rs | 20 +++++++++---------- .../compiler-builtins/libm/src/math/cbrtf.rs | 2 -- .../compiler-builtins/libm/src/math/expm1.rs | 2 -- .../compiler-builtins/libm/src/math/hypot.rs | 2 -- .../compiler-builtins/libm/src/math/hypotf.rs | 2 -- .../compiler-builtins/libm/src/math/log10.rs | 2 -- .../compiler-builtins/libm/src/math/log10f.rs | 2 -- .../compiler-builtins/libm/src/math/log1p.rs | 2 -- .../compiler-builtins/libm/src/math/log1pf.rs | 2 -- .../compiler-builtins/libm/src/math/log2.rs | 2 -- .../compiler-builtins/libm/src/math/log2f.rs | 2 -- .../libm/src/math/rem_pio2f.rs | 2 -- 13 files changed, 9 insertions(+), 35 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index 3fb8c1b37109..c441922d302b 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -1,8 +1,6 @@ //! Configuration for skipping or changing the result for individual test cases (inputs) rather //! than ignoring entire tests. -use core::f32; - use CheckBasis::{Mpfr, Musl}; use libm::support::CastFrom; use {BaseName as Bn, Identifier as Id}; diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index 0590ba87cf85..a303ebd42f0d 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -29,8 +29,6 @@ * to produce the hexadecimal values shown. */ -use core::f64; - use super::fabs; const ATANHI: [f64; 4] = [ @@ -134,19 +132,19 @@ pub fn atan(x: f64) -> f64 { #[cfg(test)] mod tests { - use core::f64; + use core::f64::consts; use super::atan; #[test] fn sanity_check() { for (input, answer) in [ - (3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6), - (1.0, f64::consts::FRAC_PI_4), - (3.0_f64.sqrt(), f64::consts::FRAC_PI_3), - (-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6), - (-1.0, -f64::consts::FRAC_PI_4), - (-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3), + (3.0_f64.sqrt() / 3.0, consts::FRAC_PI_6), + (1.0, consts::FRAC_PI_4), + (3.0_f64.sqrt(), consts::FRAC_PI_3), + (-3.0_f64.sqrt() / 3.0, -consts::FRAC_PI_6), + (-1.0, -consts::FRAC_PI_4), + (-3.0_f64.sqrt(), -consts::FRAC_PI_3), ] .iter() { @@ -167,12 +165,12 @@ fn zero() { #[test] fn infinity() { - assert_eq!(atan(f64::INFINITY), f64::consts::FRAC_PI_2); + assert_eq!(atan(f64::INFINITY), consts::FRAC_PI_2); } #[test] fn minus_infinity() { - assert_eq!(atan(f64::NEG_INFINITY), -f64::consts::FRAC_PI_2); + assert_eq!(atan(f64::NEG_INFINITY), -consts::FRAC_PI_2); } #[test] diff --git a/library/compiler-builtins/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/src/math/cbrtf.rs index 9d69584834a3..6916ca6735b6 100644 --- a/library/compiler-builtins/libm/src/math/cbrtf.rs +++ b/library/compiler-builtins/libm/src/math/cbrtf.rs @@ -17,8 +17,6 @@ * Return cube root of x */ -use core::f32; - const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs index 3714bf3afc93..3ce1d886bb19 100644 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -10,8 +10,6 @@ * ==================================================== */ -use core::f64; - const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs index b92ee18ca110..c0b2a19370cd 100644 --- a/library/compiler-builtins/libm/src/math/hypot.rs +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -1,5 +1,3 @@ -use core::f64; - use super::sqrt; const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 diff --git a/library/compiler-builtins/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/src/math/hypotf.rs index e7635ffc9a0b..dfb36d4b23ed 100644 --- a/library/compiler-builtins/libm/src/math/hypotf.rs +++ b/library/compiler-builtins/libm/src/math/hypotf.rs @@ -1,5 +1,3 @@ -use core::f32; - use super::sqrtf; #[cfg_attr(assert_no_panic, no_panic::no_panic)] diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs index 29f25d944af9..228c00a5b2ff 100644 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -17,8 +17,6 @@ * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) */ -use core::f64; - const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ const IVLN10LO: f64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ const LOG10_2HI: f64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs index f89584bf9c99..f72fcf9e1e27 100644 --- a/library/compiler-builtins/libm/src/math/log10f.rs +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -13,8 +13,6 @@ * See comments in log10.c. */ -use core::f32; - const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */ const IVLN10LO: f32 = -3.1689971365e-05; /* 0xb804ead9 */ const LOG10_2HI: f32 = 3.0102920532e-01; /* 0x3e9a2080 */ diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index c991cce60df0..c2f9eb89be60 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -53,8 +53,6 @@ * See HP-15C Advanced Functions Handbook, p.193. */ -use core::f64; - const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index 89a92fac98ee..2e4775b8de90 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -10,8 +10,6 @@ * ==================================================== */ -use core::f32; - const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index 9b750c9a2a6c..0f72fe0b84dc 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -17,8 +17,6 @@ * log2(x) = (f - f*f/2 + r)/log(2) + k */ -use core::f64; - const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ const IVLN2LO: f64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs index 0e5177d7afa8..78673675a915 100644 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -13,8 +13,6 @@ * See comments in log2.c. */ -use core::f32; - const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */ const IVLN2LO: f32 = -1.7605285393e-04; /* 0xb9389ad4 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 0472a10355a0..481f7ee830bb 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -14,8 +14,6 @@ * ==================================================== */ -use core::f64; - use super::rem_pio2_large; const TOINT: f64 = 1.5 / f64::EPSILON; From a7cfc82b642019cf3b25e8c025d4a240809afa7a Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Thu, 25 Sep 2025 04:12:30 +0000 Subject: [PATCH 015/585] Prepare for merging from rust-lang/rust This updates the rust-version file to caccb4d0368bd918ef6668af8e13834d07040417. --- library/compiler-builtins/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version index 7420b6200967..8854fb95997b 100644 --- a/library/compiler-builtins/rust-version +++ b/library/compiler-builtins/rust-version @@ -1 +1 @@ -9385c64c95d971329e62917adc4349c8ccdbafe0 +caccb4d0368bd918ef6668af8e13834d07040417 From 37be71b0451269ecb9a4477862e3ef08290b34fa Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 25 Sep 2025 19:58:00 +0000 Subject: [PATCH 016/585] Add back the `unsafe` for `intrinsics::fma` but `allow(unused_unsafe)` Rustc commit 055e05a338af / builtins commit 2fb3a1871bc9 ("Mark float intrinsics with no preconditions as safe") changed `fma` and other intrinsics to not be unsafe to call. Unfortunately we can't remove the `unsafe` just yet since the rustc we pin for benchmarks is older than this. Add back `unsafe` but allow it to be unused. --- .../compiler-builtins/libm/src/math/support/float_traits.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index b5ee6413d553..4e5011f62e0f 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -289,7 +289,10 @@ fn fma(self, y: Self, z: Self) -> Self { cfg_if! { // fma is not yet available in `core` if #[cfg(intrinsics_enabled)] { - core::intrinsics::$fma_intrinsic(self, y, z) + // FIXME(msrv,bench): once our benchmark rustc version is above the + // 2022-09-23 nightly, this can be removed. + #[allow(unused_unsafe)] + unsafe { core::intrinsics::$fma_intrinsic(self, y, z) } } else { super::super::$fma_fn(self, y, z) } From 321cd2aa25318eb2f565b06d26ced5111e1fd15f Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 22 Sep 2025 22:55:22 +0200 Subject: [PATCH 017/585] remove duplicated columns from `rustc_error_code::error_codes!` --- .../src/error_codes/E0773.md | 2 +- compiler/rustc_error_codes/src/lib.rs | 1040 ++++++++--------- compiler/rustc_errors/src/codes.rs | 8 +- compiler/rustc_errors/src/lib.rs | 1 + src/tools/tidy/src/error_codes.rs | 46 +- 5 files changed, 535 insertions(+), 562 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0773.md b/compiler/rustc_error_codes/src/error_codes/E0773.md index 5ebb43c6683e..91cf005d5471 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0773.md +++ b/compiler/rustc_error_codes/src/error_codes/E0773.md @@ -1,4 +1,4 @@ -#### this error code is no longer emitted by the compiler. +#### Note: this error code is no longer emitted by the compiler. This was triggered when multiple macro definitions used the same `#[rustc_builtin_macro(..)]`. This is no longer an error. diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 0aff1c06e0a8..a7bcab444788 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -21,533 +21,531 @@ // Also, the contents of this macro is checked by tidy (in `check_error_codes_docs`). If you change // the macro syntax you will need to change tidy as well. // -// Both columns are necessary because it's not possible in Rust to create a new identifier such as -// `E0123` from an integer literal such as `0123`, unfortunately. -// -// Do *not* remove entries from this list. Instead, just add a note th the corresponding markdown +// Do *not* remove entries from this list. Instead, just add a note to the corresponding markdown // file saying that this error is not emitted by the compiler any more (see E0001.md for an // example), and remove all code examples that do not build any more. #[macro_export] +#[rustfmt::skip] macro_rules! error_codes { ($macro:path) => ( $macro!( -E0001: 0001, -E0002: 0002, -E0004: 0004, -E0005: 0005, -E0007: 0007, -E0009: 0009, -E0010: 0010, -E0013: 0013, -E0014: 0014, -E0015: 0015, -E0023: 0023, -E0025: 0025, -E0026: 0026, -E0027: 0027, -E0029: 0029, -E0030: 0030, -E0033: 0033, -E0034: 0034, -E0038: 0038, -E0040: 0040, -E0044: 0044, -E0045: 0045, -E0046: 0046, -E0049: 0049, -E0050: 0050, -E0053: 0053, -E0054: 0054, -E0055: 0055, -E0057: 0057, -E0059: 0059, -E0060: 0060, -E0061: 0061, -E0062: 0062, -E0063: 0063, -E0067: 0067, -E0069: 0069, -E0070: 0070, -E0071: 0071, -E0072: 0072, -E0073: 0073, -E0074: 0074, -E0075: 0075, -E0076: 0076, -E0077: 0077, -E0080: 0080, -E0081: 0081, -E0084: 0084, -E0087: 0087, -E0088: 0088, -E0089: 0089, -E0090: 0090, -E0091: 0091, -E0092: 0092, -E0093: 0093, -E0094: 0094, -E0106: 0106, -E0107: 0107, -E0109: 0109, -E0110: 0110, -E0116: 0116, -E0117: 0117, -E0118: 0118, -E0119: 0119, -E0120: 0120, -E0121: 0121, -E0124: 0124, -E0128: 0128, -E0130: 0130, -E0131: 0131, -E0132: 0132, -E0133: 0133, -E0136: 0136, -E0137: 0137, -E0138: 0138, -E0139: 0139, -E0152: 0152, -E0154: 0154, -E0158: 0158, -E0161: 0161, -E0162: 0162, -E0164: 0164, -E0165: 0165, -E0170: 0170, -E0178: 0178, -E0183: 0183, -E0184: 0184, -E0185: 0185, -E0186: 0186, -E0191: 0191, -E0192: 0192, -E0193: 0193, -E0195: 0195, -E0197: 0197, -E0198: 0198, -E0199: 0199, -E0200: 0200, -E0201: 0201, -E0203: 0203, -E0204: 0204, -E0205: 0205, -E0206: 0206, -E0207: 0207, -E0208: 0208, -E0210: 0210, -E0211: 0211, -E0212: 0212, -E0214: 0214, -E0220: 0220, -E0221: 0221, -E0222: 0222, -E0223: 0223, -E0224: 0224, -E0225: 0225, -E0226: 0226, -E0227: 0227, -E0228: 0228, -E0229: 0229, -E0230: 0230, -E0231: 0231, -E0232: 0232, -E0243: 0243, -E0244: 0244, -E0251: 0251, -E0252: 0252, -E0253: 0253, -E0254: 0254, -E0255: 0255, -E0256: 0256, -E0259: 0259, -E0260: 0260, -E0261: 0261, -E0262: 0262, -E0263: 0263, -E0264: 0264, -E0267: 0267, -E0268: 0268, -E0271: 0271, -E0275: 0275, -E0276: 0276, -E0277: 0277, -E0281: 0281, -E0282: 0282, -E0283: 0283, -E0284: 0284, -E0297: 0297, -E0301: 0301, -E0302: 0302, -E0303: 0303, -E0307: 0307, -E0308: 0308, -E0309: 0309, -E0310: 0310, -E0311: 0311, -E0312: 0312, -E0316: 0316, -E0317: 0317, -E0320: 0320, -E0321: 0321, -E0322: 0322, -E0323: 0323, -E0324: 0324, -E0325: 0325, -E0326: 0326, -E0328: 0328, -E0329: 0329, -E0364: 0364, -E0365: 0365, -E0366: 0366, -E0367: 0367, -E0368: 0368, -E0369: 0369, -E0370: 0370, -E0371: 0371, -E0373: 0373, -E0374: 0374, -E0375: 0375, -E0376: 0376, -E0377: 0377, -E0378: 0378, -E0379: 0379, -E0380: 0380, -E0381: 0381, -E0382: 0382, -E0383: 0383, -E0384: 0384, -E0386: 0386, -E0387: 0387, -E0388: 0388, -E0389: 0389, -E0390: 0390, -E0391: 0391, -E0392: 0392, -E0393: 0393, -E0398: 0398, -E0399: 0399, -E0401: 0401, -E0403: 0403, -E0404: 0404, -E0405: 0405, -E0407: 0407, -E0408: 0408, -E0409: 0409, -E0411: 0411, -E0412: 0412, -E0415: 0415, -E0416: 0416, -E0422: 0422, -E0423: 0423, -E0424: 0424, -E0425: 0425, -E0426: 0426, -E0428: 0428, -E0429: 0429, -E0430: 0430, -E0431: 0431, -E0432: 0432, -E0433: 0433, -E0434: 0434, -E0435: 0435, -E0436: 0436, -E0437: 0437, -E0438: 0438, -E0439: 0439, -E0445: 0445, -E0446: 0446, -E0447: 0447, -E0448: 0448, -E0449: 0449, -E0451: 0451, -E0452: 0452, -E0453: 0453, -E0454: 0454, -E0455: 0455, -E0457: 0457, -E0458: 0458, -E0459: 0459, -E0460: 0460, -E0461: 0461, -E0462: 0462, -E0463: 0463, -E0464: 0464, -E0466: 0466, -E0468: 0468, -E0469: 0469, -E0472: 0472, -E0476: 0476, -E0477: 0477, -E0478: 0478, -E0482: 0482, -E0491: 0491, -E0492: 0492, -E0493: 0493, -E0495: 0495, -E0496: 0496, -E0497: 0497, -E0498: 0498, -E0499: 0499, -E0500: 0500, -E0501: 0501, -E0502: 0502, -E0503: 0503, -E0504: 0504, -E0505: 0505, -E0506: 0506, -E0507: 0507, -E0508: 0508, -E0509: 0509, -E0510: 0510, -E0511: 0511, -E0512: 0512, -E0514: 0514, -E0515: 0515, -E0516: 0516, -E0517: 0517, -E0518: 0518, -E0519: 0519, -E0520: 0520, -E0521: 0521, -E0522: 0522, -E0523: 0523, -E0524: 0524, -E0525: 0525, -E0527: 0527, -E0528: 0528, -E0529: 0529, -E0530: 0530, -E0531: 0531, -E0532: 0532, -E0533: 0533, -E0534: 0534, -E0535: 0535, -E0536: 0536, -E0537: 0537, -E0538: 0538, -E0539: 0539, -E0541: 0541, -E0542: 0542, -E0543: 0543, -E0544: 0544, -E0545: 0545, -E0546: 0546, -E0547: 0547, -E0549: 0549, -E0550: 0550, -E0551: 0551, -E0552: 0552, -E0554: 0554, -E0556: 0556, -E0557: 0557, -E0559: 0559, -E0560: 0560, -E0561: 0561, -E0562: 0562, -E0565: 0565, -E0566: 0566, -E0567: 0567, -E0568: 0568, -E0569: 0569, -E0570: 0570, -E0571: 0571, -E0572: 0572, -E0573: 0573, -E0574: 0574, -E0575: 0575, -E0576: 0576, -E0577: 0577, -E0578: 0578, -E0579: 0579, -E0580: 0580, -E0581: 0581, -E0582: 0582, -E0583: 0583, -E0584: 0584, -E0585: 0585, -E0586: 0586, -E0587: 0587, -E0588: 0588, -E0589: 0589, -E0590: 0590, -E0591: 0591, -E0592: 0592, -E0593: 0593, -E0594: 0594, -E0595: 0595, -E0596: 0596, -E0597: 0597, -E0599: 0599, -E0600: 0600, -E0601: 0601, -E0602: 0602, -E0603: 0603, -E0604: 0604, -E0605: 0605, -E0606: 0606, -E0607: 0607, -E0608: 0608, -E0609: 0609, -E0610: 0610, -E0614: 0614, -E0615: 0615, -E0616: 0616, -E0617: 0617, -E0618: 0618, -E0619: 0619, -E0620: 0620, -E0621: 0621, -E0622: 0622, // REMOVED: rustc-intrinsic ABI was removed -E0623: 0623, -E0624: 0624, -E0625: 0625, -E0626: 0626, -E0627: 0627, -E0628: 0628, -E0631: 0631, -E0632: 0632, -E0633: 0633, -E0634: 0634, -E0635: 0635, -E0636: 0636, -E0637: 0637, -E0638: 0638, -E0639: 0639, -E0640: 0640, -E0641: 0641, -E0642: 0642, -E0643: 0643, -E0644: 0644, -E0646: 0646, -E0647: 0647, -E0648: 0648, -E0657: 0657, -E0658: 0658, -E0659: 0659, -E0660: 0660, -E0661: 0661, -E0662: 0662, -E0663: 0663, -E0664: 0664, -E0665: 0665, -E0666: 0666, -E0667: 0667, -E0668: 0668, -E0669: 0669, -E0670: 0670, -E0671: 0671, -E0687: 0687, -E0688: 0688, -E0689: 0689, -E0690: 0690, -E0691: 0691, -E0692: 0692, -E0693: 0693, -E0695: 0695, -E0696: 0696, -E0697: 0697, -E0698: 0698, -E0699: 0699, // REMOVED: merged into generic inference var error -E0700: 0700, -E0701: 0701, -E0703: 0703, -E0704: 0704, -E0705: 0705, -E0706: 0706, -E0708: 0708, -E0710: 0710, -E0712: 0712, -E0713: 0713, -E0714: 0714, -E0715: 0715, -E0716: 0716, -E0711: 0711, -E0717: 0717, -E0718: 0718, -E0719: 0719, -E0720: 0720, -E0722: 0722, -E0724: 0724, -E0725: 0725, -E0726: 0726, -E0727: 0727, -E0728: 0728, -E0729: 0729, -E0730: 0730, -E0731: 0731, -E0732: 0732, -E0733: 0733, -E0734: 0734, -E0735: 0735, -E0736: 0736, -E0737: 0737, -E0739: 0739, -E0740: 0740, -E0741: 0741, -E0742: 0742, -E0743: 0743, -E0744: 0744, -E0745: 0745, -E0746: 0746, -E0747: 0747, -E0748: 0748, -E0749: 0749, -E0750: 0750, -E0751: 0751, -E0752: 0752, -E0753: 0753, -E0754: 0754, -E0755: 0755, -E0756: 0756, -E0757: 0757, -E0758: 0758, -E0759: 0759, -E0760: 0760, -E0761: 0761, -E0762: 0762, -E0763: 0763, -E0764: 0764, -E0765: 0765, -E0766: 0766, -E0767: 0767, -E0768: 0768, -E0769: 0769, -E0770: 0770, -E0771: 0771, -E0772: 0772, -E0773: 0773, -E0774: 0774, -E0775: 0775, -E0776: 0776, -E0777: 0777, -E0778: 0778, -E0779: 0779, -E0780: 0780, -E0781: 0781, -E0782: 0782, -E0783: 0783, -E0784: 0784, -E0785: 0785, -E0786: 0786, -E0787: 0787, -E0788: 0788, -E0789: 0789, -E0790: 0790, -E0791: 0791, -E0792: 0792, -E0793: 0793, -E0794: 0794, -E0795: 0795, -E0796: 0796, -E0797: 0797, -E0798: 0798, -E0799: 0799, -E0800: 0800, -E0801: 0801, -E0802: 0802, -E0803: 0803, -E0804: 0804, -E0805: 0805, +0001, +0002, +0004, +0005, +0007, +0009, +0010, +0013, +0014, +0015, +0023, +0025, +0026, +0027, +0029, +0030, +0033, +0034, +0038, +0040, +0044, +0045, +0046, +0049, +0050, +0053, +0054, +0055, +0057, +0059, +0060, +0061, +0062, +0063, +0067, +0069, +0070, +0071, +0072, +0073, +0074, +0075, +0076, +0077, +0080, +0081, +0084, +0087, +0088, +0089, +0090, +0091, +0092, +0093, +0094, +0106, +0107, +0109, +0110, +0116, +0117, +0118, +0119, +0120, +0121, +0124, +0128, +0130, +0131, +0132, +0133, +0136, +0137, +0138, +0139, +0152, +0154, +0158, +0161, +0162, +0164, +0165, +0170, +0178, +0183, +0184, +0185, +0186, +0191, +0192, +0193, +0195, +0197, +0198, +0199, +0200, +0201, +0203, +0204, +0205, +0206, +0207, +0208, +0210, +0211, +0212, +0214, +0220, +0221, +0222, +0223, +0224, +0225, +0226, +0227, +0228, +0229, +0230, +0231, +0232, +0243, +0244, +0251, +0252, +0253, +0254, +0255, +0256, +0259, +0260, +0261, +0262, +0263, +0264, +0267, +0268, +0271, +0275, +0276, +0277, +0281, +0282, +0283, +0284, +0297, +0301, +0302, +0303, +0307, +0308, +0309, +0310, +0311, +0312, +0316, +0317, +0320, +0321, +0322, +0323, +0324, +0325, +0326, +0328, +0329, +0364, +0365, +0366, +0367, +0368, +0369, +0370, +0371, +0373, +0374, +0375, +0376, +0377, +0378, +0379, +0380, +0381, +0382, +0383, +0384, +0386, +0387, +0388, +0389, +0390, +0391, +0392, +0393, +0398, +0399, +0401, +0403, +0404, +0405, +0407, +0408, +0409, +0411, +0412, +0415, +0416, +0422, +0423, +0424, +0425, +0426, +0428, +0429, +0430, +0431, +0432, +0433, +0434, +0435, +0436, +0437, +0438, +0439, +0445, +0446, +0447, +0448, +0449, +0451, +0452, +0453, +0454, +0455, +0457, +0458, +0459, +0460, +0461, +0462, +0463, +0464, +0466, +0468, +0469, +0472, +0476, +0477, +0478, +0482, +0491, +0492, +0493, +0495, +0496, +0497, +0498, +0499, +0500, +0501, +0502, +0503, +0504, +0505, +0506, +0507, +0508, +0509, +0510, +0511, +0512, +0514, +0515, +0516, +0517, +0518, +0519, +0520, +0521, +0522, +0523, +0524, +0525, +0527, +0528, +0529, +0530, +0531, +0532, +0533, +0534, +0535, +0536, +0537, +0538, +0539, +0541, +0542, +0543, +0544, +0545, +0546, +0547, +0549, +0550, +0551, +0552, +0554, +0556, +0557, +0559, +0560, +0561, +0562, +0565, +0566, +0567, +0568, +0569, +0570, +0571, +0572, +0573, +0574, +0575, +0576, +0577, +0578, +0579, +0580, +0581, +0582, +0583, +0584, +0585, +0586, +0587, +0588, +0589, +0590, +0591, +0592, +0593, +0594, +0595, +0596, +0597, +0599, +0600, +0601, +0602, +0603, +0604, +0605, +0606, +0607, +0608, +0609, +0610, +0614, +0615, +0616, +0617, +0618, +0619, +0620, +0621, +0622, // REMOVED: rustc-intrinsic ABI was removed +0623, +0624, +0625, +0626, +0627, +0628, +0631, +0632, +0633, +0634, +0635, +0636, +0637, +0638, +0639, +0640, +0641, +0642, +0643, +0644, +0646, +0647, +0648, +0657, +0658, +0659, +0660, +0661, +0662, +0663, +0664, +0665, +0666, +0667, +0668, +0669, +0670, +0671, +0687, +0688, +0689, +0690, +0691, +0692, +0693, +0695, +0696, +0697, +0698, +0699, // REMOVED: merged into generic inference var error +0700, +0701, +0703, +0704, +0705, +0706, +0708, +0710, +0712, +0713, +0714, +0715, +0716, +0711, +0717, +0718, +0719, +0720, +0722, +0724, +0725, +0726, +0727, +0728, +0729, +0730, +0731, +0732, +0733, +0734, +0735, +0736, +0737, +0739, +0740, +0741, +0742, +0743, +0744, +0745, +0746, +0747, +0748, +0749, +0750, +0751, +0752, +0753, +0754, +0755, +0756, +0757, +0758, +0759, +0760, +0761, +0762, +0763, +0764, +0765, +0766, +0767, +0768, +0769, +0770, +0771, +0772, +0773, // REMOVED: no longer an error +0774, +0775, +0776, +0777, +0778, +0779, +0780, +0781, +0782, +0783, +0784, +0785, +0786, +0787, +0788, +0789, +0790, +0791, +0792, +0793, +0794, +0795, +0796, +0797, +0798, +0799, +0800, +0801, +0802, +0803, +0804, +0805, ); ) } diff --git a/compiler/rustc_errors/src/codes.rs b/compiler/rustc_errors/src/codes.rs index 787a8af99b1f..924924f285eb 100644 --- a/compiler/rustc_errors/src/codes.rs +++ b/compiler/rustc_errors/src/codes.rs @@ -23,15 +23,15 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { rustc_error_messages::into_diag_arg_using_display!(ErrCode); macro_rules! define_error_code_constants_and_diagnostics_table { - ($($name:ident: $num:literal,)*) => ( + ($($num:literal,)*) => ( $( - pub const $name: $crate::ErrCode = $crate::ErrCode::from_u32($num); + pub const ${concat(E, $num)}: $crate::ErrCode = $crate::ErrCode::from_u32($num); )* pub static DIAGNOSTICS: &[($crate::ErrCode, &str)] = &[ $( ( - $name, + ${concat(E, $num)}, include_str!( - concat!("../../rustc_error_codes/src/error_codes/", stringify!($name), ".md") + concat!("../../rustc_error_codes/src/error_codes/E", stringify!($num), ".md") ) ), )* ]; diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 8869799ce90d..ad2b3c74270a 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -15,6 +15,7 @@ #![feature(box_patterns)] #![feature(default_field_values)] #![feature(error_reporter)] +#![feature(macro_metavar_expr_concat)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index 83fbefa43d97..240ac839e3e3 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -91,20 +91,16 @@ fn extract_error_codes(root_path: &Path, check: &mut RunningCheck) -> Vec(); + if chars.next() != Some(',') { check.error(format!( - "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \ - but got \"{line}\" without a `:` delimiter", + "{path}:{line_index}: Expected a line with the format `abcd,` \ + but got \"{line}\" without a `,` delimiter", )); continue; - }; - - let err_code = split_line.0.to_owned(); + } // If this is a duplicate of another error code, emit a fatal error. if error_codes.contains(&err_code) { @@ -114,35 +110,13 @@ fn extract_error_codes(root_path: &Path, check: &mut RunningCheck) -> Vec Date: Sat, 11 Oct 2025 18:52:58 +0800 Subject: [PATCH 018/585] Suppress the error for private fields with non_exhaustive attribute --- compiler/rustc_hir_typeck/src/expr.rs | 6 ++++- .../auxiliary/non_exhaustive_with_private.rs | 13 +++++++++++ ...n-exhaustive-with-private-fields-147513.rs | 17 ++++++++++++++ ...haustive-with-private-fields-147513.stderr | 23 +++++++++++++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 tests/ui/privacy/auxiliary/non_exhaustive_with_private.rs create mode 100644 tests/ui/privacy/non-exhaustive-with-private-fields-147513.rs create mode 100644 tests/ui/privacy/non-exhaustive-with-private-fields-147513.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 1aaf02646c79..9aaf34a0fd1c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2331,7 +2331,11 @@ struct definition", } }; self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr.hir_id, fru_tys); - } else if adt_kind != AdtKind::Union && !remaining_fields.is_empty() { + } else if adt_kind != AdtKind::Union + && !remaining_fields.is_empty() + //~ non_exhaustive already reported, which will only happen for extern modules + && !variant.field_list_has_applicable_non_exhaustive() + { debug!(?remaining_fields); let private_fields: Vec<&ty::FieldDef> = variant .fields diff --git a/tests/ui/privacy/auxiliary/non_exhaustive_with_private.rs b/tests/ui/privacy/auxiliary/non_exhaustive_with_private.rs new file mode 100644 index 000000000000..18e63db0cdd1 --- /dev/null +++ b/tests/ui/privacy/auxiliary/non_exhaustive_with_private.rs @@ -0,0 +1,13 @@ +// Auxiliary crate for testing non-exhaustive struct with private fields + +#[non_exhaustive] +pub struct Foo { + pub my_field: u32, + private_field: i32, +} + +#[non_exhaustive] +pub struct Bar { + pub my_field: u32, + pub missing_field: i32, +} diff --git a/tests/ui/privacy/non-exhaustive-with-private-fields-147513.rs b/tests/ui/privacy/non-exhaustive-with-private-fields-147513.rs new file mode 100644 index 000000000000..0553ff6c781e --- /dev/null +++ b/tests/ui/privacy/non-exhaustive-with-private-fields-147513.rs @@ -0,0 +1,17 @@ +//@ aux-build:non_exhaustive_with_private.rs + +extern crate non_exhaustive_with_private; + +use non_exhaustive_with_private::{Bar, Foo}; + +fn main() { + let foo = Foo { + //~^ ERROR cannot create non-exhaustive struct using struct expression + my_field: 10, + }; + + let bar = Bar { + //~^ ERROR cannot create non-exhaustive struct using struct expression + my_field: 10, + }; +} diff --git a/tests/ui/privacy/non-exhaustive-with-private-fields-147513.stderr b/tests/ui/privacy/non-exhaustive-with-private-fields-147513.stderr new file mode 100644 index 000000000000..85bf7e4847d7 --- /dev/null +++ b/tests/ui/privacy/non-exhaustive-with-private-fields-147513.stderr @@ -0,0 +1,23 @@ +error[E0639]: cannot create non-exhaustive struct using struct expression + --> $DIR/non-exhaustive-with-private-fields-147513.rs:8:15 + | +LL | let foo = Foo { + | _______________^ +LL | | +LL | | my_field: 10, +LL | | }; + | |_____^ + +error[E0639]: cannot create non-exhaustive struct using struct expression + --> $DIR/non-exhaustive-with-private-fields-147513.rs:13:15 + | +LL | let bar = Bar { + | _______________^ +LL | | +LL | | my_field: 10, +LL | | }; + | |_____^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0639`. From e4194c7075ae35d45bdec1b779a2b57c400af60b Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 12 Oct 2025 16:51:28 +0900 Subject: [PATCH 019/585] Deduplicate higher-ranked lifetime capture errors in impl Trait Previously, when an `impl Trait` captured multiple higher-ranked lifetimes from an outer `impl Trait`, the compiler would emit a separate error for each captured lifetime. This resulted in verbose and confusing diagnostics, especially in edition 2024 where implicit captures caused duplicate errors. This commit introduces error accumulation that collects all capture spans and lifetime declaration spans, then emits a single consolidated diagnostic using MultiSpan. The new error shows all captured lifetimes with visual indicators and lists all declarations in a single note. --- .../src/collect/resolve_bound_vars.rs | 69 ++++++++++++++++--- compiler/rustc_hir_analysis/src/errors.rs | 4 +- tests/ui/error-codes/E0657.stderr | 8 +-- ...e-capture-deduplication.edition2015.stderr | 17 +++++ ...e-capture-deduplication.edition2024.stderr | 17 +++++ ...r-ranked-lifetime-capture-deduplication.rs | 26 +++++++ .../ui/impl-trait/impl-fn-hrtb-bounds.stderr | 18 +++-- .../impl-fn-parsing-ambiguities.stderr | 6 +- .../issues/issue-54895.edition2015.stderr | 6 +- .../issues/issue-54895.edition2024.stderr | 18 ++--- tests/ui/impl-trait/issues/issue-54895.rs | 1 - tests/ui/impl-trait/issues/issue-67830.stderr | 6 +- .../ui/impl-trait/issues/issue-88236-2.stderr | 18 +++-- tests/ui/impl-trait/issues/issue-88236.stderr | 6 +- tests/ui/impl-trait/nested-rpit-hrtb.stderr | 20 +++--- .../bound-lifetime-through-dyn-trait.stderr | 4 +- .../escaping-bound-var.rs | 1 - .../escaping-bound-var.stderr | 16 +---- 18 files changed, 185 insertions(+), 76 deletions(-) create mode 100644 tests/ui/impl-trait/higher-ranked-lifetime-capture-deduplication.edition2015.stderr create mode 100644 tests/ui/impl-trait/higher-ranked-lifetime-capture-deduplication.edition2024.stderr create mode 100644 tests/ui/impl-trait/higher-ranked-lifetime-capture-deduplication.rs diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 8133f9f68234..6f7ce916c7ac 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -66,6 +66,13 @@ struct BoundVarContext<'a, 'tcx> { rbv: &'a mut ResolveBoundVars, disambiguator: &'a mut DisambiguatorState, scope: ScopeRef<'a>, + opaque_capture_errors: RefCell>, +} + +struct OpaqueHigherRankedLifetimeCaptureErrors { + bad_place: &'static str, + capture_spans: Vec, + decl_spans: Vec, } #[derive(Debug)] @@ -253,6 +260,7 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou rbv: &mut rbv, scope: &Scope::Root { opt_parent_item: None }, disambiguator: &mut DisambiguatorState::new(), + opaque_capture_errors: RefCell::new(None), }; match tcx.hir_owner_node(local_def_id) { hir::OwnerNode::Item(item) => visitor.visit_item(item), @@ -597,6 +605,8 @@ fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) { }) }); + self.emit_opaque_capture_errors(); + let captures = captures.into_inner().into_iter().collect(); debug!(?captures); self.rbv.opaque_captured_lifetimes.insert(opaque.def_id, captures); @@ -1089,12 +1099,20 @@ fn with(&mut self, wrap_scope: Scope<'_>, f: F) F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>), { let BoundVarContext { tcx, rbv, disambiguator, .. } = self; - let mut this = BoundVarContext { tcx: *tcx, rbv, disambiguator, scope: &wrap_scope }; + let nested_errors = RefCell::new(self.opaque_capture_errors.borrow_mut().take()); + let mut this = BoundVarContext { + tcx: *tcx, + rbv, + disambiguator, + scope: &wrap_scope, + opaque_capture_errors: nested_errors, + }; let span = debug_span!("scope", scope = ?this.scope.debug_truncated()); { let _enter = span.enter(); f(&mut this); } + *self.opaque_capture_errors.borrow_mut() = this.opaque_capture_errors.into_inner(); } fn record_late_bound_vars(&mut self, hir_id: HirId, binder: Vec) { @@ -1424,21 +1442,52 @@ fn check_lifetime_is_capturable( }; let decl_span = self.tcx.def_span(lifetime_def_id); - let (span, label) = if capture_span != decl_span { - (capture_span, None) - } else { - let opaque_span = self.tcx.def_span(opaque_def_id); - (opaque_span, Some(opaque_span)) - }; + let opaque_span = self.tcx.def_span(opaque_def_id); + + let mut errors = self.opaque_capture_errors.borrow_mut(); + let error_info = errors.get_or_insert_with(|| OpaqueHigherRankedLifetimeCaptureErrors { + bad_place, + capture_spans: Vec::new(), + decl_spans: Vec::new(), + }); + + if error_info.capture_spans.is_empty() { + error_info.capture_spans.push(opaque_span); + } + + if capture_span != decl_span && capture_span != opaque_span { + error_info.capture_spans.push(capture_span); + } + + if !error_info.decl_spans.contains(&decl_span) { + error_info.decl_spans.push(decl_span); + } + + // Errors should be emitted by `emit_opaque_capture_errors`. + Err(self.tcx.dcx().span_delayed_bug(capture_span, "opaque capture error not emitted")) + } + + fn emit_opaque_capture_errors(&self) -> Option { + let errors = self.opaque_capture_errors.borrow_mut().take()?; + if errors.capture_spans.is_empty() { + return None; + } + + let mut span = rustc_errors::MultiSpan::from_span(errors.capture_spans[0]); + for &capture_span in &errors.capture_spans[1..] { + span.push_span_label(capture_span, ""); + } + let decl_span = rustc_errors::MultiSpan::from_spans(errors.decl_spans); // Ensure that the parent of the def is an item, not HRTB let guar = self.tcx.dcx().emit_err(errors::OpaqueCapturesHigherRankedLifetime { span, - label, + label: Some(errors.capture_spans[0]), decl_span, - bad_place, + bad_place: errors.bad_place, }); - Err(guar) + + Some(guar) } #[instrument(level = "trace", skip(self, opaque_capture_scopes), ret)] diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 49c510642288..c0cb6f732799 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1562,11 +1562,11 @@ pub(crate) struct UnconstrainedGenericParameter { #[diag(hir_analysis_opaque_captures_higher_ranked_lifetime, code = E0657)] pub(crate) struct OpaqueCapturesHigherRankedLifetime { #[primary_span] - pub span: Span, + pub span: MultiSpan, #[label] pub label: Option, #[note] - pub decl_span: Span, + pub decl_span: MultiSpan, pub bad_place: &'static str, } diff --git a/tests/ui/error-codes/E0657.stderr b/tests/ui/error-codes/E0657.stderr index c9dfc9eb9069..1d69af5d9654 100644 --- a/tests/ui/error-codes/E0657.stderr +++ b/tests/ui/error-codes/E0657.stderr @@ -1,8 +1,8 @@ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type - --> $DIR/E0657.rs:10:35 + --> $DIR/E0657.rs:10:27 | LL | -> Box Id>> - | ^^ + | ^^^^^^^^--^ `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/E0657.rs:10:20 @@ -11,10 +11,10 @@ LL | -> Box Id>> | ^^ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type - --> $DIR/E0657.rs:19:39 + --> $DIR/E0657.rs:19:31 | LL | -> Box Id>> - | ^^ + | ^^^^^^^^--^ `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/E0657.rs:19:24 diff --git a/tests/ui/impl-trait/higher-ranked-lifetime-capture-deduplication.edition2015.stderr b/tests/ui/impl-trait/higher-ranked-lifetime-capture-deduplication.edition2015.stderr new file mode 100644 index 000000000000..8954a802ab95 --- /dev/null +++ b/tests/ui/impl-trait/higher-ranked-lifetime-capture-deduplication.edition2015.stderr @@ -0,0 +1,17 @@ +error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` + --> $DIR/higher-ranked-lifetime-capture-deduplication.rs:19:44 + | +LL | fn f() -> impl for<'a, 'b> Trait<'a, Out = impl Sized + 'a + 'b> { + | ^^^^^^^^^^^^^--^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope + | +note: lifetime declared here + --> $DIR/higher-ranked-lifetime-capture-deduplication.rs:19:20 + | +LL | fn f() -> impl for<'a, 'b> Trait<'a, Out = impl Sized + 'a + 'b> { + | ^^ ^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0657`. diff --git a/tests/ui/impl-trait/higher-ranked-lifetime-capture-deduplication.edition2024.stderr b/tests/ui/impl-trait/higher-ranked-lifetime-capture-deduplication.edition2024.stderr new file mode 100644 index 000000000000..8954a802ab95 --- /dev/null +++ b/tests/ui/impl-trait/higher-ranked-lifetime-capture-deduplication.edition2024.stderr @@ -0,0 +1,17 @@ +error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` + --> $DIR/higher-ranked-lifetime-capture-deduplication.rs:19:44 + | +LL | fn f() -> impl for<'a, 'b> Trait<'a, Out = impl Sized + 'a + 'b> { + | ^^^^^^^^^^^^^--^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope + | +note: lifetime declared here + --> $DIR/higher-ranked-lifetime-capture-deduplication.rs:19:20 + | +LL | fn f() -> impl for<'a, 'b> Trait<'a, Out = impl Sized + 'a + 'b> { + | ^^ ^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0657`. diff --git a/tests/ui/impl-trait/higher-ranked-lifetime-capture-deduplication.rs b/tests/ui/impl-trait/higher-ranked-lifetime-capture-deduplication.rs new file mode 100644 index 000000000000..d8da93e5560d --- /dev/null +++ b/tests/ui/impl-trait/higher-ranked-lifetime-capture-deduplication.rs @@ -0,0 +1,26 @@ +//@revisions: edition2015 edition2024 +//@[edition2015] edition:2015 +//@[edition2024] edition:2024 + +trait Trait<'a> { + type Out; + fn call(&'a self) -> Self::Out; +} + +struct X(()); + +impl<'a> Trait<'a> for X { + type Out = (); + fn call(&'a self) -> Self::Out { + () + } +} + +fn f() -> impl for<'a, 'b> Trait<'a, Out = impl Sized + 'a + 'b> { + //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` + X(()) +} + +fn main() { + let _ = f(); +} diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr index 40cb6b647d1e..36f52e8103a3 100644 --- a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr +++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr @@ -12,10 +12,12 @@ LL + fn d() -> impl Fn() -> (impl Debug + 'static) { | error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/impl-fn-hrtb-bounds.rs:4:41 + --> $DIR/impl-fn-hrtb-bounds.rs:4:28 | LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) { - | ^^ + | ^^^^^^^^^^^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/impl-fn-hrtb-bounds.rs:4:19 @@ -24,10 +26,12 @@ LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) { | ^ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/impl-fn-hrtb-bounds.rs:9:52 + --> $DIR/impl-fn-hrtb-bounds.rs:9:39 | LL | fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) { - | ^^ + | ^^^^^^^^^^^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/impl-fn-hrtb-bounds.rs:9:20 @@ -36,10 +40,12 @@ LL | fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) { | ^^ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/impl-fn-hrtb-bounds.rs:14:52 + --> $DIR/impl-fn-hrtb-bounds.rs:14:39 | LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) { - | ^^ + | ^^^^^^^^^^^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/impl-fn-hrtb-bounds.rs:14:20 diff --git a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr index 94b6ffdd9123..5ba9567e14e3 100644 --- a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr +++ b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr @@ -21,10 +21,12 @@ LL | fn b() -> impl Fn() -> (impl Debug + Send) { | + + error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/impl-fn-parsing-ambiguities.rs:4:40 + --> $DIR/impl-fn-parsing-ambiguities.rs:4:27 | LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ { - | ^^ + | ^^^^^^^^^^^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/impl-fn-parsing-ambiguities.rs:4:19 diff --git a/tests/ui/impl-trait/issues/issue-54895.edition2015.stderr b/tests/ui/impl-trait/issues/issue-54895.edition2015.stderr index 27a3c6c8b7ce..8348a1d5e87b 100644 --- a/tests/ui/impl-trait/issues/issue-54895.edition2015.stderr +++ b/tests/ui/impl-trait/issues/issue-54895.edition2015.stderr @@ -1,8 +1,10 @@ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/issue-54895.rs:18:53 + --> $DIR/issue-54895.rs:18:40 | LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> { - | ^^ + | ^^^^^^^^^^^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/issue-54895.rs:18:20 diff --git a/tests/ui/impl-trait/issues/issue-54895.edition2024.stderr b/tests/ui/impl-trait/issues/issue-54895.edition2024.stderr index 54aa29e62d88..8348a1d5e87b 100644 --- a/tests/ui/impl-trait/issues/issue-54895.edition2024.stderr +++ b/tests/ui/impl-trait/issues/issue-54895.edition2024.stderr @@ -2,7 +2,9 @@ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `imp --> $DIR/issue-54895.rs:18:40 | LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> { - | ^^^^^^^^^^^^^^^ `impl Trait` implicitly captures all lifetimes in scope + | ^^^^^^^^^^^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/issue-54895.rs:18:20 @@ -10,18 +12,6 @@ note: lifetime declared here LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> { | ^^ -error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/issue-54895.rs:18:53 - | -LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> { - | ^^ - | -note: lifetime declared here - --> $DIR/issue-54895.rs:18:20 - | -LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> { - | ^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0657`. diff --git a/tests/ui/impl-trait/issues/issue-54895.rs b/tests/ui/impl-trait/issues/issue-54895.rs index bc1841209e17..ccdb0ce20f9a 100644 --- a/tests/ui/impl-trait/issues/issue-54895.rs +++ b/tests/ui/impl-trait/issues/issue-54895.rs @@ -17,7 +17,6 @@ fn call(&'a self) -> Self::Out { fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> { //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - //[edition2024]~^^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` X(()) } diff --git a/tests/ui/impl-trait/issues/issue-67830.stderr b/tests/ui/impl-trait/issues/issue-67830.stderr index a7633c7f20b6..7254955ed0bd 100644 --- a/tests/ui/impl-trait/issues/issue-67830.stderr +++ b/tests/ui/impl-trait/issues/issue-67830.stderr @@ -1,8 +1,10 @@ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/issue-67830.rs:20:64 + --> $DIR/issue-67830.rs:20:48 | LL | fn test() -> impl for<'a> MyFn<&'a A, Output = impl Iterator + 'a> { - | ^^ + | ^^^^^^^^^^^^^^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/issue-67830.rs:20:23 diff --git a/tests/ui/impl-trait/issues/issue-88236-2.stderr b/tests/ui/impl-trait/issues/issue-88236-2.stderr index 4ded9ed386fa..3943c4121845 100644 --- a/tests/ui/impl-trait/issues/issue-88236-2.stderr +++ b/tests/ui/impl-trait/issues/issue-88236-2.stderr @@ -1,8 +1,10 @@ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/issue-88236-2.rs:15:61 + --> $DIR/issue-88236-2.rs:15:49 | LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} - | ^^ + | ^^^^^^^^^^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/issue-88236-2.rs:15:28 @@ -11,10 +13,12 @@ LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} | ^^ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/issue-88236-2.rs:18:80 + --> $DIR/issue-88236-2.rs:18:68 | LL | fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { - | ^^ + | ^^^^^^^^^^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/issue-88236-2.rs:18:47 @@ -23,10 +27,12 @@ LL | fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Sen | ^^ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/issue-88236-2.rs:23:78 + --> $DIR/issue-88236-2.rs:23:66 | LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { - | ^^ + | ^^^^^^^^^^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/issue-88236-2.rs:23:45 diff --git a/tests/ui/impl-trait/issues/issue-88236.stderr b/tests/ui/impl-trait/issues/issue-88236.stderr index 5dee5f88c89f..6303379288b7 100644 --- a/tests/ui/impl-trait/issues/issue-88236.stderr +++ b/tests/ui/impl-trait/issues/issue-88236.stderr @@ -1,8 +1,10 @@ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/issue-88236.rs:15:61 + --> $DIR/issue-88236.rs:15:49 | LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} - | ^^ + | ^^^^^^^^^^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/issue-88236.rs:15:28 diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.stderr b/tests/ui/impl-trait/nested-rpit-hrtb.stderr index 93cd7bd788f4..130723035b1a 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.stderr +++ b/tests/ui/impl-trait/nested-rpit-hrtb.stderr @@ -30,10 +30,12 @@ LL | fn two_htrb_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl for<'b | ++++ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/nested-rpit-hrtb.rs:25:69 + --> $DIR/nested-rpit-hrtb.rs:25:56 | LL | fn one_hrtb_outlives() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'a> {} - | ^^ + | ^^^^^^^^^^^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/nested-rpit-hrtb.rs:25:36 @@ -42,10 +44,10 @@ LL | fn one_hrtb_outlives() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'a> {} | ^^ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/nested-rpit-hrtb.rs:29:68 + --> $DIR/nested-rpit-hrtb.rs:29:59 | LL | fn one_hrtb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl Qux<'a>> {} - | ^^ + | ^^^^^^^^^--^ `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/nested-rpit-hrtb.rs:29:39 @@ -54,10 +56,12 @@ LL | fn one_hrtb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl Qux<'a>> {} | ^^ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/nested-rpit-hrtb.rs:32:74 + --> $DIR/nested-rpit-hrtb.rs:32:61 | LL | fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {} - | ^^ + | ^^^^^^^^^^^^^-- + | | + | `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/nested-rpit-hrtb.rs:32:41 @@ -66,10 +70,10 @@ LL | fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a | ^^ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/nested-rpit-hrtb.rs:35:73 + --> $DIR/nested-rpit-hrtb.rs:35:64 | LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} - | ^^ + | ^^^^^^^^^--^ `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/nested-rpit-hrtb.rs:35:44 diff --git a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr index 7219fda4772a..6f0c6bb22060 100644 --- a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr +++ b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr @@ -1,8 +1,8 @@ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type - --> $DIR/bound-lifetime-through-dyn-trait.rs:6:71 + --> $DIR/bound-lifetime-through-dyn-trait.rs:6:57 | LL | fn dyn_hoops() -> dyn for<'a> Iterator> { - | ^^ + | ^^^^^^^^^^^^^^--^ `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/bound-lifetime-through-dyn-trait.rs:6:37 diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs index 31bdd0815ec3..4b17448080ed 100644 --- a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs +++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs @@ -8,7 +8,6 @@ trait Test<'a> {} pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` -//~| ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` impl Trait<'_> for () { type Assoc = (); diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr index c9f0618639af..cdbcfa6f3dc9 100644 --- a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr +++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr @@ -2,7 +2,7 @@ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `imp --> $DIR/escaping-bound-var.rs:9:47 | LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; - | ^^^^^^^^^^^^^ `impl Trait` implicitly captures all lifetimes in scope + | ^^^^^^^^^^--^ `impl Trait` implicitly captures all lifetimes in scope | note: lifetime declared here --> $DIR/escaping-bound-var.rs:9:25 @@ -10,18 +10,6 @@ note: lifetime declared here LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; | ^^ -error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/escaping-bound-var.rs:9:57 - | -LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; - | ^^ - | -note: lifetime declared here - --> $DIR/escaping-bound-var.rs:9:25 - | -LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; - | ^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0657`. From 3fadbd50b099b873b8631bc39158ce83d0845768 Mon Sep 17 00:00:00 2001 From: Dan54 Date: Thu, 16 Oct 2025 01:33:22 +0100 Subject: [PATCH 020/585] Add bounds to clamp error message --- library/core/src/cmp.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 7f369d19c3d1..e50984bb781d 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1997,6 +1997,19 @@ impl const Ord for $t { fn cmp(&self, other: &Self) -> Ordering { crate::intrinsics::three_way_compare(*self, *other) } + + #[inline] + fn clamp(self, min: Self, max: Self) -> Self + { + assert!(min <= max, "min > max. min = {min}, max = {max}"); + if self < min { + min + } else if self > max { + max + } else { + self + } + } } )*) } From f7d7a35daf9cb25b0b5ed0c76d176df66eb2a4e4 Mon Sep 17 00:00:00 2001 From: Dan54 Date: Thu, 16 Oct 2025 02:03:39 +0100 Subject: [PATCH 021/585] track_caller for clamp --- library/core/src/cmp.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index e50984bb781d..3bc4c28a9d81 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1999,6 +1999,7 @@ fn cmp(&self, other: &Self) -> Ordering { } #[inline] + #[track_caller] fn clamp(self, min: Self, max: Self) -> Self { assert!(min <= max, "min > max. min = {min}, max = {max}"); From 6dbea1f0a257862d1fcc1582f80fbd701dc5f18e Mon Sep 17 00:00:00 2001 From: Dan54 Date: Thu, 16 Oct 2025 03:04:51 +0100 Subject: [PATCH 022/585] use const_assert! --- library/core/src/cmp.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 3bc4c28a9d81..feb9c4319604 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1855,6 +1855,7 @@ mod impls { use crate::hint::unreachable_unchecked; use crate::marker::PointeeSized; use crate::ops::ControlFlow::{self, Break, Continue}; + use crate::panic::const_assert; macro_rules! partial_eq_impl { ($($t:ty)*) => ($( @@ -2002,7 +2003,13 @@ fn cmp(&self, other: &Self) -> Ordering { #[track_caller] fn clamp(self, min: Self, max: Self) -> Self { - assert!(min <= max, "min > max. min = {min}, max = {max}"); + const_assert!( + min <= max, + "min > max", + "min > max. min = {min:?}, max = {max:?}", + min: $t, + max: $t, + ); if self < min { min } else if self > max { From ce4265663ded513b905f2371ba85cc119bae07e5 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 10 Oct 2025 00:21:33 +0200 Subject: [PATCH 023/585] make the suggestions verbose they are much readable this way imo --- .../src/matches/match_like_matches.rs | 46 +++--- tests/ui/match_like_matches_macro.stderr | 135 ++++++++++++++++-- 2 files changed, 150 insertions(+), 31 deletions(-) diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index b5f631e8fea3..63bef58409ea 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -1,7 +1,7 @@ //! Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!` use super::REDUNDANT_PATTERN_MATCHING; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_lint_allowed, is_wild, span_contains_comment}; use rustc_ast::LitKind; @@ -43,18 +43,23 @@ pub(crate) fn check_if_let<'tcx>( { ex_new = ex_inner; } - span_lint_and_sugg( + span_lint_and_then( cx, MATCH_LIKE_MATCHES_MACRO, expr.span, - "if let .. else expression looks like `matches!` macro", - "try", - format!( - "{}matches!({}, {pat})", - if b0 { "" } else { "!" }, - snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), - ), - applicability, + "`if let .. else` expression looks like `matches!` macro", + |diag| { + diag.span_suggestion_verbose( + expr.span, + "use `matches!` directly", + format!( + "{}matches!({}, {pat})", + if b0 { "" } else { "!" }, + snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), + ), + applicability, + ); + }, ); } } @@ -169,18 +174,23 @@ pub(super) fn check_match<'tcx>( { ex_new = ex_inner; } - span_lint_and_sugg( + span_lint_and_then( cx, MATCH_LIKE_MATCHES_MACRO, e.span, "match expression looks like `matches!` macro", - "try", - format!( - "{}matches!({}, {pat_and_guard})", - if b0 { "" } else { "!" }, - snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), - ), - applicability, + |diag| { + diag.span_suggestion_verbose( + e.span, + "use `matches!` directly", + format!( + "{}matches!({}, {pat_and_guard})", + if b0 { "" } else { "!" }, + snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), + ), + applicability, + ); + }, ); true } else { diff --git a/tests/ui/match_like_matches_macro.stderr b/tests/ui/match_like_matches_macro.stderr index ae277ce4dca6..8ea13e04422e 100644 --- a/tests/ui/match_like_matches_macro.stderr +++ b/tests/ui/match_like_matches_macro.stderr @@ -6,10 +6,18 @@ LL | let _y = match x { LL | | Some(0) => true, LL | | _ => false, LL | | }; - | |_____^ help: try: `matches!(x, Some(0))` + | |_____^ | = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::match_like_matches_macro)]` +help: use `matches!` directly + | +LL - let _y = match x { +LL - Some(0) => true, +LL - _ => false, +LL - }; +LL + let _y = matches!(x, Some(0)); + | error: redundant pattern matching, consider using `is_some()` --> tests/ui/match_like_matches_macro.rs:20:14 @@ -42,13 +50,28 @@ LL | let _zz = match x { LL | | Some(r) if r == 0 => false, LL | | _ => true, LL | | }; - | |_____^ help: try: `!matches!(x, Some(r) if r == 0)` + | |_____^ + | +help: use `matches!` directly + | +LL - let _zz = match x { +LL - Some(r) if r == 0 => false, +LL - _ => true, +LL - }; +LL + let _zz = !matches!(x, Some(r) if r == 0); + | -error: if let .. else expression looks like `matches!` macro +error: `if let .. else` expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:41:16 | LL | let _zzz = if let Some(5) = x { true } else { false }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(x, Some(5))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `matches!` directly + | +LL - let _zzz = if let Some(5) = x { true } else { false }; +LL + let _zzz = matches!(x, Some(5)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:66:20 @@ -59,7 +82,17 @@ LL | | E::A(_) => true, LL | | E::B(_) => true, LL | | _ => false, LL | | }; - | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))` + | |_________^ + | +help: use `matches!` directly + | +LL - let _ans = match x { +LL - E::A(_) => true, +LL - E::B(_) => true, +LL - _ => false, +LL - }; +LL + let _ans = matches!(x, E::A(_) | E::B(_)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:77:20 @@ -71,7 +104,19 @@ LL | | true ... | LL | | _ => false, LL | | }; - | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))` + | |_________^ + | +help: use `matches!` directly + | +LL - let _ans = match x { +LL - E::A(_) => { +LL - true +LL - } +LL - E::B(_) => true, +LL - _ => false, +LL - }; +LL + let _ans = matches!(x, E::A(_) | E::B(_)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:88:20 @@ -82,7 +127,17 @@ LL | | E::B(_) => false, LL | | E::C => false, LL | | _ => true, LL | | }; - | |_________^ help: try: `!matches!(x, E::B(_) | E::C)` + | |_________^ + | +help: use `matches!` directly + | +LL - let _ans = match x { +LL - E::B(_) => false, +LL - E::C => false, +LL - _ => true, +LL - }; +LL + let _ans = !matches!(x, E::B(_) | E::C); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:149:18 @@ -92,7 +147,16 @@ LL | let _z = match &z { LL | | Some(3) => true, LL | | _ => false, LL | | }; - | |_________^ help: try: `matches!(z, Some(3))` + | |_________^ + | +help: use `matches!` directly + | +LL - let _z = match &z { +LL - Some(3) => true, +LL - _ => false, +LL - }; +LL + let _z = matches!(z, Some(3)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:159:18 @@ -102,7 +166,16 @@ LL | let _z = match &z { LL | | Some(3) => true, LL | | _ => false, LL | | }; - | |_________^ help: try: `matches!(&z, Some(3))` + | |_________^ + | +help: use `matches!` directly + | +LL - let _z = match &z { +LL - Some(3) => true, +LL - _ => false, +LL - }; +LL + let _z = matches!(&z, Some(3)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:177:21 @@ -112,7 +185,16 @@ LL | let _ = match &z { LL | | AnEnum::X => true, LL | | _ => false, LL | | }; - | |_____________^ help: try: `matches!(&z, AnEnum::X)` + | |_____________^ + | +help: use `matches!` directly + | +LL - let _ = match &z { +LL - AnEnum::X => true, +LL - _ => false, +LL - }; +LL + let _ = matches!(&z, AnEnum::X); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:192:20 @@ -122,7 +204,16 @@ LL | let _res = match &val { LL | | &Some(ref _a) => true, LL | | _ => false, LL | | }; - | |_________^ help: try: `matches!(&val, &Some(ref _a))` + | |_________^ + | +help: use `matches!` directly + | +LL - let _res = match &val { +LL - &Some(ref _a) => true, +LL - _ => false, +LL - }; +LL + let _res = matches!(&val, &Some(ref _a)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:205:20 @@ -132,7 +223,16 @@ LL | let _res = match &val { LL | | &Some(ref _a) => true, LL | | _ => false, LL | | }; - | |_________^ help: try: `matches!(&val, &Some(ref _a))` + | |_________^ + | +help: use `matches!` directly + | +LL - let _res = match &val { +LL - &Some(ref _a) => true, +LL - _ => false, +LL - }; +LL + let _res = matches!(&val, &Some(ref _a)); + | error: match expression looks like `matches!` macro --> tests/ui/match_like_matches_macro.rs:264:14 @@ -142,7 +242,16 @@ LL | let _y = match Some(5) { LL | | Some(0) => true, LL | | _ => false, LL | | }; - | |_____^ help: try: `matches!(Some(5), Some(0))` + | |_____^ + | +help: use `matches!` directly + | +LL - let _y = match Some(5) { +LL - Some(0) => true, +LL - _ => false, +LL - }; +LL + let _y = matches!(Some(5), Some(0)); + | error: aborting due to 14 previous errors From 7b83f421075bb9b8e68fb26570d18554a926526e Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 10 Oct 2025 00:01:51 +0200 Subject: [PATCH 024/585] fix(match_like_matches_macro): don't create `matches!` with if-let guards --- .../src/matches/match_like_matches.rs | 6 ++- tests/ui/match_like_matches_macro.fixed | 7 +++ tests/ui/match_like_matches_macro.rs | 10 ++++ tests/ui/match_like_matches_macro.stderr | 21 +++++++- .../match_like_matches_macro_if_let_guard.rs | 51 +++++++++++++++++++ 5 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 tests/ui/match_like_matches_macro_if_let_guard.rs diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index 63bef58409ea..89411115f730 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -2,6 +2,7 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::higher::has_let_expr; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_lint_allowed, is_wild, span_contains_comment}; use rustc_ast::LitKind; @@ -92,7 +93,10 @@ pub(super) fn check_match<'tcx>( // ```rs // matches!(e, Either::Left $(if $guard)|+) // ``` - middle_arms.is_empty() + // + // But if the guard _is_ present, it may not be an `if-let` guard, as `matches!` doesn't + // support these (currently?) + (middle_arms.is_empty() && first_arm.guard.is_none_or(|g| !has_let_expr(g))) // - (added in #6216) There are middle arms // diff --git a/tests/ui/match_like_matches_macro.fixed b/tests/ui/match_like_matches_macro.fixed index a1c95e8a94f1..dad59c1ce6e4 100644 --- a/tests/ui/match_like_matches_macro.fixed +++ b/tests/ui/match_like_matches_macro.fixed @@ -223,3 +223,10 @@ fn msrv_1_42() { let _y = matches!(Some(5), Some(0)); //~^^^^ match_like_matches_macro } + +#[expect(clippy::option_option)] +fn issue15841(opt: Option>>, value: i32) { + // Lint: no if-let _in the guard_ + let _ = matches!(opt, Some(first) if (if let Some(second) = first { true } else { todo!() })); + //~^^^^ match_like_matches_macro +} diff --git a/tests/ui/match_like_matches_macro.rs b/tests/ui/match_like_matches_macro.rs index eb419ba5bf8d..94bc6433e5cb 100644 --- a/tests/ui/match_like_matches_macro.rs +++ b/tests/ui/match_like_matches_macro.rs @@ -267,3 +267,13 @@ fn msrv_1_42() { }; //~^^^^ match_like_matches_macro } + +#[expect(clippy::option_option)] +fn issue15841(opt: Option>>, value: i32) { + // Lint: no if-let _in the guard_ + let _ = match opt { + Some(first) if (if let Some(second) = first { true } else { todo!() }) => true, + _ => false, + }; + //~^^^^ match_like_matches_macro +} diff --git a/tests/ui/match_like_matches_macro.stderr b/tests/ui/match_like_matches_macro.stderr index 8ea13e04422e..a8e352461dbb 100644 --- a/tests/ui/match_like_matches_macro.stderr +++ b/tests/ui/match_like_matches_macro.stderr @@ -253,5 +253,24 @@ LL - }; LL + let _y = matches!(Some(5), Some(0)); | -error: aborting due to 14 previous errors +error: match expression looks like `matches!` macro + --> tests/ui/match_like_matches_macro.rs:274:13 + | +LL | let _ = match opt { + | _____________^ +LL | | Some(first) if (if let Some(second) = first { true } else { todo!() }) => true, +LL | | _ => false, +LL | | }; + | |_____^ + | +help: use `matches!` directly + | +LL - let _ = match opt { +LL - Some(first) if (if let Some(second) = first { true } else { todo!() }) => true, +LL - _ => false, +LL - }; +LL + let _ = matches!(opt, Some(first) if (if let Some(second) = first { true } else { todo!() })); + | + +error: aborting due to 15 previous errors diff --git a/tests/ui/match_like_matches_macro_if_let_guard.rs b/tests/ui/match_like_matches_macro_if_let_guard.rs new file mode 100644 index 000000000000..b596d36072e5 --- /dev/null +++ b/tests/ui/match_like_matches_macro_if_let_guard.rs @@ -0,0 +1,51 @@ +//@check-pass +#![warn(clippy::match_like_matches_macro)] +#![feature(if_let_guard)] + +#[expect(clippy::option_option)] +fn issue15841(opt: Option>>, value: i32) { + let _ = match opt { + Some(first) + if let Some(second) = first + && let Some(third) = second + && third == value => + { + true + }, + _ => false, + }; + + // if-let is the second if + let _ = match opt { + Some(first) + if first.is_some() + && let Some(second) = first => + { + true + }, + _ => false, + }; + + // if-let is the third if + let _ = match opt { + Some(first) + if first.is_some() + && first.is_none() + && let Some(second) = first => + { + true + }, + _ => false, + }; + + // don't get confused by `or`s + let _ = match opt { + Some(first) + if (first.is_some() || first.is_none()) + && let Some(second) = first => + { + true + }, + _ => false, + }; +} From 3833ac3be02c3e9853570660224d14dced9250f2 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 8 Oct 2025 16:38:57 +0200 Subject: [PATCH 025/585] misc: use `Symbol`s instead of `&str`s --- .../methods/manual_saturating_arithmetic.rs | 67 ++++++++++++++----- clippy_lints/src/methods/mod.rs | 9 +-- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 2196ce92b0ab..21526c83c318 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -8,6 +8,7 @@ use rustc_hir::def::Res; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; +use rustc_span::Symbol; pub fn check( cx: &LateContext<'_>, @@ -15,7 +16,7 @@ pub fn check( arith_lhs: &hir::Expr<'_>, arith_rhs: &hir::Expr<'_>, unwrap_arg: &hir::Expr<'_>, - arith: &str, + arith: Symbol, ) { let ty = cx.typeck_results().expr_ty(arith_lhs); if !ty.is_integral() { @@ -26,35 +27,43 @@ pub fn check( return; }; - if ty.is_signed() { + let Some(checked_arith) = CheckedArith::new(arith) else { + return; + }; + + { use self::MinMax::{Max, Min}; use self::Sign::{Neg, Pos}; + use CheckedArith::{Add, Mul, Sub}; - let Some(sign) = lit_sign(arith_rhs) else { - return; - }; + if ty.is_signed() { + let Some(sign) = lit_sign(arith_rhs) else { + return; + }; - match (arith, sign, mm) { - ("add", Pos, Max) | ("add", Neg, Min) | ("sub", Neg, Max) | ("sub", Pos, Min) => (), - // "mul" is omitted because lhs can be negative. - _ => return, - } - } else { - match (mm, arith) { - (MinMax::Max, "add" | "mul") | (MinMax::Min, "sub") => (), - _ => return, + match (&checked_arith, sign, mm) { + (Add, Pos, Max) | (Add, Neg, Min) | (Sub, Neg, Max) | (Sub, Pos, Min) => (), + // "mul" is omitted because lhs can be negative. + _ => return, + } + } else { + match (mm, &checked_arith) { + (Max, Add | Mul) | (Min, Sub) => (), + _ => return, + } } } let mut applicability = Applicability::MachineApplicable; + let saturating_arith = checked_arith.as_saturating(); span_lint_and_sugg( cx, super::MANUAL_SATURATING_ARITHMETIC, expr.span, "manual saturating arithmetic", - format!("consider using `saturating_{arith}`"), + format!("consider using `{saturating_arith}`"), format!( - "{}.saturating_{arith}({})", + "{}.{saturating_arith}({})", snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability), snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability), ), @@ -62,6 +71,32 @@ pub fn check( ); } +enum CheckedArith { + Add, + Sub, + Mul, +} + +impl CheckedArith { + fn new(sym: Symbol) -> Option { + let res = match sym { + sym::checked_add => Self::Add, + sym::checked_sub => Self::Sub, + sym::checked_mul => Self::Mul, + _ => return None, + }; + Some(res) + } + + fn as_saturating(&self) -> &'static str { + match self { + Self::Add => "saturating_add", + Self::Sub => "saturating_sub", + Self::Mul => "saturating_mul", + } + } +} + #[derive(PartialEq, Eq)] enum MinMax { Min, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c9066be51c44..5702d08aa6d3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5507,14 +5507,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { (sym::unwrap_or, [u_arg]) => { match method_call(recv) { Some((arith @ (sym::checked_add | sym::checked_sub | sym::checked_mul), lhs, [rhs], _, _)) => { - manual_saturating_arithmetic::check( - cx, - expr, - lhs, - rhs, - u_arg, - &arith.as_str()[const { "checked_".len() }..], - ); + manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, arith); }, Some((sym::map, m_recv, [m_arg], span, _)) => { option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv); From 95834c9f6008a2f6fda31db7e990bd816cc297b3 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 8 Oct 2025 17:15:13 +0200 Subject: [PATCH 026/585] recognize `x.checked_sub(y).unwrap_or_default()` as well --- .../methods/manual_saturating_arithmetic.rs | 90 +++++++++++++------ clippy_lints/src/methods/mod.rs | 5 +- tests/ui/manual_saturating_arithmetic.fixed | 10 +++ tests/ui/manual_saturating_arithmetic.rs | 10 +++ tests/ui/manual_saturating_arithmetic.stderr | 8 +- 5 files changed, 93 insertions(+), 30 deletions(-) diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 21526c83c318..a3dd967bd77a 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -4,18 +4,19 @@ use clippy_utils::sym; use rustc_ast::ast; use rustc_errors::Applicability; -use rustc_hir as hir; use rustc_hir::def::Res; +use rustc_hir::{self as hir, Expr}; use rustc_lint::LateContext; +use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; use rustc_span::Symbol; -pub fn check( +pub fn check_unwrap_or( cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - arith_lhs: &hir::Expr<'_>, - arith_rhs: &hir::Expr<'_>, - unwrap_arg: &hir::Expr<'_>, + expr: &Expr<'_>, + arith_lhs: &Expr<'_>, + arith_rhs: &Expr<'_>, + unwrap_arg: &Expr<'_>, arith: Symbol, ) { let ty = cx.typeck_results().expr_ty(arith_lhs); @@ -31,26 +32,58 @@ pub fn check( return; }; - { - use self::MinMax::{Max, Min}; - use self::Sign::{Neg, Pos}; - use CheckedArith::{Add, Mul, Sub}; + check(cx, expr, arith_lhs, arith_rhs, ty, mm, checked_arith); +} - if ty.is_signed() { - let Some(sign) = lit_sign(arith_rhs) else { - return; - }; +pub(super) fn check_sub_unwrap_or_default( + cx: &LateContext<'_>, + expr: &Expr<'_>, + arith_lhs: &Expr<'_>, + arith_rhs: &Expr<'_>, +) { + let ty = cx.typeck_results().expr_ty(arith_lhs); + if !ty.is_integral() { + return; + } - match (&checked_arith, sign, mm) { - (Add, Pos, Max) | (Add, Neg, Min) | (Sub, Neg, Max) | (Sub, Pos, Min) => (), - // "mul" is omitted because lhs can be negative. - _ => return, - } - } else { - match (mm, &checked_arith) { - (Max, Add | Mul) | (Min, Sub) => (), - _ => return, - } + let mm = if ty.is_signed() { + return; // iN::default() is 0, which is neither MIN nor MAX + } else { + MinMax::Min // uN::default() is 0, which is also the MIN + }; + + let checked_arith = CheckedArith::Sub; + + check(cx, expr, arith_lhs, arith_rhs, ty, mm, checked_arith); +} + +fn check( + cx: &LateContext<'_>, + expr: &Expr<'_>, + arith_lhs: &Expr<'_>, + arith_rhs: &Expr<'_>, + ty: Ty<'_>, + mm: MinMax, + checked_arith: CheckedArith, +) { + use self::MinMax::{Max, Min}; + use self::Sign::{Neg, Pos}; + use CheckedArith::{Add, Mul, Sub}; + + if ty.is_signed() { + let Some(sign) = lit_sign(arith_rhs) else { + return; + }; + + match (checked_arith, sign, mm) { + (Add, Pos, Max) | (Add, Neg, Min) | (Sub, Neg, Max) | (Sub, Pos, Min) => (), + // "mul" is omitted because lhs can be negative. + _ => return, + } + } else { + match (mm, checked_arith) { + (Max, Add | Mul) | (Min, Sub) => (), + _ => return, } } @@ -71,6 +104,7 @@ pub fn check( ); } +#[derive(Clone, Copy)] enum CheckedArith { Add, Sub, @@ -88,7 +122,7 @@ fn new(sym: Symbol) -> Option { Some(res) } - fn as_saturating(&self) -> &'static str { + fn as_saturating(self) -> &'static str { match self { Self::Add => "saturating_add", Self::Sub => "saturating_sub", @@ -103,7 +137,7 @@ enum MinMax { Max, } -fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { +fn is_min_or_max(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { // `T::max_value()` `T::min_value()` inherent methods if let hir::ExprKind::Call(func, []) = &expr.kind && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, segment)) = &func.kind @@ -141,7 +175,7 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { (0, if bits == 128 { !0 } else { (1 << bits) - 1 }) }; - let check_lit = |expr: &hir::Expr<'_>, check_min: bool| { + let check_lit = |expr: &Expr<'_>, check_min: bool| { if let hir::ExprKind::Lit(lit) = &expr.kind && let ast::LitKind::Int(value, _) = lit.node { @@ -176,7 +210,7 @@ enum Sign { Neg, } -fn lit_sign(expr: &hir::Expr<'_>) -> Option { +fn lit_sign(expr: &Expr<'_>) -> Option { if let hir::ExprKind::Unary(hir::UnOp::Neg, inner) = &expr.kind { if let hir::ExprKind::Lit(..) = &inner.kind { return Some(Sign::Neg); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5702d08aa6d3..d8181dcf19f0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5507,7 +5507,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { (sym::unwrap_or, [u_arg]) => { match method_call(recv) { Some((arith @ (sym::checked_add | sym::checked_sub | sym::checked_mul), lhs, [rhs], _, _)) => { - manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, arith); + manual_saturating_arithmetic::check_unwrap_or(cx, expr, lhs, rhs, u_arg, arith); }, Some((sym::map, m_recv, [m_arg], span, _)) => { option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv); @@ -5528,6 +5528,9 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { }, (sym::unwrap_or_default, []) => { match method_call(recv) { + Some((sym::checked_sub, lhs, [rhs], _, _)) => { + manual_saturating_arithmetic::check_sub_unwrap_or_default(cx, expr, lhs, rhs); + }, Some((sym::map, m_recv, [arg], span, _)) => { manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv); }, diff --git a/tests/ui/manual_saturating_arithmetic.fixed b/tests/ui/manual_saturating_arithmetic.fixed index 304be05f6c4c..8dd142b2c79a 100644 --- a/tests/ui/manual_saturating_arithmetic.fixed +++ b/tests/ui/manual_saturating_arithmetic.fixed @@ -58,3 +58,13 @@ fn main() { let _ = 1i8.checked_sub(1).unwrap_or(127); // ok let _ = 1i8.checked_sub(-1).unwrap_or(-128); // ok } + +fn issue15655() { + let _ = 5u32.saturating_sub(1u32); //~ manual_saturating_arithmetic + let _ = 5u32.checked_add(1u32).unwrap_or_default(); // ok + let _ = 5u32.checked_mul(1u32).unwrap_or_default(); // ok + + let _ = 5i32.checked_sub(1i32).unwrap_or_default(); // ok + let _ = 5i32.checked_add(1i32).unwrap_or_default(); // ok + let _ = 5i32.checked_mul(1i32).unwrap_or_default(); // ok +} diff --git a/tests/ui/manual_saturating_arithmetic.rs b/tests/ui/manual_saturating_arithmetic.rs index c2b570e974ac..9cc8bc42410d 100644 --- a/tests/ui/manual_saturating_arithmetic.rs +++ b/tests/ui/manual_saturating_arithmetic.rs @@ -73,3 +73,13 @@ fn main() { let _ = 1i8.checked_sub(1).unwrap_or(127); // ok let _ = 1i8.checked_sub(-1).unwrap_or(-128); // ok } + +fn issue15655() { + let _ = 5u32.checked_sub(1u32).unwrap_or_default(); //~ manual_saturating_arithmetic + let _ = 5u32.checked_add(1u32).unwrap_or_default(); // ok + let _ = 5u32.checked_mul(1u32).unwrap_or_default(); // ok + + let _ = 5i32.checked_sub(1i32).unwrap_or_default(); // ok + let _ = 5i32.checked_add(1i32).unwrap_or_default(); // ok + let _ = 5i32.checked_mul(1i32).unwrap_or_default(); // ok +} diff --git a/tests/ui/manual_saturating_arithmetic.stderr b/tests/ui/manual_saturating_arithmetic.stderr index 2f006a3ae170..aec0f0a16419 100644 --- a/tests/ui/manual_saturating_arithmetic.stderr +++ b/tests/ui/manual_saturating_arithmetic.stderr @@ -165,5 +165,11 @@ LL | | .checked_sub(-1) LL | | .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); | |_______________________________________________________________________^ help: consider using `saturating_sub`: `1i128.saturating_sub(-1)` -error: aborting due to 24 previous errors +error: manual saturating arithmetic + --> tests/ui/manual_saturating_arithmetic.rs:78:13 + | +LL | let _ = 5u32.checked_sub(1u32).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `5u32.saturating_sub(1u32)` + +error: aborting due to 25 previous errors From feb1b52180dff2b95f6b47d44679027ee0af0f78 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 22 Oct 2025 11:35:20 +0200 Subject: [PATCH 027/585] Compare against `CARGO_CFG_TARGET_FAMILY` in a multi-valued fashion `cfg(target_family = "...")` can be set multiple times, and thus `CARGO_CFG_TARGET_FAMILY` can also contain comma-separated values, similar to `CARGO_CFG_TARGET_FEATURE`. This allows `cargo build --target wasm32-unknown-emscripten -p musl-math-sys` to work, and will become more important if we were to add e.g. `cfg(target_family = "darwin")` in the future as discussed in https://github.com/rust-lang/rust/issues/100343. --- library/compiler-builtins/crates/musl-math-sys/build.rs | 9 ++++++--- library/compiler-builtins/libm/configure.rs | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/crates/musl-math-sys/build.rs b/library/compiler-builtins/crates/musl-math-sys/build.rs index 59e42f2d2e67..3bab5f2eb112 100644 --- a/library/compiler-builtins/crates/musl-math-sys/build.rs +++ b/library/compiler-builtins/crates/musl-math-sys/build.rs @@ -46,7 +46,7 @@ fn main() { let cfg = Config::from_env(); if cfg.target_env == "msvc" - || cfg.target_family == "wasm" + || cfg.target_families.iter().any(|f| f == "wasm") || cfg.target_features.iter().any(|f| f == "thumb-mode") { println!( @@ -69,7 +69,7 @@ struct Config { musl_arch: String, target_arch: String, target_env: String, - target_family: String, + target_families: Vec, target_os: String, target_string: String, target_vendor: String, @@ -79,6 +79,9 @@ struct Config { impl Config { fn from_env() -> Self { let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let target_families = env::var("CARGO_CFG_TARGET_FAMILY") + .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) + .unwrap_or_default(); let target_features = env::var("CARGO_CFG_TARGET_FEATURE") .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) .unwrap_or_default(); @@ -104,7 +107,7 @@ fn from_env() -> Self { musl_arch, target_arch, target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), - target_family: env::var("CARGO_CFG_TARGET_FAMILY").unwrap(), + target_families, target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), target_string: env::var("TARGET").unwrap(), target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index 76186e636527..857a30229716 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -13,7 +13,7 @@ pub struct Config { pub target_triple: String, pub target_arch: String, pub target_env: String, - pub target_family: Option, + pub target_families: Vec, pub target_os: String, pub target_string: String, pub target_vendor: String, @@ -25,6 +25,9 @@ pub struct Config { impl Config { pub fn from_env() -> Self { let target_triple = env::var("TARGET").unwrap(); + let target_families = env::var("CARGO_CFG_TARGET_FAMILY") + .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) + .unwrap_or_default(); let target_features = env::var("CARGO_CFG_TARGET_FEATURE") .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) .unwrap_or_default(); @@ -41,7 +44,7 @@ pub fn from_env() -> Self { cargo_features, target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), - target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(), + target_families, target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), target_string: env::var("TARGET").unwrap(), target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), From 033711ce8d011d7eed296917eb274232c3b45c34 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 23 Oct 2025 17:04:03 -0400 Subject: [PATCH 028/585] Stabilize `const_mul_add` Newly stable API: impl {f32, f64} { pub const fn mul_add(self, a: Self, b: Self) -> Self; } This includes making the intrinsics `fmaf{16,32,64,128}` const stable for indirect use, matching similar intrinsics. Closes: https://github.com/rust-lang/rust/issues/146724 --- library/core/src/intrinsics/mod.rs | 4 ++++ library/core/src/num/f128.rs | 1 - library/core/src/num/f16.rs | 1 - library/core/src/num/f32.rs | 1 - library/core/src/num/f64.rs | 1 - library/coretests/tests/lib.rs | 1 - library/std/src/lib.rs | 1 - library/std/src/num/f32.rs | 2 +- library/std/src/num/f64.rs | 2 +- 9 files changed, 6 insertions(+), 8 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index c397e762d558..eef147b9b506 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1310,6 +1310,7 @@ pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { /// /// The stabilized version of this intrinsic is /// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn fmaf16(a: f16, b: f16, c: f16) -> f16; @@ -1317,6 +1318,7 @@ pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { /// /// The stabilized version of this intrinsic is /// [`f32::mul_add`](../../std/primitive.f32.html#method.mul_add) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn fmaf32(a: f32, b: f32, c: f32) -> f32; @@ -1324,6 +1326,7 @@ pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { /// /// The stabilized version of this intrinsic is /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn fmaf64(a: f64, b: f64, c: f64) -> f64; @@ -1331,6 +1334,7 @@ pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { /// /// The stabilized version of this intrinsic is /// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn fmaf128(a: f128, b: f128, c: f128) -> f128; diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index e7101537b298..09b89b2f7e8c 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1660,7 +1660,6 @@ pub const fn fract(self) -> f128 { #[doc(alias = "fmaf128", alias = "fusedMultiplyAdd")] #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] - #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] pub const fn mul_add(self, a: f128, b: f128) -> f128 { intrinsics::fmaf128(self, a, b) } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index aa8342a22ad5..38165ce46692 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1635,7 +1635,6 @@ pub const fn fract(self) -> f16 { #[unstable(feature = "f16", issue = "116909")] #[doc(alias = "fmaf16", alias = "fusedMultiplyAdd")] #[must_use = "method returns a new number and does not mutate the original value"] - #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] pub const fn mul_add(self, a: f16, b: f16) -> f16 { intrinsics::fmaf16(self, a, b) } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 3070e1dedbe4..f4255ae75d3b 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1799,7 +1799,6 @@ pub const fn fract(x: f32) -> f32 { #[doc(alias = "fmaf", alias = "fusedMultiplyAdd")] #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] pub const fn mul_add(x: f32, y: f32, z: f32) -> f32 { intrinsics::fmaf32(x, y, z) } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index dc8ccc551b2d..5a09ecd326ba 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1797,7 +1797,6 @@ pub const fn fract(x: f64) -> f64 { #[doc(alias = "fma", alias = "fusedMultiplyAdd")] #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] - #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] pub const fn mul_add(x: f64, a: f64, b: f64) -> f64 { intrinsics::fmaf64(x, a, b) } diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 5c2522acb136..dee21a1fec91 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -22,7 +22,6 @@ #![feature(const_destruct)] #![feature(const_drop_in_place)] #![feature(const_eval_select)] -#![feature(const_mul_add)] #![feature(const_ops)] #![feature(const_option_ops)] #![feature(const_ref_cell)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 60c8f53a0cc4..eec5fc91cdfe 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -328,7 +328,6 @@ #![feature(char_internals)] #![feature(clone_to_uninit)] #![feature(const_convert)] -#![feature(const_mul_add)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(drop_guard)] diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index c9e192201aff..ef288f967f71 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -217,7 +217,7 @@ pub const fn fract(self) -> f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] - #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + #[rustc_const_stable(feature = "const_mul_add", since = "CURRENT_RUSTC_VERSION")] pub const fn mul_add(self, a: f32, b: f32) -> f32 { core::f32::math::mul_add(self, a, b) } diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 11874f9280f0..a62ec289591b 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -217,7 +217,7 @@ pub const fn fract(self) -> f64 { #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] - #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + #[rustc_const_stable(feature = "const_mul_add", since = "CURRENT_RUSTC_VERSION")] pub const fn mul_add(self, a: f64, b: f64) -> f64 { core::f64::math::mul_add(self, a, b) } From 482feee3118977db3731f1de171da7dfd043a864 Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Sat, 3 May 2025 22:58:27 -0600 Subject: [PATCH 029/585] refactor ub_checks and contract_checks to share logic --- src/base.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/base.rs b/src/base.rs index 7d50548b4026..6a1217a6a49b 100644 --- a/src/base.rs +++ b/src/base.rs @@ -841,17 +841,8 @@ fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { fields.iter(), ) .bytes(), - NullOp::UbChecks => { - let val = fx.tcx.sess.ub_checks(); - let val = CValue::by_val( - fx.bcx.ins().iconst(types::I8, i64::from(val)), - fx.layout_of(fx.tcx.types.bool), - ); - lval.write_cvalue(fx, val); - return; - } - NullOp::ContractChecks => { - let val = fx.tcx.sess.contract_checks(); + NullOp::RuntimeChecks(kind) => { + let val = kind.value(fx.tcx.sess); let val = CValue::by_val( fx.bcx.ins().iconst(types::I8, i64::from(val)), fx.layout_of(fx.tcx.types.bool), From ce850bf8733cf65f9c9c3fb9208edc113fa97e3d Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 29 Oct 2025 12:50:47 +0000 Subject: [PATCH 030/585] array_chunks: slightly improve docs --- library/core/src/array/mod.rs | 7 ++++--- library/core/src/iter/adapters/array_chunks.rs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 0dc10758a856..312c8da10747 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -907,7 +907,7 @@ fn try_from_fn_erased( /// All write accesses to this structure are unsafe and must maintain a correct /// count of `initialized` elements. /// -/// To minimize indirection fields are still pub but callers should at least use +/// To minimize indirection, fields are still pub but callers should at least use /// `push_unchecked` to signal that something unsafe is going on. struct Guard<'a, T> { /// The array to be initialized. @@ -925,7 +925,7 @@ impl Guard<'_, T> { #[inline] pub(crate) unsafe fn push_unchecked(&mut self, item: T) { // SAFETY: If `initialized` was correct before and the caller does not - // invoke this method more than N times then writes will be in-bounds + // invoke this method more than N times, then writes will be in-bounds // and slots will not be initialized more than once. unsafe { self.array_mut.get_unchecked_mut(self.initialized).write(item); @@ -954,7 +954,7 @@ fn drop(&mut self) { /// `next` at most `N` times, the iterator can still be used afterwards to /// retrieve the remaining items. /// -/// If `iter.next()` panicks, all items already yielded by the iterator are +/// If `iter.next()` panics, all items already yielded by the iterator are /// dropped. /// /// Used for [`Iterator::next_chunk`]. @@ -986,6 +986,7 @@ fn iter_next_chunk_erased( buffer: &mut [MaybeUninit], iter: &mut impl Iterator, ) -> Result<(), usize> { + // if `Iterator::next` panics, this guard will drop already initialized items let mut guard = Guard { array_mut: buffer, initialized: 0 }; while guard.initialized < guard.array_mut.len() { let Some(item) = iter.next() else { diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs index 8f1744fc5fbb..ff83b2010490 100644 --- a/library/core/src/iter/adapters/array_chunks.rs +++ b/library/core/src/iter/adapters/array_chunks.rs @@ -89,7 +89,7 @@ fn try_fold(&mut self, init: B, mut f: F) -> R match self.iter.next_chunk() { Ok(chunk) => acc = f(acc, chunk)?, Err(remainder) => { - // Make sure to not override `self.remainder` with an empty array + // Make sure to not overwrite `self.remainder` with an empty array // when `next` is called after `ArrayChunks` exhaustion. self.remainder.get_or_insert(remainder); From 96ac0996a0d41e80536343bc861b2cda6d54d8d5 Mon Sep 17 00:00:00 2001 From: yanglsh Date: Tue, 2 Sep 2025 00:40:54 +0800 Subject: [PATCH 031/585] fix: `nonstandard_macro_braces` FN on macros with empty args --- clippy_lints/src/nonstandard_macro_braces.rs | 38 +++++++++------- .../conf_nonstandard_macro_braces.fixed | 14 ++++++ .../conf_nonstandard_macro_braces.rs | 14 ++++++ .../conf_nonstandard_macro_braces.stderr | 44 ++++++++++++++----- 4 files changed, 84 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 3a8a4dd0c713..8970970f4b47 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -115,35 +115,41 @@ fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) { } fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBraces) -> Option { - let unnested_or_local = || { - !span.ctxt().outer_expn_data().call_site.from_expansion() + let unnested_or_local = |span: Span| { + !span.from_expansion() || span .macro_backtrace() .last() .is_some_and(|e| e.macro_def_id.is_some_and(DefId::is_local)) }; - let callsite_span = span.ctxt().outer_expn_data().call_site; - if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind + + let mut ctxt = span.ctxt(); + while !ctxt.is_root() { + let expn_data = ctxt.outer_expn_data(); + if let ExpnKind::Macro(MacroKind::Bang, mac_name) = expn_data.kind && let name = mac_name.as_str() && let Some(&braces) = mac_braces.macro_braces.get(name) - && let Some(snip) = callsite_span.get_source_text(cx) + && let Some(snip) = expn_data.call_site.get_source_text(cx) // we must check only invocation sites // https://github.com/rust-lang/rust-clippy/issues/7422 && let Some(macro_args_str) = snip.strip_prefix(name).and_then(|snip| snip.strip_prefix('!')) && let Some(old_open_brace @ ('{' | '(' | '[')) = macro_args_str.trim_start().chars().next() && old_open_brace != braces.0 - && unnested_or_local() - && !mac_braces.done.contains(&callsite_span) - { - Some(MacroInfo { - callsite_span, - callsite_snippet: snip, - old_open_brace, - braces, - }) - } else { - None + && unnested_or_local(expn_data.call_site) + && !mac_braces.done.contains(&expn_data.call_site) + { + return Some(MacroInfo { + callsite_span: expn_data.call_site, + callsite_snippet: snip, + old_open_brace, + braces, + }); + } + + ctxt = expn_data.call_site.ctxt(); } + + None } fn emit_help(cx: &EarlyContext<'_>, snip: &str, (open, close): (char, char), span: Span, add_semi: bool) { diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed index 419e62f92f46..3683e826aa92 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed @@ -1,6 +1,7 @@ //@aux-build:proc_macro_derive.rs #![warn(clippy::nonstandard_macro_braces)] +#![allow(clippy::println_empty_string)] extern crate proc_macro_derive; extern crate quote; @@ -75,3 +76,16 @@ fn issue9913() { [0]; // separate statement, not indexing into the result of println. //~^^ nonstandard_macro_braces } + +fn issue15594() { + println!(); + println!(""); + println!(); + //~^ nonstandard_macro_braces + println!(""); + //~^ nonstandard_macro_braces + println!(); + //~^ nonstandard_macro_braces + println!(""); + //~^ nonstandard_macro_braces +} diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs index b0bbced4ea3c..c1779dceff17 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs @@ -1,6 +1,7 @@ //@aux-build:proc_macro_derive.rs #![warn(clippy::nonstandard_macro_braces)] +#![allow(clippy::println_empty_string)] extern crate proc_macro_derive; extern crate quote; @@ -75,3 +76,16 @@ fn issue9913() { [0]; // separate statement, not indexing into the result of println. //~^^ nonstandard_macro_braces } + +fn issue15594() { + println!(); + println!(""); + println![]; + //~^ nonstandard_macro_braces + println![""]; + //~^ nonstandard_macro_braces + println! {}; + //~^ nonstandard_macro_braces + println! {""}; + //~^ nonstandard_macro_braces +} diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr index 87325f05c9bc..2488f7fa01e5 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr @@ -1,5 +1,5 @@ error: use of irregular braces for `vec!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:44:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:45:13 | LL | let _ = vec! {1, 2, 3}; | ^^^^^^^^^^^^^^ help: consider writing: `vec![1, 2, 3]` @@ -8,31 +8,31 @@ LL | let _ = vec! {1, 2, 3}; = help: to override `-D warnings` add `#[allow(clippy::nonstandard_macro_braces)]` error: use of irregular braces for `format!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:46:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:47:13 | LL | let _ = format!["ugh {} stop being such a good compiler", "hello"]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `format!("ugh {} stop being such a good compiler", "hello")` error: use of irregular braces for `matches!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:48:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:49:13 | LL | let _ = matches!{{}, ()}; | ^^^^^^^^^^^^^^^^ help: consider writing: `matches!({}, ())` error: use of irregular braces for `quote!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:50:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:51:13 | LL | let _ = quote!(let x = 1;); | ^^^^^^^^^^^^^^^^^^ help: consider writing: `quote!{let x = 1;}` error: use of irregular braces for `quote::quote!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:52:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:53:13 | LL | let _ = quote::quote!(match match match); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `quote::quote!{match match match}` error: use of irregular braces for `vec!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:18:9 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:19:9 | LL | vec!{0, 0, 0} | ^^^^^^^^^^^^^ help: consider writing: `vec![0, 0, 0]` @@ -43,22 +43,46 @@ LL | let _ = test!(); // trigger when macro def is inside our own crate = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error: use of irregular braces for `type_pos!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:62:12 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:63:12 | LL | let _: type_pos!(usize) = vec![]; | ^^^^^^^^^^^^^^^^ help: consider writing: `type_pos![usize]` error: use of irregular braces for `eprint!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:65:5 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:66:5 | LL | eprint!("test if user config overrides defaults"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `eprint!["test if user config overrides defaults"]` error: use of irregular braces for `println!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:74:5 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:75:5 | LL | println! {"hello world"} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `println!("hello world");` -error: aborting due to 9 previous errors +error: use of irregular braces for `println!` macro + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:83:5 + | +LL | println![]; + | ^^^^^^^^^^ help: consider writing: `println!()` + +error: use of irregular braces for `println!` macro + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:85:5 + | +LL | println![""]; + | ^^^^^^^^^^^^ help: consider writing: `println!("")` + +error: use of irregular braces for `println!` macro + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:87:5 + | +LL | println! {}; + | ^^^^^^^^^^^ help: consider writing: `println!()` + +error: use of irregular braces for `println!` macro + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:89:5 + | +LL | println! {""}; + | ^^^^^^^^^^^^^ help: consider writing: `println!("")` + +error: aborting due to 13 previous errors From 786cca82d24e6a29e66e1d945492db911cae0020 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 10 Sep 2025 13:33:45 +0000 Subject: [PATCH 032/585] slice iter: replace manual saturating_sub --- library/core/src/slice/iter.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 7053ae86e732..10dd6ada3026 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2368,10 +2368,7 @@ fn nth(&mut self, n: usize) -> Option { } else { // Can't underflow because of the check above let end = self.v.len() - end; - let start = match end.checked_sub(self.chunk_size) { - Some(sum) => sum, - None => 0, - }; + let start = end.saturating_sub(self.chunk_size); let nth = &self.v[start..end]; self.v = &self.v[0..start]; Some(nth) @@ -2391,10 +2388,7 @@ fn last(self) -> Option { unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; - let start = match end.checked_sub(self.chunk_size) { - None => 0, - Some(start) => start, - }; + let start = end.saturating_sub(self.chunk_size); // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`. unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } } @@ -2571,10 +2565,7 @@ fn last(self) -> Option { unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; - let start = match end.checked_sub(self.chunk_size) { - None => 0, - Some(start) => start, - }; + let start = end.saturating_sub(self.chunk_size); // SAFETY: see comments for `RChunks::__iterator_get_unchecked` and // `ChunksMut::__iterator_get_unchecked`, `self.v`. unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } From c62abb65c773654c9e8f65f5f115a3fce441781c Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Thu, 11 Sep 2025 11:05:03 +0000 Subject: [PATCH 033/585] slice iter: cleanup and make similar Chunks[Mut]::nth --- library/core/src/slice/iter.rs | 44 +++++++++++++++------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 10dd6ada3026..8ca78941a8a5 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1537,13 +1537,13 @@ fn count(self) -> usize { #[inline] fn nth(&mut self, n: usize) -> Option { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - // min(len) makes a wrong start harmless, but enables optimizing this to brachless code - let chunk_start = &self.v[start.min(self.v.len())..]; - let (nth, remainder) = chunk_start.split_at(self.chunk_size.min(chunk_start.len())); - if !overflow && start < self.v.len() { - self.v = remainder; - Some(nth) + if let Some(start) = n.checked_mul(self.chunk_size) + && start < self.v.len() + { + let rest = &self.v[start..]; + let (chunk, rest) = rest.split_at(self.chunk_size.min(rest.len())); + self.v = rest; + Some(chunk) } else { self.v = &self.v[..0]; // cheaper than &[] None @@ -1613,10 +1613,7 @@ fn nth_back(&mut self, n: usize) -> Option { None } else { let start = (len - 1 - n) * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - Some(res) => cmp::min(self.v.len(), res), - None => self.v.len(), - }; + let end = (start + self.chunk_size).min(self.v.len()); let nth_back = &self.v[start..end]; self.v = &self.v[..start]; Some(nth_back) @@ -1719,22 +1716,19 @@ fn count(self) -> usize { #[inline] fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { + if let Some(start) = n.checked_mul(self.chunk_size) + && start < self.v.len() + { + // SAFETY: `start < self.v.len()` ensures this is in bounds + let (_, rest) = unsafe { self.v.split_at_mut(start) }; + // SAFETY: `.min(rest.len()` ensures this is in bounds + let (chunk, rest) = unsafe { rest.split_at_mut(self.chunk_size.min(rest.len())) }; + self.v = rest; + // SAFETY: Nothing else points to or will point to the contents of this slice. + Some(unsafe { &mut *chunk }) + } else { self.v = &mut []; None - } else { - let end = match start.checked_add(self.chunk_size) { - Some(sum) => cmp::min(self.v.len(), sum), - None => self.v.len(), - }; - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (head, tail) = unsafe { self.v.split_at_mut(end) }; - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (_, nth) = unsafe { head.split_at_mut(start) }; - self.v = tail; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *nth }) } } From dc3ab70b58ecc619dbebef3433f4af6d07e219fa Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Tue, 4 Nov 2025 11:38:45 -0500 Subject: [PATCH 034/585] add Option::into_flat_iter --- library/core/src/option.rs | 60 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index e3c4758bc6af..8fe3c0c4d351 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2007,6 +2007,30 @@ pub fn reduce(self, other: Option, f: F) -> Option } } +impl Option { + /// Transforms an optional iterator into an iterator. + /// + /// If `self` is `None`, the resulting iterator is empty. + /// Otherwise, an iterator is made from the `Some` value and returned. + /// # Examples + /// ``` + /// #![feature(option_into_flat_iter)] + /// + /// let o1 = Some([1, 2]); + /// let o2 = None::<&[usize]>; + /// + /// assert_eq!(o1.into_flat_iter().collect::>(), [1, 2]); + /// assert_eq!(o2.into_flat_iter().collect::>(), Vec::<&usize>::new()); + /// ``` + #[unstable(feature = "option_into_flat_iter", issue = "148441")] + pub fn into_flat_iter(self) -> OptionFlatten + where + T: IntoIterator, + { + OptionFlatten { iter: self.map(IntoIterator::into_iter) } + } +} + impl Option<(T, U)> { /// Unzips an option containing a tuple of two options. /// @@ -2569,6 +2593,42 @@ impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for IntoIter {} +/// The iterator produced by [`Option::into_flat_iter`]. See its documentation for more. +#[derive(Clone, Debug)] +#[unstable(feature = "option_into_flat_iter", issue = "148441")] +pub struct OptionFlatten { + iter: Option, +} + +#[unstable(feature = "option_into_flat_iter", issue = "148441")] +impl Iterator for OptionFlatten { + type Item = A::Item; + + fn next(&mut self) -> Option { + self.iter.as_mut()?.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.as_ref().map(|i| i.size_hint()).unwrap_or((0, Some(0))) + } +} + +#[unstable(feature = "option_into_flat_iter", issue = "148441")] +impl DoubleEndedIterator for OptionFlatten { + fn next_back(&mut self) -> Option { + self.iter.as_mut()?.next_back() + } +} + +#[unstable(feature = "option_into_flat_iter", issue = "148441")] +impl ExactSizeIterator for OptionFlatten {} + +#[unstable(feature = "option_into_flat_iter", issue = "148441")] +impl FusedIterator for OptionFlatten {} + +#[unstable(feature = "option_into_flat_iter", issue = "148441")] +unsafe impl TrustedLen for OptionFlatten {} + ///////////////////////////////////////////////////////////////////////////// // FromIterator ///////////////////////////////////////////////////////////////////////////// From c90a9d836ba72cd3ae6bb0d6ba09883025835d8b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 8 Nov 2025 14:18:53 +0000 Subject: [PATCH 035/585] Merge commit 'a0b865dc8782500efe9623859017dd5e16f85407' into sync_cg_clif-2025-11-08 --- .cirrus.yml | 44 +-- .github/workflows/abi-cafe.yml | 2 +- .github/workflows/main.yml | 6 +- .vscode/settings.json | 6 +- Cargo.lock | 290 +++++++++++------- Cargo.toml | 31 +- Readme.md | 19 +- build_system/abi_cafe.rs | 2 + build_system/bench.rs | 2 +- build_system/build_backend.rs | 7 +- build_system/build_sysroot.rs | 73 ++--- build_system/main.rs | 7 + build_system/rustc_info.rs | 30 +- build_system/tests.rs | 42 ++- build_system/usage.txt | 4 + build_system/utils.rs | 4 +- config.txt | 1 - example/example.rs | 16 +- example/mini_core.rs | 22 +- example/mini_core_hello_world.rs | 91 +++--- example/neon.rs | 52 ++-- example/raw-dylib.rs | 2 +- example/std_example.rs | 144 +++++---- ...oot_tests-Disable-long-running-tests.patch | 47 +-- rust-toolchain | 2 +- scripts/cargo-clif.rs | 6 +- scripts/rustc-clif.rs | 6 +- scripts/rustdoc-clif.rs | 6 +- scripts/rustup.sh | 2 +- scripts/setup_rust_fork.sh | 29 +- scripts/test_rustc_tests.sh | 29 +- src/abi/mod.rs | 208 ++++++++++--- src/abi/pass_mode.rs | 7 +- src/base.rs | 99 ++++-- src/codegen_f16_f128.rs | 11 +- src/common.rs | 36 +-- src/compiler_builtins.rs | 51 ++- src/config.rs | 2 +- src/constant.rs | 76 +++-- src/debuginfo/emit.rs | 6 +- src/debuginfo/gcc_except_table.rs | 271 ++++++++++++++++ src/debuginfo/line_info.rs | 48 +-- src/debuginfo/mod.rs | 51 ++- src/debuginfo/types.rs | 4 +- src/debuginfo/unwind.rs | 191 +++++++++++- src/driver/aot.rs | 61 ++-- src/driver/jit.rs | 43 ++- src/driver/mod.rs | 16 +- src/global_asm.rs | 5 +- src/inline_asm.rs | 56 ++-- src/intrinsics/mod.rs | 76 ++++- src/intrinsics/simd.rs | 18 +- src/lib.rs | 96 ++---- src/main_shim.rs | 6 +- src/pretty_clif.rs | 9 +- src/unsize.rs | 2 +- src/value_and_place.rs | 21 +- src/vtable.rs | 2 +- 58 files changed, 1664 insertions(+), 832 deletions(-) create mode 100644 src/debuginfo/gcc_except_table.rs diff --git a/.cirrus.yml b/.cirrus.yml index ee5de8b42f46..3ed89beceb7f 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,21 +1,23 @@ -# FIXME re-enable once https://github.com/rust-lang/rust/issues/134863 is fixed. -# task: -# name: freebsd -# freebsd_instance: -# image: freebsd-13-2-release-amd64 -# setup_rust_script: -# - pkg install -y git-tiny binutils -# - curl https://sh.rustup.rs -sSf --output rustup.sh -# - sh rustup.sh --default-toolchain none -y --profile=minimal -# target_cache: -# folder: build/cg_clif -# prepare_script: -# - . $HOME/.cargo/env -# - ./y.sh prepare -# test_script: -# - . $HOME/.cargo/env -# # Disabling incr comp reduces cache size and incr comp doesn't save as much -# # on CI anyway. -# - export CARGO_BUILD_INCREMENTAL=false -# # Skip rand as it fails on FreeBSD due to rust-random/rand#1355 -# - ./y.sh test --skip-test test.rust-random/rand +task: + name: freebsd + freebsd_instance: + image_family: freebsd-14-2 + setup_rust_script: + - pkg install -y git-tiny binutils + - curl https://sh.rustup.rs -sSf --output rustup.sh + - sh rustup.sh --default-toolchain none -y --profile=minimal + target_cache: + folder: build/cg_clif + prepare_script: + - . $HOME/.cargo/env + - ./y.sh prepare + test_script: + - . $HOME/.cargo/env + # Disabling incr comp reduces cache size and incr comp doesn't save as much + # on CI anyway. + - export CARGO_BUILD_INCREMENTAL=false + # FIXME(rust-lang/rust#134863) necessary to avoid error when dlopening proc + # macros during compilation of cg_clif. + - export LD_STATIC_TLS_EXTRA=4096 + # Skip rand as it fails on FreeBSD due to rust-random/rand#1355 + - ./y.sh test --skip-test test.rust-random/rand diff --git a/.github/workflows/abi-cafe.yml b/.github/workflows/abi-cafe.yml index 6ad041a796c9..170c7126c296 100644 --- a/.github/workflows/abi-cafe.yml +++ b/.github/workflows/abi-cafe.yml @@ -28,7 +28,7 @@ jobs: - os: ubuntu-24.04-arm env: TARGET_TRIPLE: aarch64-unknown-linux-gnu - - os: macos-13 + - os: macos-15-intel env: TARGET_TRIPLE: x86_64-apple-darwin - os: macos-latest diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d92e0fdce99a..0930b924d177 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,7 +56,7 @@ jobs: - os: ubuntu-24.04-arm env: TARGET_TRIPLE: aarch64-unknown-linux-gnu - - os: macos-13 + - os: macos-15-intel env: TARGET_TRIPLE: x86_64-apple-darwin - os: macos-latest @@ -187,7 +187,7 @@ jobs: - os: ubuntu-24.04-arm env: TARGET_TRIPLE: aarch64-unknown-linux-gnu - - os: macos-13 + - os: macos-15-intel env: TARGET_TRIPLE: x86_64-apple-darwin - os: macos-latest @@ -231,7 +231,7 @@ jobs: release: runs-on: ubuntu-latest timeout-minutes: 10 - if: ${{ github.ref == 'refs/heads/master' }} + if: ${{ github.ref == 'refs/heads/main' }} needs: [rustfmt, test, bench, dist] permissions: diff --git a/.vscode/settings.json b/.vscode/settings.json index 68bd93aea890..2a3ec5e1c905 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,13 +20,13 @@ "crates": [ { "root_module": "./example/mini_core.rs", - "edition": "2015", + "edition": "2024", "deps": [], "cfg": [], }, { "root_module": "./example/mini_core_hello_world.rs", - "edition": "2015", + "edition": "2024", "deps": [ { "crate": 0, @@ -37,7 +37,7 @@ }, { "root_module": "./example/std_example.rs", - "edition": "2015", + "edition": "2024", "deps": [], "cfg": [], }, diff --git a/Cargo.lock b/Cargo.lock index b893a2be9a2c..09b6c6b87c30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arbitrary" @@ -28,57 +28,57 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" dependencies = [ "allocator-api2", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cranelift-assembler-x64" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f53499803b1607b6ee0ba0de4ba036e6da700c2e489fe8f9d0f683d0b84d31" +checksum = "f502c60b6af2025c312b37788c089943ef03156a2910da1aa046bb39eb8f61c7" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aadaa5bc8430d0e7bb999459369bedd0e5816ad4a82a0e20748341c4e333eda" +checksum = "2b7e21a74bcf08443a4ef800a4a257063e5c51ee4d7a3bd58da5262d10340830" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2005fda2fc52a2dbce58229b4fb4483b70cbc806ba8ecc11b3f050c1a2d26cac" +checksum = "f337d268865c292ad5df0669a9bbf6223ca41460292a20ad5b0a57b8e9f27f93" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56935e02452ca1249d39ad5c45a96304d0b4300a158a391fd113451e0cd4483d" +checksum = "c0e60319a8242c8d1c7b5a2444d140c416f903f75e0d84da3256fceb822bab85" [[package]] name = "cranelift-codegen" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62612786bf00e10999f50217d6f455d02b31591155881a45a903d1a95d1a4043" +checksum = "78dee669e447a1c68760bf7acee33835e99d564f0137b067f74d4718dfc9970d" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -97,49 +97,50 @@ dependencies = [ "serde", "smallvec", "target-lexicon", - "wasmtime-math", + "wasmtime-internal-math", ] [[package]] name = "cranelift-codegen-meta" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bae789df91ef236079733af9df11d852256c64af196f0bc6471ea0f5f301be" +checksum = "601f629d172b7230f41dd0e78ee797efaf7ec1a5e113c8f395f4027dff6a92ca" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", "cranelift-srcgen", + "heck", ] [[package]] name = "cranelift-codegen-shared" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be319616d36527782558a8312508757815f64deb19b094c7b8f4337229a9bc6" +checksum = "15755c2660902c7d59d96f6551a66ef629650dc3fd405f9dad841e8c58c1a4a2" [[package]] name = "cranelift-control" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8810ee1ab5e9bd5cff4c0c8d240e2009cb5c2b79888fde1d5256d605712314b7" +checksum = "727bfca18705101a294ab9077ad214a8b762ea2bc9844389d0db233d7c61ec3b" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "086452c97cfbe116bf17dbe622dc5fdf2ea97299c7d4ce42460f284387c9928a" +checksum = "15564c6f0c72750ca4374f40b044857cbc8087571e46d4c7ccdbdcc29b1dec8b" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c27947010ab759330f252610c17a8cd64d123358be4f33164233d04fcd77b80" +checksum = "16c681f2731f1cf68eed9f3b6811571823a5ac498f59c52b73736b68599defb3" dependencies = [ "cranelift-codegen", "log", @@ -149,15 +150,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec67bfb8bd55b1e9760eb9f5186dca8d81bd4d86110f8d5af01154a044c91802" +checksum = "40cedc02f08307da019a3e06d3f20f772f829ff813aec975accb012f8930b688" [[package]] name = "cranelift-jit" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d67cdfc447f2abdb46bb30a6582cce189539c3c051c1d5330692376e1400edff" +checksum = "c2864461448c72d15ae3311ea63df9c7e35f22f04683785f6715a0cf17e6577d" dependencies = [ "anyhow", "cranelift-codegen", @@ -169,15 +170,15 @@ dependencies = [ "log", "region", "target-lexicon", - "wasmtime-jit-icache-coherence", - "windows-sys 0.59.0", + "wasmtime-internal-jit-icache-coherence", + "windows-sys 0.60.2", ] [[package]] name = "cranelift-module" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4597eaa52bca1ed111986c7a7f70cdbe192f83d271d627201365078e37b7e84" +checksum = "2b31d249bbbccc4c1ae54701087d4d49d05951897691eef44f4a60e70252743b" dependencies = [ "anyhow", "cranelift-codegen", @@ -186,9 +187,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a9b63edea46e013fce459c46e500462cb03a0490fdd9c18fe42b1dd7b93aa1" +checksum = "db03ab51c60710eb83d0217725b77db4062aca83b35359f5e6aa99ed1c275977" dependencies = [ "cranelift-codegen", "libc", @@ -197,9 +198,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce706f0166d5b7f31693dff521e87cb9858e12adf22ffcde93c4a2826f8f04a9" +checksum = "7131e0eb45ee10b0bd6082d0c0114c2e9a670b034d46774b39d0fc5c0ed7cedf" dependencies = [ "anyhow", "cranelift-codegen", @@ -212,24 +213,24 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.121.0" +version = "0.125.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5870e266df8237b56cc98b04f5739c228565c92dd629ec6c66efa87271a158" +checksum = "3d7a06c330b7994a891ad5b622ebc9aefcd17beae832dd25f577cf60c13426bf" [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "fallible-iterator" @@ -239,15 +240,15 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "foldhash" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe" dependencies = [ "fallible-iterator", "indexmap", @@ -256,18 +257,24 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "foldhash", ] [[package]] -name = "indexmap" -version = "2.7.0" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indexmap" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown", @@ -275,18 +282,18 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.169" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets", + "windows-targets 0.53.3", ] [[package]] @@ -297,30 +304,30 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "mach2" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" dependencies = [ "libc", ] [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "crc32fast", "hashbrown", @@ -330,27 +337,27 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] name = "regalloc2" -version = "0.12.2" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5216b1837de2149f8bc8e6d5f88a9326b63b8c836ed58ce4a0a29ec736a59734" +checksum = "efd8138ce7c3d7c13be4f61893154b5d711bd798d2d7be3ecb8dcc7e7a06ca98" dependencies = [ "allocator-api2", "bumpalo", @@ -374,9 +381,9 @@ dependencies = [ [[package]] name = "rustc-hash" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc_codegen_cranelift" @@ -398,18 +405,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -418,9 +425,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "stable_deref_trait" @@ -430,9 +437,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "2.0.95" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -441,53 +448,59 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc12939a1c9b9d391e0b7135f72fd30508b73450753e28341fed159317582a77" +checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] -name = "wasmtime-jit-icache-coherence" -version = "34.0.0" +name = "wasmtime-internal-jit-icache-coherence" +version = "38.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eedc0324e37cf39b049f4dca0c30997eaab49f09006d5f4c1994e64e7b7dba8" +checksum = "8d0a76f1a6e887cc1b551b02dfd6e2ce5f6738e8cacd9ad7284f6ac1aac4698f" dependencies = [ "anyhow", "cfg-if", "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] -name = "wasmtime-math" -version = "34.0.0" +name = "wasmtime-internal-math" +version = "38.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd35fae4cf51d2b4a9bd2ef04b0eb309fa1849cab6a6ab5ac27cbd054ea284d" +checksum = "b900df4252ad86547e7f2b2c00201b006db4e864893bedfb3aca32b23d81868a" dependencies = [ "libm", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets", + "windows-targets 0.53.3", ] [[package]] @@ -496,14 +509,31 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -512,44 +542,92 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" diff --git a/Cargo.toml b/Cargo.toml index 9066e4dbbb52..f2001123e579 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,22 +1,22 @@ [package] name = "rustc_codegen_cranelift" version = "0.1.0" -edition = "2021" +edition = "2024" [lib] crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.121.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.121.0" } -cranelift-module = { version = "0.121.0" } -cranelift-native = { version = "0.121.0" } -cranelift-jit = { version = "0.121.0", optional = true } -cranelift-object = { version = "0.121.0" } +cranelift-codegen = { version = "0.125.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.125.0" } +cranelift-module = { version = "0.125.0" } +cranelift-native = { version = "0.125.0" } +cranelift-jit = { version = "0.125.0", optional = true } +cranelift-object = { version = "0.125.0" } target-lexicon = "0.13" -gimli = { version = "0.31", default-features = false, features = ["write"] } -object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +gimli = { version = "0.32", default-features = false, features = ["write"] } +object = { version = "0.37.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" libloading = { version = "0.8.0", optional = true } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } @@ -46,6 +46,7 @@ smallvec = "1.8.1" unstable-features = ["jit", "inline_asm_sym"] jit = ["cranelift-jit", "libloading"] inline_asm_sym = [] +unwinding = [] # Not yet included in unstable-features for performance reasons [package.metadata.rust-analyzer] rustc_private = true diff --git a/Readme.md b/Readme.md index 4d1e4d843ffe..c5436cf67c80 100644 --- a/Readme.md +++ b/Readme.md @@ -11,7 +11,7 @@ The Cranelift codegen backend is distributed in nightly builds on Linux, macOS a install it using Rustup, you can do that by running: ```bash -$ rustup component add rustc-codegen-cranelift-preview --toolchain nightly +rustup component add rustc-codegen-cranelift-preview --toolchain nightly ``` Once it is installed, you can enable it with one of the following approaches: @@ -47,16 +47,16 @@ If you want to use `cargo clif build` instead of having to specify the full path If you want to build the backend manually, you can download it from GitHub and build it yourself: ```bash -$ git clone https://github.com/rust-lang/rustc_codegen_cranelift -$ cd rustc_codegen_cranelift -$ ./y.sh build +git clone https://github.com/rust-lang/rustc_codegen_cranelift +cd rustc_codegen_cranelift +./y.sh build ``` To run the test suite replace the last command with: ```bash -$ ./y.sh prepare # only needs to be run the first time -$ ./test.sh +./y.sh prepare # only needs to be run the first time +./test.sh ``` For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.sh`. @@ -66,7 +66,7 @@ For more docs on how to build and test see [build_system/usage.txt](build_system |OS \ architecture|x86\_64|AArch64|Riscv64|s390x (System-Z)| |---|---|---|---|---| |Linux|✅|✅|✅[^no-rustup]|✅[^no-rustup]| -|FreeBSD|✅[^no-rustup]|❓|❓|❓| +|FreeBSD|✅[^no-rustup][^tls]|❓|❓|❓| |AIX|❌[^xcoff]|N/A|N/A|❌[^xcoff]| |Other unixes|❓|❓|❓|❓| |macOS|✅|✅|N/A|N/A| @@ -80,6 +80,7 @@ Not all targets are available as rustup component for nightly. See notes in the [^xcoff]: XCOFF object file format is not supported. [^no-rustup]: Not available as [rustup component for nightly](https://rust-lang.github.io/rustup-components-history/). You can build it yourself. +[^tls]: FreeBSD requires setting `LD_STATIC_TLS_EXTRA=4096` to build cg_clif. In addition you need at least FreeBSD 14. ## Usage @@ -90,7 +91,7 @@ Assuming `$cg_clif_dir` is the directory you cloned this repo into and you follo In the directory with your project (where you can do the usual `cargo build`), run: ```bash -$ $cg_clif_dir/dist/cargo-clif build +$cg_clif_dir/dist/cargo-clif build ``` This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend. @@ -104,7 +105,7 @@ See [rustc_testing.md](docs/rustc_testing.md). ## Not yet supported * SIMD ([tracked here](https://github.com/rust-lang/rustc_codegen_cranelift/issues/171), `std::simd` fully works, `std::arch` is partially supported) -* Unwinding on panics ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1677), `-Cpanic=abort` is enabled by default) +* Unwinding on panics ([experimental and not supported on Windows and macOS](https://github.com/rust-lang/rustc_codegen_cranelift/issues/1567), `-Cpanic=abort` is enabled by default) ## License diff --git a/build_system/abi_cafe.rs b/build_system/abi_cafe.rs index 43025137bc6b..5a393a217c27 100644 --- a/build_system/abi_cafe.rs +++ b/build_system/abi_cafe.rs @@ -19,6 +19,7 @@ pub(crate) fn run( cg_clif_dylib: &CodegenBackend, rustup_toolchain_name: Option<&str>, bootstrap_host_compiler: &Compiler, + panic_unwind_support: bool, ) { std::fs::create_dir_all(&dirs.download_dir).unwrap(); ABI_CAFE_REPO.fetch(dirs); @@ -32,6 +33,7 @@ pub(crate) fn run( bootstrap_host_compiler, rustup_toolchain_name, bootstrap_host_compiler.triple.clone(), + panic_unwind_support, ); eprintln!("Running abi-cafe"); diff --git a/build_system/bench.rs b/build_system/bench.rs index 8359b7b52790..192cb499536f 100644 --- a/build_system/bench.rs +++ b/build_system/bench.rs @@ -144,7 +144,7 @@ fn hyperfine_command( } for &(name, cmd) in cmds { - if name != "" { + if !name.is_empty() { bench.arg("-n").arg(name); } bench.arg(cmd); diff --git a/build_system/build_backend.rs b/build_system/build_backend.rs index bf7cf1c0a346..b9fa0ff2d94c 100644 --- a/build_system/build_backend.rs +++ b/build_system/build_backend.rs @@ -12,10 +12,11 @@ pub(crate) fn build_backend( dirs: &Dirs, bootstrap_host_compiler: &Compiler, use_unstable_features: bool, + panic_unwind_support: bool, ) -> PathBuf { let _group = LogGroup::guard("Build backend"); - let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs); + let mut cmd = CG_CLIF.build(bootstrap_host_compiler, dirs); let mut rustflags = rustflags_from_env("RUSTFLAGS"); rustflags.push("-Zallow-features=rustc_private,f16,f128".to_owned()); @@ -31,6 +32,10 @@ pub(crate) fn build_backend( cmd.arg("--features").arg("unstable-features"); } + if panic_unwind_support { + cmd.arg("--features").arg("unwinding"); + } + cmd.arg("--release"); eprintln!("[BUILD] rustc_codegen_cranelift"); diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 00955998e703..72140c651a9a 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -17,6 +17,7 @@ pub(crate) fn build_sysroot( bootstrap_host_compiler: &Compiler, rustup_toolchain_name: Option<&str>, target_triple: String, + panic_unwind_support: bool, ) -> Compiler { let _guard = LogGroup::guard("Build sysroot"); @@ -48,10 +49,13 @@ pub(crate) fn build_sysroot( let mut build_cargo_wrapper_cmd = Command::new(&bootstrap_host_compiler.rustc); let wrapper_path = dist_dir.join(&wrapper_name); build_cargo_wrapper_cmd - .arg(dirs.source_dir.join("scripts").join(&format!("{wrapper}.rs"))) + .arg(dirs.source_dir.join("scripts").join(format!("{wrapper}.rs"))) .arg("-o") .arg(&wrapper_path) .arg("-Cstrip=debuginfo"); + if panic_unwind_support { + build_cargo_wrapper_cmd.arg("--cfg").arg("support_panic_unwind"); + } if let Some(rustup_toolchain_name) = &rustup_toolchain_name { build_cargo_wrapper_cmd .env("TOOLCHAIN_NAME", rustup_toolchain_name) @@ -77,6 +81,7 @@ pub(crate) fn build_sysroot( bootstrap_host_compiler.clone(), &cg_clif_dylib_path, sysroot_kind, + panic_unwind_support, ); host.install_into_sysroot(dist_dir); @@ -91,6 +96,7 @@ pub(crate) fn build_sysroot( }, &cg_clif_dylib_path, sysroot_kind, + panic_unwind_support, ) .install_into_sysroot(dist_dir); } @@ -134,19 +140,20 @@ fn install_into_sysroot(&self, sysroot: &Path) { static STDLIB_SRC: RelPath = RelPath::build("stdlib"); static STANDARD_LIBRARY: CargoProject = CargoProject::new(&RelPath::build("stdlib/library/sysroot"), "stdlib_target"); -static RTSTARTUP_SYSROOT: RelPath = RelPath::build("rtstartup"); fn build_sysroot_for_triple( dirs: &Dirs, compiler: Compiler, cg_clif_dylib_path: &CodegenBackend, sysroot_kind: SysrootKind, + panic_unwind_support: bool, ) -> SysrootTarget { match sysroot_kind { - SysrootKind::None => build_rtstartup(dirs, &compiler) - .unwrap_or(SysrootTarget { triple: compiler.triple, libs: vec![] }), + SysrootKind::None => SysrootTarget { triple: compiler.triple, libs: vec![] }, SysrootKind::Llvm => build_llvm_sysroot_for_triple(compiler), - SysrootKind::Clif => build_clif_sysroot_for_triple(dirs, compiler, cg_clif_dylib_path), + SysrootKind::Clif => { + build_clif_sysroot_for_triple(dirs, compiler, cg_clif_dylib_path, panic_unwind_support) + } } } @@ -188,25 +195,28 @@ fn build_clif_sysroot_for_triple( dirs: &Dirs, mut compiler: Compiler, cg_clif_dylib_path: &CodegenBackend, + panic_unwind_support: bool, ) -> SysrootTarget { let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] }; - if let Some(rtstartup_target_libs) = build_rtstartup(dirs, &compiler) { - rtstartup_target_libs.install_into_sysroot(&RTSTARTUP_SYSROOT.to_path(dirs)); - - target_libs.libs.extend(rtstartup_target_libs.libs); - } - let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(&compiler.triple).join("release"); if !config::get_bool("keep_sysroot") { + let sysroot_src_orig = get_default_sysroot(&compiler.rustc).join("lib/rustlib/src/rust"); + assert!(sysroot_src_orig.exists()); + + apply_patches(dirs, "stdlib", &sysroot_src_orig, &STDLIB_SRC.to_path(dirs)); + // Cleanup the deps dir, but keep build scripts and the incremental cache for faster // recompilation as they are not affected by changes in cg_clif. ensure_empty_dir(&build_dir.join("deps")); } // Build sysroot - let mut rustflags = vec!["-Zforce-unstable-if-unmarked".to_owned(), "-Cpanic=abort".to_owned()]; + let mut rustflags = vec!["-Zforce-unstable-if-unmarked".to_owned()]; + if !panic_unwind_support { + rustflags.push("-Cpanic=abort".to_owned()); + } match cg_clif_dylib_path { CodegenBackend::Local(path) => { rustflags.push(format!("-Zcodegen-backend={}", path.to_str().unwrap())); @@ -215,9 +225,7 @@ fn build_clif_sysroot_for_triple( rustflags.push(format!("-Zcodegen-backend={name}")); } }; - // Necessary for MinGW to find rsbegin.o and rsend.o - rustflags.push("--sysroot".to_owned()); - rustflags.push(RTSTARTUP_SYSROOT.to_path(dirs).to_str().unwrap().to_owned()); + rustflags.push("--sysroot=/dev/null".to_owned()); // Incremental compilation by default disables mir inlining. This leads to both a decent // compile perf and a significant runtime perf regression. As such forcefully enable mir @@ -258,38 +266,3 @@ fn build_clif_sysroot_for_triple( target_libs } - -fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option { - if !config::get_bool("keep_sysroot") { - let sysroot_src_orig = get_default_sysroot(&compiler.rustc).join("lib/rustlib/src/rust"); - assert!(sysroot_src_orig.exists()); - - apply_patches(dirs, "stdlib", &sysroot_src_orig, &STDLIB_SRC.to_path(dirs)); - } - - if !compiler.triple.ends_with("windows-gnu") { - return None; - } - - let rtstartup_sysroot = RTSTARTUP_SYSROOT.to_path(dirs); - ensure_empty_dir(&rtstartup_sysroot); - - let rtstartup_src = STDLIB_SRC.to_path(dirs).join("library").join("rtstartup"); - let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] }; - - for file in ["rsbegin", "rsend"] { - let obj = rtstartup_sysroot.join(format!("{file}.o")); - let mut build_rtstartup_cmd = Command::new(&compiler.rustc); - build_rtstartup_cmd - .arg("--target") - .arg(&compiler.triple) - .arg("--emit=obj") - .arg("-o") - .arg(&obj) - .arg(rtstartup_src.join(format!("{file}.rs"))); - spawn_and_wait(build_rtstartup_cmd); - target_libs.libs.push(obj.clone()); - } - - Some(target_libs) -} diff --git a/build_system/main.rs b/build_system/main.rs index 3ff9751a3ef2..fc0093128300 100644 --- a/build_system/main.rs +++ b/build_system/main.rs @@ -83,6 +83,7 @@ fn main() { let mut download_dir = None; let mut sysroot_kind = SysrootKind::Clif; let mut use_unstable_features = true; + let mut panic_unwind_support = false; let mut frozen = false; let mut skip_tests = vec![]; let mut use_backend = None; @@ -108,6 +109,7 @@ fn main() { } } "--no-unstable-features" => use_unstable_features = false, + "--panic-unwind-support" => panic_unwind_support = true, "--frozen" => frozen = true, "--skip-test" => { // FIXME check that all passed in tests actually exist @@ -201,6 +203,7 @@ fn main() { &dirs, &bootstrap_host_compiler, use_unstable_features, + panic_unwind_support, )) }; match command { @@ -212,6 +215,7 @@ fn main() { &dirs, sysroot_kind, use_unstable_features, + panic_unwind_support, &skip_tests.iter().map(|test| &**test).collect::>(), &cg_clif_dylib, &bootstrap_host_compiler, @@ -230,6 +234,7 @@ fn main() { &cg_clif_dylib, rustup_toolchain_name.as_deref(), &bootstrap_host_compiler, + panic_unwind_support, ); } Command::Build => { @@ -240,6 +245,7 @@ fn main() { &bootstrap_host_compiler, rustup_toolchain_name.as_deref(), target_triple, + panic_unwind_support, ); } Command::Bench => { @@ -250,6 +256,7 @@ fn main() { &bootstrap_host_compiler, rustup_toolchain_name.as_deref(), target_triple, + panic_unwind_support, ); bench::benchmark(&dirs, &compiler); } diff --git a/build_system/rustc_info.rs b/build_system/rustc_info.rs index 5b71504e90a4..2fa827498de9 100644 --- a/build_system/rustc_info.rs +++ b/build_system/rustc_info.rs @@ -2,25 +2,19 @@ use std::process::{Command, Stdio}; pub(crate) fn get_host_triple(rustc: &Path) -> String { - let version_info = - Command::new(rustc).stderr(Stdio::inherit()).args(&["-vV"]).output().unwrap().stdout; - String::from_utf8(version_info) + let version_info = Command::new(rustc) + .stderr(Stdio::inherit()) + .args(["--print", "host-tuple"]) + .output() .unwrap() - .lines() - .to_owned() - .find(|line| line.starts_with("host")) - .unwrap() - .split(":") - .nth(1) - .unwrap() - .trim() - .to_owned() + .stdout; + String::from_utf8(version_info).unwrap().trim().to_owned() } pub(crate) fn get_toolchain_name() -> String { let active_toolchain = Command::new("rustup") .stderr(Stdio::inherit()) - .args(&["show", "active-toolchain"]) + .args(["show", "active-toolchain"]) .output() .unwrap() .stdout; @@ -33,7 +27,7 @@ pub(crate) fn get_cargo_path() -> PathBuf { } let cargo_path = Command::new("rustup") .stderr(Stdio::inherit()) - .args(&["which", "cargo"]) + .args(["which", "cargo"]) .output() .unwrap() .stdout; @@ -46,7 +40,7 @@ pub(crate) fn get_rustc_path() -> PathBuf { } let rustc_path = Command::new("rustup") .stderr(Stdio::inherit()) - .args(&["which", "rustc"]) + .args(["which", "rustc"]) .output() .unwrap() .stdout; @@ -59,7 +53,7 @@ pub(crate) fn get_rustdoc_path() -> PathBuf { } let rustc_path = Command::new("rustup") .stderr(Stdio::inherit()) - .args(&["which", "rustdoc"]) + .args(["which", "rustdoc"]) .output() .unwrap() .stdout; @@ -69,7 +63,7 @@ pub(crate) fn get_rustdoc_path() -> PathBuf { pub(crate) fn get_default_sysroot(rustc: &Path) -> PathBuf { let default_sysroot = Command::new(rustc) .stderr(Stdio::inherit()) - .args(&["--print", "sysroot"]) + .args(["--print", "sysroot"]) .output() .unwrap() .stdout; @@ -80,7 +74,7 @@ pub(crate) fn get_default_sysroot(rustc: &Path) -> PathBuf { pub(crate) fn get_file_name(rustc: &Path, crate_name: &str, crate_type: &str) -> String { let file_name = Command::new(rustc) .stderr(Stdio::inherit()) - .args(&[ + .args([ "--crate-name", crate_name, "--crate-type", diff --git a/build_system/tests.rs b/build_system/tests.rs index eec89c026b26..dd8cf929bc2f 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -89,15 +89,7 @@ const fn jit_bin(config: &'static str, source: &'static str, args: &'static str) TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]), TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"), TestCase::build_bin_and_run("aot.neon", "example/neon.rs", &[]), - TestCase::custom("aot.gen_block_iterate", &|runner| { - runner.run_rustc([ - "example/gen_block_iterate.rs", - "--edition", - "2024", - "-Zunstable-options", - ]); - runner.run_out_command("gen_block_iterate", &[]); - }), + TestCase::build_bin_and_run("aot.gen_block_iterate", "example/gen_block_iterate.rs", &[]), TestCase::build_bin_and_run("aot.raw-dylib", "example/raw-dylib.rs", &[]), TestCase::custom("test.sysroot", &|runner| { apply_patches( @@ -217,13 +209,15 @@ const fn jit_bin(config: &'static str, source: &'static str, args: &'static str) PORTABLE_SIMD.clean(&runner.dirs); - let mut build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs); - build_cmd.arg("--all-targets"); + let build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs); + // FIXME uncomment once examples work: https://github.com/rust-lang/portable-simd/issues/470 + //build_cmd.arg("--all-targets"); spawn_and_wait(build_cmd); if runner.is_native { let mut test_cmd = PORTABLE_SIMD.test(&runner.target_compiler, &runner.dirs); - test_cmd.arg("-q"); + // FIXME remove --tests once examples work: https://github.com/rust-lang/portable-simd/issues/470 + test_cmd.arg("-q").arg("--tests"); spawn_and_wait(test_cmd); } }), @@ -233,6 +227,7 @@ pub(crate) fn run_tests( dirs: &Dirs, sysroot_kind: SysrootKind, use_unstable_features: bool, + panic_unwind_support: bool, skip_tests: &[&str], cg_clif_dylib: &CodegenBackend, bootstrap_host_compiler: &Compiler, @@ -251,12 +246,14 @@ pub(crate) fn run_tests( bootstrap_host_compiler, rustup_toolchain_name, target_triple.clone(), + panic_unwind_support, ); let runner = TestRunner::new( dirs.clone(), target_compiler, use_unstable_features, + panic_unwind_support, skip_tests, bootstrap_host_compiler.triple == target_triple, stdlib_source.clone(), @@ -283,12 +280,14 @@ pub(crate) fn run_tests( bootstrap_host_compiler, rustup_toolchain_name, target_triple.clone(), + panic_unwind_support, ); let mut runner = TestRunner::new( dirs.clone(), target_compiler, use_unstable_features, + panic_unwind_support, skip_tests, bootstrap_host_compiler.triple == target_triple, stdlib_source, @@ -314,6 +313,7 @@ pub(crate) fn run_tests( struct TestRunner<'a> { is_native: bool, jit_supported: bool, + panic_unwind_support: bool, skip_tests: &'a [&'a str], dirs: Dirs, target_compiler: Compiler, @@ -325,6 +325,7 @@ fn new( dirs: Dirs, mut target_compiler: Compiler, use_unstable_features: bool, + panic_unwind_support: bool, skip_tests: &'a [&'a str], is_native: bool, stdlib_source: PathBuf, @@ -335,7 +336,15 @@ fn new( let jit_supported = use_unstable_features && is_native && !target_compiler.triple.contains("windows"); - Self { is_native, jit_supported, skip_tests, dirs, target_compiler, stdlib_source } + Self { + is_native, + jit_supported, + panic_unwind_support, + skip_tests, + dirs, + target_compiler, + stdlib_source, + } } fn run_testsuite(&self, tests: &[TestCase]) { @@ -346,7 +355,7 @@ fn run_testsuite(&self, tests: &[TestCase]) { let _guard = if !config::get_bool(config) || (is_jit_test && !self.jit_supported) - || self.skip_tests.contains(&config) + || self.skip_tests.contains(config) { eprintln!("[{tag}] {testname} (skipped)"); continue; @@ -404,8 +413,11 @@ fn rustc_command(&self, args: I) -> Command cmd.arg("-Cdebuginfo=2"); cmd.arg("--target"); cmd.arg(&self.target_compiler.triple); - cmd.arg("-Cpanic=abort"); + if !self.panic_unwind_support { + cmd.arg("-Cpanic=abort"); + } cmd.arg("--check-cfg=cfg(jit)"); + cmd.arg("--edition=2024"); cmd.args(args); cmd } diff --git a/build_system/usage.txt b/build_system/usage.txt index 5c333fe2db59..6c98087e5239 100644 --- a/build_system/usage.txt +++ b/build_system/usage.txt @@ -25,6 +25,10 @@ OPTIONS: Some features are not yet ready for production usage. This option will disable these features. This includes the JIT mode and inline assembly support. + --panic-unwind-support + Enable support for unwinding when -Cpanic=unwind is used. This currently regresses build + performance. + --frozen Require Cargo.lock and cache are up to date diff --git a/build_system/utils.rs b/build_system/utils.rs index d9807155a3d5..3266aa0ce8b6 100644 --- a/build_system/utils.rs +++ b/build_system/utils.rs @@ -162,7 +162,7 @@ pub(crate) fn run(&self, compiler: &Compiler, dirs: &Dirs) -> Command { pub(crate) fn try_hard_link(src: impl AsRef, dst: impl AsRef) { let src = src.as_ref(); let dst = dst.as_ref(); - if let Err(_) = fs::hard_link(src, dst) { + if fs::hard_link(src, dst).is_err() { fs::copy(src, dst).unwrap(); // Fallback to copying if hardlinking failed } } @@ -179,7 +179,7 @@ pub(crate) fn spawn_and_wait(mut cmd: Command) { /// Create the specified directory if it doesn't exist yet and delete all contents. pub(crate) fn ensure_empty_dir(path: &Path) { fs::create_dir_all(path).unwrap(); - let read_dir = match fs::read_dir(&path) { + let read_dir = match fs::read_dir(path) { Ok(read_dir) => read_dir, Err(err) if err.kind() == io::ErrorKind::NotFound => { return; diff --git a/config.txt b/config.txt index 6ae4767adfdf..85748a4f8a78 100644 --- a/config.txt +++ b/config.txt @@ -20,7 +20,6 @@ aot.mini_core_hello_world testsuite.base_sysroot aot.arbitrary_self_types_pointers_and_wrappers -aot.issue_91827_extern_types jit.std_example aot.std_example aot.dst_field_align diff --git a/example/example.rs b/example/example.rs index 769d262b9ebb..2e15f06f8fc7 100644 --- a/example/example.rs +++ b/example/example.rs @@ -77,12 +77,16 @@ pub fn use_size_of() -> usize { } pub unsafe fn use_copy_intrinsic(src: *const u8, dst: *mut u8) { - intrinsics::copy::(src, dst, 1); + unsafe { + intrinsics::copy::(src, dst, 1); + } } pub unsafe fn use_copy_intrinsic_ref(src: *const u8, dst: *mut u8) { - let copy2 = &intrinsics::copy::; - copy2(src, dst, 1); + unsafe { + let copy2 = &intrinsics::copy::; + copy2(src, dst, 1); + } } pub const ABC: u8 = 6 * 7; @@ -126,11 +130,11 @@ pub fn eq_char(a: char, b: char) -> bool { } pub unsafe fn transmute(c: char) -> u32 { - intrinsics::transmute(c) + unsafe { intrinsics::transmute(c) } } pub unsafe fn deref_str_ptr(s: *const str) -> &'static str { - &*s + unsafe { &*s } } pub fn use_array(arr: [u8; 3]) -> u8 { @@ -146,7 +150,7 @@ pub unsafe fn deref_str_ptr(s: *const str) -> &'static str { } pub unsafe fn use_ctlz_nonzero(a: u16) -> u32 { - intrinsics::ctlz_nonzero(a) + unsafe { intrinsics::ctlz_nonzero(a) } } pub fn ptr_as_usize(ptr: *const u8) -> usize { diff --git a/example/mini_core.rs b/example/mini_core.rs index 304d0d648561..b522ea193716 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -546,7 +546,7 @@ fn panic_in_cleanup() -> ! { #[cfg(all(unix, not(target_vendor = "apple")))] #[link(name = "gcc_s")] -extern "C" { +unsafe extern "C" { fn _Unwind_Resume(exc: *mut ()) -> !; } @@ -555,7 +555,9 @@ fn panic_in_cleanup() -> ! { pub unsafe fn drop_in_place(to_drop: *mut T) { // Code here does not matter - this is replaced by the // real drop glue by the compiler. - drop_in_place(to_drop); + unsafe { + drop_in_place(to_drop); + } } #[lang = "unpin"] @@ -622,7 +624,7 @@ fn deref(&self) -> &Self::Target { #[lang = "exchange_malloc"] unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { - libc::malloc(size) + unsafe { libc::malloc(size) } } #[lang = "drop"] @@ -649,11 +651,11 @@ pub mod intrinsics { #[rustc_intrinsic] pub const fn size_of() -> usize; #[rustc_intrinsic] - pub unsafe fn size_of_val(val: *const T) -> usize; + pub unsafe fn size_of_val(val: *const T) -> usize; #[rustc_intrinsic] pub const fn align_of() -> usize; #[rustc_intrinsic] - pub unsafe fn align_of_val(val: *const T) -> usize; + pub unsafe fn align_of_val(val: *const T) -> usize; #[rustc_intrinsic] pub unsafe fn copy(src: *const T, dst: *mut T, count: usize); #[rustc_intrinsic] @@ -661,7 +663,7 @@ pub mod intrinsics { #[rustc_intrinsic] pub unsafe fn ctlz_nonzero(x: T) -> u32; #[rustc_intrinsic] - pub const fn needs_drop() -> bool; + pub const fn needs_drop() -> bool; #[rustc_intrinsic] pub fn bitreverse(x: T) -> T; #[rustc_intrinsic] @@ -678,13 +680,13 @@ pub mod libc { // symbols to link against. #[cfg_attr(unix, link(name = "c"))] #[cfg_attr(target_env = "msvc", link(name = "legacy_stdio_definitions"))] - extern "C" { + unsafe extern "C" { pub fn printf(format: *const i8, ...) -> i32; } #[cfg_attr(unix, link(name = "c"))] #[cfg_attr(target_env = "msvc", link(name = "msvcrt"))] - extern "C" { + unsafe extern "C" { pub fn puts(s: *const i8) -> i32; pub fn malloc(size: usize) -> *mut u8; pub fn free(ptr: *mut u8); @@ -733,7 +735,7 @@ trait SizedTypeProperties: Sized { } impl SizedTypeProperties for T {} -extern "C" { +unsafe extern "C" { type VaListImpl; } @@ -792,7 +794,7 @@ struct PanicLocation { column: u32, } -#[no_mangle] +#[unsafe(no_mangle)] #[cfg(not(all(windows, target_env = "gnu")))] pub fn get_tls() -> u8 { #[thread_local] diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index a9388814a7f5..10549cd2a41e 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -124,9 +124,11 @@ fn start( static NUM_REF: &'static u8 = unsafe { &*&raw const NUM }; unsafe fn zeroed() -> T { - let mut uninit = MaybeUninit { uninit: () }; - intrinsics::write_bytes(&mut uninit.value.value as *mut T, 0, 1); - uninit.value.value + unsafe { + let mut uninit = MaybeUninit { uninit: () }; + intrinsics::write_bytes(&mut uninit.value.value as *mut T, 0, 1); + uninit.value.value + } } fn take_f32(_f: f32) {} @@ -237,7 +239,7 @@ struct Foo { } unsafe fn uninitialized() -> T { - MaybeUninit { uninit: () }.value.value + unsafe { MaybeUninit { uninit: () }.value.value } } zeroed::<(u8, u8)>(); @@ -270,20 +272,20 @@ unsafe fn uninitialized() -> T { let x = &[0u32, 42u32] as &[u32]; match x { [] => assert_eq!(0u32, 1), - [_, ref y @ ..] => assert_eq!(&x[1] as *const u32 as usize, &y[0] as *const u32 as usize), + [_, y @ ..] => assert_eq!(&x[1] as *const u32 as usize, &y[0] as *const u32 as usize), } assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42); #[cfg(not(any(jit, target_vendor = "apple", windows)))] { - extern "C" { + unsafe extern "C" { #[linkage = "extern_weak"] static ABC: *const u8; } { - extern "C" { + unsafe extern "C" { #[linkage = "extern_weak"] static ABC: *const u8; } @@ -310,7 +312,7 @@ unsafe fn uninitialized() -> T { check_niche_behavior(); - extern "C" { + unsafe extern "C" { type ExternType; } @@ -364,7 +366,7 @@ fn stack_val_align() { } #[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "macos")))] -extern "C" { +unsafe extern "C" { fn global_asm_test(); } @@ -412,7 +414,7 @@ struct pthread_attr_t { #[link(name = "pthread")] #[cfg(unix)] -extern "C" { +unsafe extern "C" { fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int; fn pthread_create( @@ -433,7 +435,7 @@ fn pthread_create( #[link(name = "msvcrt")] #[cfg(windows)] -extern "C" { +unsafe extern "C" { fn WaitForSingleObject(hHandle: LPVOID, dwMilliseconds: DWORD) -> DWORD; fn CreateThread( @@ -455,46 +457,51 @@ struct Thread { impl Thread { unsafe fn create(f: extern "C" fn(_: *mut c_void) -> *mut c_void) -> Self { - #[cfg(unix)] - { - let mut attr: pthread_attr_t = zeroed(); - let mut thread: pthread_t = 0; + unsafe { + #[cfg(unix)] + { + let mut attr: pthread_attr_t = zeroed(); + let mut thread: pthread_t = 0; - if pthread_attr_init(&mut attr) != 0 { - assert!(false); + if pthread_attr_init(&mut attr) != 0 { + assert!(false); + } + + if pthread_create(&mut thread, &attr, f, 0 as *mut c_void) != 0 { + assert!(false); + } + + Thread { handle: thread } } - if pthread_create(&mut thread, &attr, f, 0 as *mut c_void) != 0 { - assert!(false); + #[cfg(windows)] + { + let handle = + CreateThread(0 as *mut c_void, 0, f, 0 as *mut c_void, 0, 0 as *mut u32); + + if (handle as u64) == 0 { + assert!(false); + } + + Thread { handle } } - - Thread { handle: thread } - } - - #[cfg(windows)] - { - let handle = CreateThread(0 as *mut c_void, 0, f, 0 as *mut c_void, 0, 0 as *mut u32); - - if (handle as u64) == 0 { - assert!(false); - } - - Thread { handle } } } unsafe fn join(self) { - #[cfg(unix)] - { - let mut res = 0 as *mut c_void; - pthread_join(self.handle, &mut res); - } + unsafe { + #[cfg(unix)] + { + let mut res = 0 as *mut c_void; + pthread_join(self.handle, &mut res); + } - #[cfg(windows)] - { - // The INFINITE macro is used to signal operations that do not timeout. - let infinite = 0xffffffff; - assert!(WaitForSingleObject(self.handle, infinite) == 0); + #[cfg(windows)] + { + // The INFINITE macro is used to signal operations that do not timeout. + let infinite = 0xffffffff; + assert!(WaitForSingleObject(self.handle, infinite) == 0); + } } } } diff --git a/example/neon.rs b/example/neon.rs index 704f866e2c4f..fb3e10a41c02 100644 --- a/example/neon.rs +++ b/example/neon.rs @@ -14,7 +14,7 @@ unsafe fn test_vpmin_s8() { let a = i8x8::from([1, -2, 3, -4, 5, 6, 7, 8]); let b = i8x8::from([0, 3, 2, 5, 4, 7, 6, 9]); let e = i8x8::from([-2, -4, 5, 7, 0, 2, 4, 6]); - let r: i8x8 = transmute(vpmin_s8(transmute(a), transmute(b))); + let r: i8x8 = unsafe { transmute(vpmin_s8(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -23,7 +23,7 @@ unsafe fn test_vpmin_s16() { let a = i16x4::from([1, 2, 3, -4]); let b = i16x4::from([0, 3, 2, 5]); let e = i16x4::from([1, -4, 0, 2]); - let r: i16x4 = transmute(vpmin_s16(transmute(a), transmute(b))); + let r: i16x4 = unsafe { transmute(vpmin_s16(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -32,7 +32,7 @@ unsafe fn test_vpmin_s32() { let a = i32x2::from([1, -2]); let b = i32x2::from([0, 3]); let e = i32x2::from([-2, 0]); - let r: i32x2 = transmute(vpmin_s32(transmute(a), transmute(b))); + let r: i32x2 = unsafe { transmute(vpmin_s32(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -41,7 +41,7 @@ unsafe fn test_vpmin_u8() { let a = u8x8::from([1, 2, 3, 4, 5, 6, 7, 8]); let b = u8x8::from([0, 3, 2, 5, 4, 7, 6, 9]); let e = u8x8::from([1, 3, 5, 7, 0, 2, 4, 6]); - let r: u8x8 = transmute(vpmin_u8(transmute(a), transmute(b))); + let r: u8x8 = unsafe { transmute(vpmin_u8(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -50,7 +50,7 @@ unsafe fn test_vpmin_u16() { let a = u16x4::from([1, 2, 3, 4]); let b = u16x4::from([0, 3, 2, 5]); let e = u16x4::from([1, 3, 0, 2]); - let r: u16x4 = transmute(vpmin_u16(transmute(a), transmute(b))); + let r: u16x4 = unsafe { transmute(vpmin_u16(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -59,7 +59,7 @@ unsafe fn test_vpmin_u32() { let a = u32x2::from([1, 2]); let b = u32x2::from([0, 3]); let e = u32x2::from([1, 0]); - let r: u32x2 = transmute(vpmin_u32(transmute(a), transmute(b))); + let r: u32x2 = unsafe { transmute(vpmin_u32(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -68,7 +68,7 @@ unsafe fn test_vpmin_f32() { let a = f32x2::from([1., -2.]); let b = f32x2::from([0., 3.]); let e = f32x2::from([-2., 0.]); - let r: f32x2 = transmute(vpmin_f32(transmute(a), transmute(b))); + let r: f32x2 = unsafe { transmute(vpmin_f32(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -77,7 +77,7 @@ unsafe fn test_vpmax_s8() { let a = i8x8::from([1, -2, 3, -4, 5, 6, 7, 8]); let b = i8x8::from([0, 3, 2, 5, 4, 7, 6, 9]); let e = i8x8::from([1, 3, 6, 8, 3, 5, 7, 9]); - let r: i8x8 = transmute(vpmax_s8(transmute(a), transmute(b))); + let r: i8x8 = unsafe { transmute(vpmax_s8(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -86,7 +86,7 @@ unsafe fn test_vpmax_s16() { let a = i16x4::from([1, 2, 3, -4]); let b = i16x4::from([0, 3, 2, 5]); let e = i16x4::from([2, 3, 3, 5]); - let r: i16x4 = transmute(vpmax_s16(transmute(a), transmute(b))); + let r: i16x4 = unsafe { transmute(vpmax_s16(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -95,7 +95,7 @@ unsafe fn test_vpmax_s32() { let a = i32x2::from([1, -2]); let b = i32x2::from([0, 3]); let e = i32x2::from([1, 3]); - let r: i32x2 = transmute(vpmax_s32(transmute(a), transmute(b))); + let r: i32x2 = unsafe { transmute(vpmax_s32(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -104,7 +104,7 @@ unsafe fn test_vpmax_u8() { let a = u8x8::from([1, 2, 3, 4, 5, 6, 7, 8]); let b = u8x8::from([0, 3, 2, 5, 4, 7, 6, 9]); let e = u8x8::from([2, 4, 6, 8, 3, 5, 7, 9]); - let r: u8x8 = transmute(vpmax_u8(transmute(a), transmute(b))); + let r: u8x8 = unsafe { transmute(vpmax_u8(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -113,7 +113,7 @@ unsafe fn test_vpmax_u16() { let a = u16x4::from([1, 2, 3, 4]); let b = u16x4::from([0, 3, 2, 5]); let e = u16x4::from([2, 4, 3, 5]); - let r: u16x4 = transmute(vpmax_u16(transmute(a), transmute(b))); + let r: u16x4 = unsafe { transmute(vpmax_u16(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -122,7 +122,7 @@ unsafe fn test_vpmax_u32() { let a = u32x2::from([1, 2]); let b = u32x2::from([0, 3]); let e = u32x2::from([2, 3]); - let r: u32x2 = transmute(vpmax_u32(transmute(a), transmute(b))); + let r: u32x2 = unsafe { transmute(vpmax_u32(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -131,7 +131,7 @@ unsafe fn test_vpmax_f32() { let a = f32x2::from([1., -2.]); let b = f32x2::from([0., 3.]); let e = f32x2::from([1., 3.]); - let r: f32x2 = transmute(vpmax_f32(transmute(a), transmute(b))); + let r: f32x2 = unsafe { transmute(vpmax_f32(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -139,7 +139,7 @@ unsafe fn test_vpmax_f32() { unsafe fn test_vpadd_s16() { let a = i16x4::from([1, 2, 3, 4]); let b = i16x4::from([0, -1, -2, -3]); - let r: i16x4 = transmute(vpadd_s16(transmute(a), transmute(b))); + let r: i16x4 = unsafe { transmute(vpadd_s16(transmute(a), transmute(b))) }; let e = i16x4::from([3, 7, -1, -5]); assert_eq!(r, e); } @@ -147,7 +147,7 @@ unsafe fn test_vpadd_s16() { unsafe fn test_vpadd_s32() { let a = i32x2::from([1, 2]); let b = i32x2::from([0, -1]); - let r: i32x2 = transmute(vpadd_s32(transmute(a), transmute(b))); + let r: i32x2 = unsafe { transmute(vpadd_s32(transmute(a), transmute(b))) }; let e = i32x2::from([3, -1]); assert_eq!(r, e); } @@ -155,7 +155,7 @@ unsafe fn test_vpadd_s32() { unsafe fn test_vpadd_s8() { let a = i8x8::from([1, 2, 3, 4, 5, 6, 7, 8]); let b = i8x8::from([0, -1, -2, -3, -4, -5, -6, -7]); - let r: i8x8 = transmute(vpadd_s8(transmute(a), transmute(b))); + let r: i8x8 = unsafe { transmute(vpadd_s8(transmute(a), transmute(b))) }; let e = i8x8::from([3, 7, 11, 15, -1, -5, -9, -13]); assert_eq!(r, e); } @@ -163,7 +163,7 @@ unsafe fn test_vpadd_s8() { unsafe fn test_vpadd_u16() { let a = u16x4::from([1, 2, 3, 4]); let b = u16x4::from([30, 31, 32, 33]); - let r: u16x4 = transmute(vpadd_u16(transmute(a), transmute(b))); + let r: u16x4 = unsafe { transmute(vpadd_u16(transmute(a), transmute(b))) }; let e = u16x4::from([3, 7, 61, 65]); assert_eq!(r, e); } @@ -171,7 +171,7 @@ unsafe fn test_vpadd_u16() { unsafe fn test_vpadd_u32() { let a = u32x2::from([1, 2]); let b = u32x2::from([30, 31]); - let r: u32x2 = transmute(vpadd_u32(transmute(a), transmute(b))); + let r: u32x2 = unsafe { transmute(vpadd_u32(transmute(a), transmute(b))) }; let e = u32x2::from([3, 61]); assert_eq!(r, e); } @@ -179,7 +179,7 @@ unsafe fn test_vpadd_u32() { unsafe fn test_vpadd_u8() { let a = u8x8::from([1, 2, 3, 4, 5, 6, 7, 8]); let b = u8x8::from([30, 31, 32, 33, 34, 35, 36, 37]); - let r: u8x8 = transmute(vpadd_u8(transmute(a), transmute(b))); + let r: u8x8 = unsafe { transmute(vpadd_u8(transmute(a), transmute(b))) }; let e = u8x8::from([3, 7, 11, 15, 61, 65, 69, 73]); assert_eq!(r, e); } @@ -188,7 +188,7 @@ unsafe fn test_vpadd_u8() { unsafe fn test_vqsub_u8() { let a = u8x8::from([1, 2, 3, 4, 5, 6, 7, 0xff]); let b = u8x8::from([30, 1, 1, 1, 34, 0xff, 36, 37]); - let r: u8x8 = transmute(vqsub_u8(transmute(a), transmute(b))); + let r: u8x8 = unsafe { transmute(vqsub_u8(transmute(a), transmute(b))) }; let e = u8x8::from([0, 1, 2, 3, 0, 0, 0, 218]); assert_eq!(r, e); } @@ -197,7 +197,7 @@ unsafe fn test_vqsub_u8() { unsafe fn test_vqadd_u8() { let a = u8x8::from([1, 2, 3, 4, 5, 6, 7, 0xff]); let b = u8x8::from([30, 1, 1, 1, 34, 0xff, 36, 37]); - let r: u8x8 = transmute(vqadd_u8(transmute(a), transmute(b))); + let r: u8x8 = unsafe { transmute(vqadd_u8(transmute(a), transmute(b))) }; let e = u8x8::from([31, 3, 4, 5, 39, 0xff, 43, 0xff]); assert_eq!(r, e); } @@ -208,7 +208,7 @@ unsafe fn test_vmaxq_f32() { let a = f32x4::from([0., -1., 2., -3.]); let b = f32x4::from([-4., 5., -6., 7.]); let e = f32x4::from([0., 5., 2., 7.]); - let r: f32x4 = transmute(vmaxq_f32(transmute(a), transmute(b))); + let r: f32x4 = unsafe { transmute(vmaxq_f32(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -218,7 +218,7 @@ unsafe fn test_vminq_f32() { let a = f32x4::from([0., -1., 2., -3.]); let b = f32x4::from([-4., 5., -6., 7.]); let e = f32x4::from([-4., -1., -6., -3.]); - let r: f32x4 = transmute(vminq_f32(transmute(a), transmute(b))); + let r: f32x4 = unsafe { transmute(vminq_f32(transmute(a), transmute(b))) }; assert_eq!(r, e); } @@ -227,7 +227,7 @@ unsafe fn test_vaddvq_f32() { // AArch64 llvm intrinsic: llvm.aarch64.neon.faddv.f32.v4f32 let a = f32x4::from([0., 1., 2., 3.]); let e = 6f32; - let r = vaddvq_f32(transmute(a)); + let r = unsafe { vaddvq_f32(transmute(a)) }; assert_eq!(r, e); } @@ -236,7 +236,7 @@ unsafe fn test_vrndnq_f32() { // llvm intrinsic: llvm.roundeven.v4f32 let a = f32x4::from([0.1, -1.9, 4.5, 5.5]); let e = f32x4::from([0., -2., 4., 6.]); - let r: f32x4 = transmute(vrndnq_f32(transmute(a))); + let r: f32x4 = unsafe { transmute(vrndnq_f32(transmute(a))) }; assert_eq!(r, e); } diff --git a/example/raw-dylib.rs b/example/raw-dylib.rs index 4711884f76af..5f5bde7d4dc5 100644 --- a/example/raw-dylib.rs +++ b/example/raw-dylib.rs @@ -5,7 +5,7 @@ fn main() { #[cfg(windows)] { #[link(name = "kernel32", kind = "raw-dylib")] - extern "C" { + unsafe extern "C" { fn GetModuleFileNameA( module: *mut std::ffi::c_void, filename: *mut u8, diff --git a/example/std_example.rs b/example/std_example.rs index 5d83066cffb8..c569ef0ef829 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -230,51 +230,53 @@ unsafe fn test_crc32() { #[cfg(target_arch = "x86_64")] #[target_feature(enable = "sse2")] unsafe fn test_simd() { - assert!(is_x86_feature_detected!("sse2")); + unsafe { + assert!(is_x86_feature_detected!("sse2")); - let x = _mm_setzero_si128(); - let y = _mm_set1_epi16(7); - let or = _mm_or_si128(x, y); - let cmp_eq = _mm_cmpeq_epi8(y, y); - let cmp_lt = _mm_cmplt_epi8(y, y); + let x = _mm_setzero_si128(); + let y = _mm_set1_epi16(7); + let or = _mm_or_si128(x, y); + let cmp_eq = _mm_cmpeq_epi8(y, y); + let cmp_lt = _mm_cmplt_epi8(y, y); - let (zero0, zero1) = std::mem::transmute::<_, (u64, u64)>(x); - assert_eq!((zero0, zero1), (0, 0)); - assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]); - assert_eq!( - std::mem::transmute::<_, [u16; 8]>(cmp_eq), - [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff] - ); - assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]); + let (zero0, zero1) = std::mem::transmute::<_, (u64, u64)>(x); + assert_eq!((zero0, zero1), (0, 0)); + assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]); + assert_eq!( + std::mem::transmute::<_, [u16; 8]>(cmp_eq), + [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff] + ); + assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]); - test_mm_slli_si128(); - test_mm_movemask_epi8(); - test_mm256_movemask_epi8(); - test_mm_add_epi8(); - test_mm_add_pd(); - test_mm_cvtepi8_epi16(); - #[cfg(not(jit))] - test_mm_cvtps_epi32(); - test_mm_cvttps_epi32(); - test_mm_cvtsi128_si64(); + test_mm_slli_si128(); + test_mm_movemask_epi8(); + test_mm256_movemask_epi8(); + test_mm_add_epi8(); + test_mm_add_pd(); + test_mm_cvtepi8_epi16(); + #[cfg(not(jit))] + test_mm_cvtps_epi32(); + test_mm_cvttps_epi32(); + test_mm_cvtsi128_si64(); - test_mm_extract_epi8(); - test_mm_insert_epi16(); - test_mm_shuffle_epi8(); + test_mm_extract_epi8(); + test_mm_insert_epi16(); + test_mm_shuffle_epi8(); - #[cfg(not(jit))] - test_mm_cmpestri(); + #[cfg(not(jit))] + test_mm_cmpestri(); - test_mm256_shuffle_epi8(); - test_mm256_permute2x128_si256(); - test_mm256_permutevar8x32_epi32(); + test_mm256_shuffle_epi8(); + test_mm256_permute2x128_si256(); + test_mm256_permutevar8x32_epi32(); - #[rustfmt::skip] + #[rustfmt::skip] let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); - assert_eq!(mask1, 1); + assert_eq!(mask1, 1); - #[cfg(not(jit))] - test_crc32(); + #[cfg(not(jit))] + test_crc32(); + } } #[cfg(target_arch = "x86_64")] @@ -361,7 +363,7 @@ fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) #[cfg(target_arch = "x86_64")] #[target_feature(enable = "sse2")] -pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) { +pub fn assert_eq_m128d(a: __m128d, b: __m128d) { if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 { panic!("{:?} != {:?}", a, b); } @@ -369,15 +371,19 @@ pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) { #[cfg(target_arch = "x86_64")] #[target_feature(enable = "avx")] -pub unsafe fn assert_eq_m256i(a: __m256i, b: __m256i) { - assert_eq!(std::mem::transmute::<_, [u64; 4]>(a), std::mem::transmute::<_, [u64; 4]>(b)) +pub fn assert_eq_m256i(a: __m256i, b: __m256i) { + unsafe { + assert_eq!(std::mem::transmute::<_, [u64; 4]>(a), std::mem::transmute::<_, [u64; 4]>(b)) + } } #[cfg(target_arch = "x86_64")] #[target_feature(enable = "sse2")] unsafe fn test_mm_cvtsi128_si64() { - let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0])); - assert_eq!(r, 5); + unsafe { + let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0])); + assert_eq!(r, 5); + } } #[cfg(target_arch = "x86_64")] @@ -445,20 +451,24 @@ unsafe fn test_mm_shuffle_epi8() { #[cfg(target_arch = "x86_64")] #[target_feature(enable = "sse4.2")] unsafe fn str_to_m128i(s: &[u8]) -> __m128i { - assert!(s.len() <= 16); - let slice = &mut [0u8; 16]; - std::ptr::copy_nonoverlapping(s.as_ptr(), slice.as_mut_ptr(), s.len()); - _mm_loadu_si128(slice.as_ptr() as *const _) + unsafe { + assert!(s.len() <= 16); + let slice = &mut [0u8; 16]; + std::ptr::copy_nonoverlapping(s.as_ptr(), slice.as_mut_ptr(), s.len()); + _mm_loadu_si128(slice.as_ptr() as *const _) + } } #[cfg(not(jit))] #[cfg(target_arch = "x86_64")] #[target_feature(enable = "sse4.2")] unsafe fn test_mm_cmpestri() { - let a = str_to_m128i(b"bar - garbage"); - let b = str_to_m128i(b"foobar"); - let i = _mm_cmpestri::<_SIDD_CMP_EQUAL_ORDERED>(a, 3, b, 6); - assert_eq!(3, i); + unsafe { + let a = str_to_m128i(b"bar - garbage"); + let b = str_to_m128i(b"foobar"); + let i = _mm_cmpestri::<_SIDD_CMP_EQUAL_ORDERED>(a, 3, b, 6); + assert_eq!(3, i); + } } #[cfg(target_arch = "x86_64")] @@ -513,35 +523,39 @@ unsafe fn test_mm256_permutevar8x32_epi32() { #[target_feature(enable = "avx2")] #[cfg(not(jit))] unsafe fn test_mm_cvtps_epi32() { - let floats: [f32; 4] = [1.5, -2.5, i32::MAX as f32 + 1.0, f32::NAN]; + unsafe { + let floats: [f32; 4] = [1.5, -2.5, i32::MAX as f32 + 1.0, f32::NAN]; - let float_vec = _mm_loadu_ps(floats.as_ptr()); - let int_vec = _mm_cvtps_epi32(float_vec); + let float_vec = _mm_loadu_ps(floats.as_ptr()); + let int_vec = _mm_cvtps_epi32(float_vec); - let mut ints: [i32; 4] = [0; 4]; - _mm_storeu_si128(ints.as_mut_ptr() as *mut __m128i, int_vec); + let mut ints: [i32; 4] = [0; 4]; + _mm_storeu_si128(ints.as_mut_ptr() as *mut __m128i, int_vec); - // this is very different from `floats.map(|f| f as i32)`! - let expected_ints: [i32; 4] = [2, -2, i32::MIN, i32::MIN]; + // this is very different from `floats.map(|f| f as i32)`! + let expected_ints: [i32; 4] = [2, -2, i32::MIN, i32::MIN]; - assert_eq!(ints, expected_ints); + assert_eq!(ints, expected_ints); + } } #[cfg(target_arch = "x86_64")] #[target_feature(enable = "avx2")] unsafe fn test_mm_cvttps_epi32() { - let floats: [f32; 4] = [1.5, -2.5, i32::MAX as f32 + 1.0, f32::NAN]; + unsafe { + let floats: [f32; 4] = [1.5, -2.5, i32::MAX as f32 + 1.0, f32::NAN]; - let float_vec = _mm_loadu_ps(floats.as_ptr()); - let int_vec = _mm_cvttps_epi32(float_vec); + let float_vec = _mm_loadu_ps(floats.as_ptr()); + let int_vec = _mm_cvttps_epi32(float_vec); - let mut ints: [i32; 4] = [0; 4]; - _mm_storeu_si128(ints.as_mut_ptr() as *mut __m128i, int_vec); + let mut ints: [i32; 4] = [0; 4]; + _mm_storeu_si128(ints.as_mut_ptr() as *mut __m128i, int_vec); - // this is very different from `floats.map(|f| f as i32)`! - let expected_ints: [i32; 4] = [1, -2, i32::MIN, i32::MIN]; + // this is very different from `floats.map(|f| f as i32)`! + let expected_ints: [i32; 4] = [1, -2, i32::MIN, i32::MIN]; - assert_eq!(ints, expected_ints); + assert_eq!(ints, expected_ints); + } } fn test_checked_mul() { diff --git a/patches/0028-sysroot_tests-Disable-long-running-tests.patch b/patches/0028-sysroot_tests-Disable-long-running-tests.patch index 357b8d306cf6..853acab2773b 100644 --- a/patches/0028-sysroot_tests-Disable-long-running-tests.patch +++ b/patches/0028-sysroot_tests-Disable-long-running-tests.patch @@ -11,38 +11,41 @@ diff --git a/coretests/tests/slice.rs b/coretests/tests/slice.rs index 8402833..84592e0 100644 --- a/coretests/tests/slice.rs +++ b/coretests/tests/slice.rs -@@ -1809,6 +1809,7 @@ fn sort_unstable() { - } - } +@@ -1619,7 +1619,7 @@ fn brute_force_rotate_test_1() { -+/* #[test] #[cfg(not(target_arch = "wasm32"))] - #[cfg_attr(miri, ignore)] // Miri is too slow -@@ -1914,6 +1915,7 @@ fn select_nth_unstable() { - v.select_nth_unstable(0); - assert!(v == [0xDEADBEEF]); - } -+*/ +-#[cfg_attr(miri, ignore)] // Miri is too slow ++#[ignore] // Miri is too slow + fn select_nth_unstable() { + use core::cmp::Ordering::{Equal, Greater, Less}; - #[test] - #[should_panic(expected = "index 0 greater than length of slice")] -@@ -2462,6 +2462,7 @@ take_tests! { - #[cfg(not(miri))] // unused in Miri +@@ -2303,14 +2303,14 @@ split_off_tests! { const EMPTY_MAX: &'static [()] = &[(); usize::MAX]; -+/* // can't be a constant due to const mutability rules - #[cfg(not(miri))] // unused in Miri +-#[cfg(not(miri))] // unused in Miri ++#[cfg(any())] // unused in Miri macro_rules! empty_max_mut { -@@ -2485,6 +2486,7 @@ take_tests! { - (split_off_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), - (split_off_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), + () => { + &mut [(); usize::MAX] as _ + }; } -+*/ - #[test] - fn test_slice_from_ptr_range() { +-#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations) ++#[cfg(any())] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations) + split_off_tests! { + slice: &[(); usize::MAX], method: split_off, + (split_off_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]), +@@ -2318,7 +2318,7 @@ split_off_tests! { + (split_off_in_bounds_max_range_from, (usize::MAX..), Some(&[] as _), EMPTY_MAX), + } + +-#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations) ++#[cfg(any())] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations) + split_off_tests! { + slice: &mut [(); usize::MAX], method: split_off_mut, + (split_off_mut_in_bounds_max_range_to, (..usize::MAX), Some(empty_max_mut!()), &mut [(); 0]), diff --git a/alloctests/tests/sort/tests.rs b/alloctests/tests/sort/tests.rs index d321f8d..8b2040a 100644 --- a/alloctests/tests/sort/tests.rs diff --git a/rust-toolchain b/rust-toolchain index 150bb562f74a..17c2cc5ac660 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-06-24" +channel = "nightly-2025-11-08" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/scripts/cargo-clif.rs b/scripts/cargo-clif.rs index e6c63bf5e650..e391cc7f75a9 100644 --- a/scripts/cargo-clif.rs +++ b/scripts/cargo-clif.rs @@ -12,7 +12,11 @@ fn main() { sysroot = sysroot.parent().unwrap(); } - let mut rustflags = vec!["-Cpanic=abort".to_owned(), "-Zpanic-abort-tests".to_owned()]; + let mut rustflags = vec![]; + if !cfg!(support_panic_unwind) { + rustflags.push("-Cpanic=abort".to_owned()); + rustflags.push("-Zpanic-abort-tests".to_owned()); + } if let Some(name) = option_env!("BUILTIN_BACKEND") { rustflags.push(format!("-Zcodegen-backend={name}")); } else { diff --git a/scripts/rustc-clif.rs b/scripts/rustc-clif.rs index 528031af82a8..15d929d0f5a5 100644 --- a/scripts/rustc-clif.rs +++ b/scripts/rustc-clif.rs @@ -17,8 +17,10 @@ fn main() { let passed_args = std::env::args_os().skip(1).collect::>(); let mut args = vec![]; - args.push(OsString::from("-Cpanic=abort")); - args.push(OsString::from("-Zpanic-abort-tests")); + if !cfg!(support_panic_unwind) { + args.push(OsString::from("-Cpanic=abort")); + args.push(OsString::from("-Zpanic-abort-tests")); + } if let Some(name) = option_env!("BUILTIN_BACKEND") { args.push(OsString::from(format!("-Zcodegen-backend={name}"))) } else { diff --git a/scripts/rustdoc-clif.rs b/scripts/rustdoc-clif.rs index 6ebe060d8bbd..dc5bef18cda8 100644 --- a/scripts/rustdoc-clif.rs +++ b/scripts/rustdoc-clif.rs @@ -17,8 +17,10 @@ fn main() { let passed_args = std::env::args_os().skip(1).collect::>(); let mut args = vec![]; - args.push(OsString::from("-Cpanic=abort")); - args.push(OsString::from("-Zpanic-abort-tests")); + if !cfg!(support_panic_unwind) { + args.push(OsString::from("-Cpanic=abort")); + args.push(OsString::from("-Zpanic-abort-tests")); + } if let Some(name) = option_env!("BUILTIN_BACKEND") { args.push(OsString::from(format!("-Zcodegen-backend={name}"))) } else { diff --git a/scripts/rustup.sh b/scripts/rustup.sh index 152c243aa6ad..fdfd03029b16 100755 --- a/scripts/rustup.sh +++ b/scripts/rustup.sh @@ -46,7 +46,7 @@ case $1 in git pull origin master branch=sync_cg_clif-$(date +%Y-%m-%d) git checkout -b "$branch" - "$cg_clif/git-fixed-subtree.sh" pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/rust-lang/rustc_codegen_cranelift.git master + "$cg_clif/git-fixed-subtree.sh" pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/rust-lang/rustc_codegen_cranelift.git main git push -u my "$branch" # immediately merge the merge commit into cg_clif to prevent merge conflicts when syncing diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index 492f4dc44527..c16cb4e538fe 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -50,23 +50,24 @@ EOF cat <( + ); } + +- #[cfg(not(test))] +- if b && dwn_ctx.is_running_on_ci && CiEnv::is_rust_lang_managed_ci_job() { +- // On rust-lang CI, we must always rebuild LLVM if there were any modifications to it +- panic!( +- "\`llvm.download-ci-llvm\` cannot be set to \`true\` on CI. Use \`if-unchanged\` instead." +- ); +- } +- + // If download-ci-llvm=true we also want to check that CI llvm is available + b && llvm::is_ci_llvm_available_for_target(&dwn_ctx.host_target, asserts) + } EOF popd diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 62f1cc6a8933..b5af585a732e 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -10,7 +10,7 @@ pushd rust command -v rg >/dev/null 2>&1 || cargo install ripgrep -rm -r tests/ui/{unsized-locals/,lto/,linkage*} || true +rm -r tests/ui/{lto/,linkage*} || true for test in $(rg --files-with-matches "lto" tests/{codegen-units,ui,incremental}); do rm $test done @@ -34,6 +34,7 @@ git checkout -- tests/ui/entry-point/auxiliary/bad_main_functions.rs # vendor intrinsics rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic rm tests/ui/simd/dont-invalid-bitcast-x86_64.rs # unimplemented llvm.x86.sse41.round.ps +rm tests/ui/simd/intrinsic/generic-arithmetic-pass.rs # unimplemented simd_funnel_{shl,shr} # exotic linkages rm tests/incremental/hashes/function_interfaces.rs @@ -42,8 +43,14 @@ rm -r tests/run-make/naked-symbol-visibility # variadic arguments rm tests/ui/abi/mir/mir_codegen_calls_variadic.rs # requires float varargs +rm tests/ui/c-variadic/naked.rs # same rm tests/ui/abi/variadic-ffi.rs # requires callee side vararg support rm -r tests/run-make/c-link-to-rust-va-list-fn # requires callee side vararg support +rm tests/ui/c-variadic/valid.rs # same +rm tests/ui/c-variadic/trait-method.rs # same +rm tests/ui/c-variadic/inherent-method.rs # same +rm tests/ui/sanitizer/kcfi-c-variadic.rs # same +rm tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs # variadics for calling conventions other than C unsupported rm tests/ui/delegation/fn-header.rs # misc unimplemented things @@ -56,8 +63,13 @@ rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't rm tests/ui/asm/global-asm-mono-sym-fn.rs # same rm tests/ui/asm/naked-asm-mono-sym-fn.rs # same rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported +rm tests/ui/asm/label-operand.rs # same rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes -rm -r tests/run-make/embed-source-dwarf # embedding sources in debuginfo +rm -r tests/run-make/used-proc-macro # used(linker) isn't supported yet +rm tests/ui/linking/no-gc-encapsulation-symbols.rs # same +rm tests/ui/attributes/fn-align-dyn.rs # per-function alignment not supported +rm -r tests/ui/explicit-tail-calls # tail calls +rm -r tests/run-make/pointer-auth-link-with-c # pointer auth # requires LTO rm -r tests/run-make/cdylib @@ -69,15 +81,13 @@ rm -r tests/run-make/reachable-extern-fn-available-lto # coverage instrumentation rm tests/ui/consts/precise-drop-with-coverage.rs -rm tests/ui/issues/issue-85461.rs rm -r tests/ui/instrument-coverage/ # optimization tests # ================== rm tests/ui/codegen/issue-28950.rs # depends on stack size optimizations rm tests/ui/codegen/init-large-type.rs # same -rm -r tests/run-make/fmt-write-bloat/ # tests an optimization -rm tests/ui/statics/const_generics.rs # same +rm tests/ui/statics/const_generics.rs # tests an optimization rm tests/ui/linking/executable-no-mangle-strip.rs # requires --gc-sections to work for statics # backend specific tests @@ -92,7 +102,7 @@ rm -r tests/run-make/llvm-location-discriminator-limit-dummy-span # same rm tests/ui/abi/stack-protector.rs # requires stack protector support rm -r tests/run-make/emit-stack-sizes # requires support for -Z emit-stack-sizes rm -r tests/run-make/optimization-remarks-dir # remarks are LLVM specific -rm -r tests/ui/optimization-remark.rs # same +rm -r tests/ui/codegen/remark-flag-functionality.rs # same rm -r tests/run-make/print-to-output # requires --print relocation-models # requires asm, llvm-ir and/or llvm-bc emit support @@ -123,6 +133,8 @@ rm -r tests/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump rm -r tests/run-make/strip # same rm -r tests/run-make-cargo/compiler-builtins # Expects lib/rustlib/src/rust to contains the standard library source rm -r tests/run-make/translation # same +rm -r tests/run-make-cargo/panic-immediate-abort-works # same +rm -r tests/run-make-cargo/panic-immediate-abort-codegen # same rm -r tests/run-make/missing-unstable-trait-bound # This disables support for unstable features, but running cg_clif needs some unstable features rm -r tests/run-make/const-trait-stable-toolchain # same rm -r tests/run-make/print-request-help-stable-unstable # same @@ -130,6 +142,7 @@ rm -r tests/run-make/incr-add-rust-src-component rm tests/ui/errors/remap-path-prefix-sysroot.rs # different sysroot source path rm -r tests/run-make/export/extern-opt # something about rustc version mismatches rm -r tests/run-make/export # same +rm -r tests/ui/compiletest-self-test/compile-flags-incremental.rs # needs compiletest compiled with panic=unwind # genuine bugs # ============ @@ -143,9 +156,9 @@ rm tests/ui/backtrace/synchronized-panic-handler.rs # missing needs-unwind annot rm tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs # same rm tests/ui/async-await/async-drop/async-drop-initial.rs # same (rust-lang/rust#140493) rm -r tests/ui/codegen/equal-pointers-unequal # make incorrect assumptions about the location of stack variables +rm -r tests/run-make-cargo/rustdoc-scrape-examples-paths # FIXME(rust-lang/rust#145580) incr comp bug -rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd -rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # same +rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # really slow with unoptimized libstd rm tests/ui/process/process-panic-after-fork.rs # same cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist diff --git a/src/abi/mod.rs b/src/abi/mod.rs index d7f17795815d..9ac282df5b5e 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -7,7 +7,9 @@ use std::borrow::Cow; use std::mem; -use cranelift_codegen::ir::{ArgumentPurpose, SigRef}; +use cranelift_codegen::ir::{ + ArgumentPurpose, BlockArg, ExceptionTableData, ExceptionTableItem, ExceptionTag, SigRef, +}; use cranelift_codegen::isa::CallConv; use cranelift_module::ModuleError; use rustc_abi::{CanonAbi, ExternAbi, X86Call}; @@ -21,10 +23,12 @@ use rustc_span::source_map::Spanned; use rustc_target::callconv::{FnAbi, PassMode}; use rustc_target::spec::Arch; -use smallvec::SmallVec; +use smallvec::{SmallVec, smallvec}; use self::pass_mode::*; pub(crate) use self::returning::codegen_return; +use crate::base::codegen_unwind_terminate; +use crate::debuginfo::EXCEPTION_HANDLER_CLEANUP; use crate::prelude::*; fn clif_sig_from_fn_abi<'tcx>( @@ -82,7 +86,7 @@ pub(crate) fn get_function_sig<'tcx>( clif_sig_from_fn_abi( tcx, default_call_conv, - &FullyMonomorphizedLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()), + FullyMonomorphizedLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()), ) } @@ -111,7 +115,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { /// Instance must be monomorphized pub(crate) fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef { let func_id = import_function(self.tcx, self.module, inst); - let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func); + let func_ref = self.module.declare_func_in_func(func_id, self.bcx.func); if self.clif_comments.enabled() { self.add_comment(func_ref, format!("{:?}", inst)); @@ -182,7 +186,7 @@ fn lib_call_unadjusted( ) -> &[Value] { let sig = Signature { params, returns, call_conv: self.target_config.default_call_conv }; let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap(); - let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func); + let func_ref = self.module.declare_func_in_func(func_id, self.bcx.func); let call_inst = self.bcx.ins().call(func_ref, args); if self.clif_comments.enabled() { self.add_comment(func_ref, format!("{:?}", name)); @@ -267,7 +271,7 @@ enum ArgKind<'tcx> { // individual function arguments. let tupled_arg_tys = match arg_ty.kind() { - ty::Tuple(ref tys) => tys, + ty::Tuple(tys) => tys, _ => bug!("spread argument isn't a tuple?! but {:?}", arg_ty), }; @@ -297,7 +301,7 @@ enum ArgKind<'tcx> { Some(cvalue_for_param(fx, None, None, arg_abi, &mut block_params_iter).unwrap()); } - assert!(arg_abis_iter.next().is_none(), "ArgAbi left behind"); + assert_eq!(arg_abis_iter.next(), None, "ArgAbi left behind for {:?}", fx.fn_abi); assert!(block_params_iter.next().is_none(), "arg_value left behind"); self::comments::add_locals_header_comment(fx); @@ -381,7 +385,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( args: &[Spanned>], destination: Place<'tcx>, target: Option, - _unwind: UnwindAction, + unwind: UnwindAction, ) { let func = codegen_operand(fx, func); let fn_sig = func.layout().ty.fn_sig(fx.tcx); @@ -416,7 +420,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( if fx.tcx.symbol_name(instance).name.starts_with("llvm.") { crate::intrinsics::codegen_llvm_intrinsic_call( fx, - &fx.tcx.symbol_name(instance).name, + fx.tcx.symbol_name(instance).name, args, ret_place, target, @@ -490,7 +494,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( }; let tupled_arguments = match pack_arg.value.layout().ty.kind() { - ty::Tuple(ref tupled_arguments) => tupled_arguments, + ty::Tuple(tupled_arguments) => tupled_arguments, _ => bug!("argument to function with \"rust-call\" ABI is not a tuple"), }; @@ -516,12 +520,6 @@ pub(crate) fn codegen_terminator_call<'tcx>( let args = args; assert_eq!(fn_abi.args.len(), args.len()); - #[derive(Copy, Clone)] - enum CallTarget { - Direct(FuncRef), - Indirect(SigRef, Value), - } - let (func_ref, first_arg_override) = match instance { // Trait object call Some(Instance { def: InstanceKind::Virtual(_, idx), .. }) => { @@ -537,7 +535,7 @@ enum CallTarget { } let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0].value, idx); - let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi); + let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, fn_abi); let sig = fx.bcx.import_signature(sig); (CallTarget::Indirect(sig, method), Some(ptr.get_addr(fx))) @@ -557,7 +555,7 @@ enum CallTarget { } let func = func.load_scalar(fx); - let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi); + let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, fn_abi); let sig = fx.bcx.import_signature(sig); (CallTarget::Indirect(sig, func), None) @@ -567,7 +565,7 @@ enum CallTarget { self::returning::codegen_with_call_return_arg(fx, &fn_abi.ret, ret_place, |fx, return_ptr| { let mut call_args = return_ptr .into_iter() - .chain(first_arg_override.into_iter()) + .chain(first_arg_override) .chain( args.into_iter() .enumerate() @@ -580,21 +578,15 @@ enum CallTarget { // FIXME: Find a cleaner way to support varargs. if fn_abi.c_variadic { - adjust_call_for_c_variadic(fx, &fn_abi, source_info, func_ref, &mut call_args); + adjust_call_for_c_variadic(fx, fn_abi, source_info, func_ref, &mut call_args); } - let call_inst = match func_ref { - CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args), - CallTarget::Indirect(sig, func_ptr) => { - fx.bcx.ins().call_indirect(sig, func_ptr, &call_args) - } - }; - if fx.clif_comments.enabled() { - with_no_trimmed_paths!(fx.add_comment(call_inst, format!("abi: {:?}", fn_abi))); + let nop_inst = fx.bcx.ins().nop(); + with_no_trimmed_paths!(fx.add_post_comment(nop_inst, format!("abi: {:?}", fn_abi))); } - fx.bcx.func.dfg.inst_results(call_inst).iter().copied().collect::>() + codegen_call_with_unwind_action(fx, source_info.span, func_ref, unwind, &call_args, None) }); if let Some(dest) = target { @@ -704,7 +696,7 @@ pub(crate) fn codegen_drop<'tcx>( source_info: mir::SourceInfo, drop_place: CPlace<'tcx>, target: BasicBlock, - _unwind: UnwindAction, + unwind: UnwindAction, ) { let ty = drop_place.layout().ty; let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty); @@ -748,11 +740,16 @@ pub(crate) fn codegen_drop<'tcx>( let fn_abi = FullyMonomorphizedLayoutCx(fx.tcx) .fn_abi_of_instance(virtual_drop, ty::List::empty()); - let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi); + let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, fn_abi); let sig = fx.bcx.import_signature(sig); - // FIXME implement cleanup on exceptions - fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]); - fx.bcx.ins().jump(ret_block, &[]); + codegen_call_with_unwind_action( + fx, + source_info.span, + CallTarget::Indirect(sig, drop_fn), + unwind, + &[ptr], + Some(ret_block), + ); } _ => { assert!(!matches!(drop_instance.def, InstanceKind::Virtual(_, _))); @@ -771,15 +768,146 @@ pub(crate) fn codegen_drop<'tcx>( if drop_instance.def.requires_caller_location(fx.tcx) { // Pass the caller location for `#[track_caller]`. let caller_location = fx.get_caller_location(source_info); - call_args.extend( - adjust_arg_for_abi(fx, caller_location, &fn_abi.args[1], false).into_iter(), - ); + call_args.extend(adjust_arg_for_abi( + fx, + caller_location, + &fn_abi.args[1], + false, + )); } let func_ref = fx.get_function_ref(drop_instance); - fx.bcx.ins().call(func_ref, &call_args); - // FIXME implement cleanup on exceptions - fx.bcx.ins().jump(ret_block, &[]); + codegen_call_with_unwind_action( + fx, + source_info.span, + CallTarget::Direct(func_ref), + unwind, + &call_args, + Some(ret_block), + ); + } + } + } +} + +#[derive(Copy, Clone)] +pub(crate) enum CallTarget { + Direct(FuncRef), + Indirect(SigRef, Value), +} + +pub(crate) fn codegen_call_with_unwind_action( + fx: &mut FunctionCx<'_, '_, '_>, + span: Span, + func_ref: CallTarget, + mut unwind: UnwindAction, + call_args: &[Value], + target_block: Option, +) -> SmallVec<[Value; 2]> { + let sig_ref = match func_ref { + CallTarget::Direct(func_ref) => fx.bcx.func.dfg.ext_funcs[func_ref].signature, + CallTarget::Indirect(sig_ref, _func_ptr) => sig_ref, + }; + + if target_block.is_some() { + assert!(fx.bcx.func.dfg.signatures[sig_ref].returns.is_empty()); + } + + if cfg!(not(feature = "unwinding")) { + unwind = UnwindAction::Unreachable; + } + + match unwind { + UnwindAction::Continue | UnwindAction::Unreachable => { + let call_inst = match func_ref { + CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, call_args), + CallTarget::Indirect(sig, func_ptr) => { + fx.bcx.ins().call_indirect(sig, func_ptr, call_args) + } + }; + + if let Some(target_block) = target_block { + fx.bcx.ins().jump(target_block, &[]); + smallvec![] + } else { + fx.bcx + .func + .dfg + .inst_results(call_inst) + .iter() + .copied() + .collect::>() + } + } + UnwindAction::Cleanup(_) | UnwindAction::Terminate(_) => { + let returns_types = fx.bcx.func.dfg.signatures[sig_ref] + .returns + .iter() + .map(|return_param| return_param.value_type) + .collect::>(); + + let fallthrough_block = fx.bcx.create_block(); + let fallthrough_block_call_args = returns_types + .iter() + .enumerate() + .map(|(i, _)| BlockArg::TryCallRet(i.try_into().unwrap())) + .collect::>(); + let fallthrough_block_call = fx.bcx.func.dfg.block_call( + target_block.unwrap_or(fallthrough_block), + &fallthrough_block_call_args, + ); + let pre_cleanup_block = fx.bcx.create_block(); + let pre_cleanup_block_call = + fx.bcx.func.dfg.block_call(pre_cleanup_block, &[BlockArg::TryCallExn(0)]); + let exception_table = fx.bcx.func.dfg.exception_tables.push(ExceptionTableData::new( + sig_ref, + fallthrough_block_call, + [ExceptionTableItem::Tag( + ExceptionTag::with_number(EXCEPTION_HANDLER_CLEANUP).unwrap(), + pre_cleanup_block_call, + )], + )); + + match func_ref { + CallTarget::Direct(func_ref) => { + fx.bcx.ins().try_call(func_ref, call_args, exception_table); + } + CallTarget::Indirect(_sig, func_ptr) => { + fx.bcx.ins().try_call_indirect(func_ptr, call_args, exception_table); + } + } + + fx.bcx.seal_block(pre_cleanup_block); + fx.bcx.switch_to_block(pre_cleanup_block); + fx.bcx.set_cold_block(pre_cleanup_block); + match unwind { + UnwindAction::Continue | UnwindAction::Unreachable => unreachable!(), + UnwindAction::Cleanup(cleanup) => { + let exception_ptr = + fx.bcx.append_block_param(pre_cleanup_block, fx.pointer_type); + fx.bcx.def_var(fx.exception_slot, exception_ptr); + let cleanup_block = fx.get_block(cleanup); + fx.bcx.ins().jump(cleanup_block, &[]); + } + UnwindAction::Terminate(reason) => { + // FIXME dedup terminate blocks + fx.bcx.append_block_param(pre_cleanup_block, fx.pointer_type); + + codegen_unwind_terminate(fx, span, reason); + } + } + + if target_block.is_none() { + fx.bcx.seal_block(fallthrough_block); + fx.bcx.switch_to_block(fallthrough_block); + let returns = returns_types + .into_iter() + .map(|ty| fx.bcx.append_block_param(fallthrough_block, ty)) + .collect(); + fx.bcx.ins().nop(); + returns + } else { + smallvec![] } } } diff --git a/src/abi/pass_mode.rs b/src/abi/pass_mode.rs index 7a909a740b05..44b63aa95f83 100644 --- a/src/abi/pass_mode.rs +++ b/src/abi/pass_mode.rs @@ -209,12 +209,7 @@ pub(super) fn to_casted_value<'tcx>( cast_target_to_abi_params(cast) .into_iter() .map(|(offset, param)| { - let val = ptr.offset_i64(fx, offset.bytes() as i64).load( - fx, - param.value_type, - MemFlags::new(), - ); - val + ptr.offset_i64(fx, offset.bytes() as i64).load(fx, param.value_type, MemFlags::new()) }) .collect() } diff --git a/src/base.rs b/src/base.rs index 7d50548b4026..0d3b38d52c8d 100644 --- a/src/base.rs +++ b/src/base.rs @@ -12,6 +12,8 @@ use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv}; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_session::config::OutputFilenames; +use rustc_span::Symbol; use crate::constant::ConstantCx; use crate::debuginfo::{FunctionDebugContext, TypeDebugContext}; @@ -25,11 +27,13 @@ pub(crate) struct CodegenedFunction { func: Function, clif_comments: CommentWriter, func_debug_cx: Option, + inline_asm: String, } pub(crate) fn codegen_fn<'tcx>( tcx: TyCtxt<'tcx>, - cx: &mut crate::CodegenCx, + cgu_name: Symbol, + mut debug_context: Option<&mut DebugContext>, type_dbg: &mut TypeDebugContext<'tcx>, cached_func: Function, module: &mut dyn Module, @@ -60,7 +64,9 @@ pub(crate) fn codegen_fn<'tcx>( func.clear(); func.name = UserFuncName::user(0, func_id.as_u32()); func.signature = sig; - func.collect_debug_info(); + if debug_context.is_some() { + func.collect_debug_info(); + } let mut bcx = FunctionBuilder::new(&mut func, &mut func_ctx); @@ -74,23 +80,27 @@ pub(crate) fn codegen_fn<'tcx>( // Make FunctionCx let target_config = module.target_config(); let pointer_type = target_config.pointer_type(); + assert_eq!(pointer_ty(tcx), pointer_type); let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance, fn_abi); - let func_debug_cx = if let Some(debug_context) = &mut cx.debug_context { + let func_debug_cx = if let Some(debug_context) = debug_context.as_deref_mut() { Some(debug_context.define_function(tcx, type_dbg, instance, fn_abi, &symbol_name, mir.span)) } else { None }; + let exception_slot = bcx.declare_var(pointer_type); + let mut fx = FunctionCx { - cx, module, + debug_context, tcx, target_config, pointer_type, constants_cx: ConstantCx::new(), func_debug_cx, + cgu_name, instance, symbol_name, mir, @@ -100,9 +110,11 @@ pub(crate) fn codegen_fn<'tcx>( block_map, local_map: IndexVec::with_capacity(mir.local_decls.len()), caller_location: None, // set by `codegen_fn_prelude` + exception_slot, clif_comments, - next_ssa_var: 0, + inline_asm: String::new(), + inline_asm_index: 0, }; tcx.prof.generic_activity("codegen clif ir").run(|| codegen_fn_body(&mut fx, start_block)); @@ -113,10 +125,11 @@ pub(crate) fn codegen_fn<'tcx>( let symbol_name = fx.symbol_name; let clif_comments = fx.clif_comments; let func_debug_cx = fx.func_debug_cx; + let inline_asm = fx.inline_asm; fx.constants_cx.finalize(fx.tcx, &mut *fx.module); - if cx.should_write_ir { + if crate::pretty_clif::should_write_ir(tcx.sess) { crate::pretty_clif::write_clif_file( tcx.output_filenames(()), &symbol_name, @@ -130,20 +143,24 @@ pub(crate) fn codegen_fn<'tcx>( // Verify function verify_func(tcx, &clif_comments, &func); - CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx } + CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx, inline_asm } } pub(crate) fn compile_fn( - cx: &mut crate::CodegenCx, profiler: &SelfProfilerRef, + output_filenames: &OutputFilenames, + should_write_ir: bool, cached_context: &mut Context, module: &mut dyn Module, + debug_context: Option<&mut DebugContext>, + global_asm: &mut String, codegened_func: CodegenedFunction, ) { let _timer = profiler.generic_activity_with_arg("compile function", &*codegened_func.symbol_name); let clif_comments = codegened_func.clif_comments; + global_asm.push_str(&codegened_func.inline_asm); // Store function in context let context = cached_context; @@ -180,7 +197,7 @@ pub(crate) fn compile_fn( // Define function profiler.generic_activity("define function").run(|| { - context.want_disasm = cx.should_write_ir; + context.want_disasm = should_write_ir; match module.define_function(codegened_func.func_id, context) { Ok(()) => {} Err(ModuleError::Compilation(CodegenError::ImplLimitExceeded)) => { @@ -210,10 +227,10 @@ pub(crate) fn compile_fn( } }); - if cx.should_write_ir { + if should_write_ir { // Write optimized function to file for debugging crate::pretty_clif::write_clif_file( - &cx.output_filenames, + output_filenames, &codegened_func.symbol_name, "opt", module.isa(), @@ -223,7 +240,7 @@ pub(crate) fn compile_fn( if let Some(disasm) = &context.compiled_code().unwrap().vcode { crate::pretty_clif::write_ir_file( - &cx.output_filenames, + output_filenames, &format!("{}.vcode", codegened_func.symbol_name), |file| file.write_all(disasm.as_bytes()), ) @@ -231,7 +248,6 @@ pub(crate) fn compile_fn( } // Define debuginfo for function - let debug_context = &mut cx.debug_context; profiler.generic_activity("generate debug info").run(|| { if let Some(debug_context) = debug_context { codegened_func.func_debug_cx.unwrap().finalize( @@ -250,12 +266,12 @@ fn verify_func(tcx: TyCtxt<'_>, writer: &crate::pretty_clif::CommentWriter, func tcx.prof.generic_activity("verify clif ir").run(|| { let flags = cranelift_codegen::settings::Flags::new(cranelift_codegen::settings::builder()); - match cranelift_codegen::verify_function(&func, &flags) { + match cranelift_codegen::verify_function(func, &flags) { Ok(_) => {} Err(err) => { tcx.dcx().err(format!("{:?}", err)); let pretty_error = cranelift_codegen::print_errors::pretty_verifier_error( - &func, + func, Some(Box::new(writer)), err, ); @@ -295,11 +311,11 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { } if bb_data.is_cleanup { - // Unwinding after panicking is not supported - continue; + if cfg!(not(feature = "unwinding")) { + continue; + } - // FIXME Once unwinding is supported and Cranelift supports marking blocks as cold, do - // so for cleanup blocks. + fx.bcx.set_cold_block(block); } fx.bcx.ins().nop(); @@ -369,7 +385,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { fx.bcx.ins().nop(); match &**msg { - AssertKind::BoundsCheck { ref len, ref index } => { + AssertKind::BoundsCheck { len, index } => { let len = codegen_operand(fx, len).load_scalar(fx); let index = codegen_operand(fx, index).load_scalar(fx); let location = fx.get_caller_location(source_info).load_scalar(fx); @@ -382,7 +398,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { source_info.span, ); } - AssertKind::MisalignedPointerDereference { ref required, ref found } => { + AssertKind::MisalignedPointerDereference { required, found } => { let required = codegen_operand(fx, required).load_scalar(fx); let found = codegen_operand(fx, found).load_scalar(fx); let location = fx.get_caller_location(source_info).load_scalar(fx); @@ -538,14 +554,22 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { template, operands, *options, - targets.get(0).copied(), + targets.first().copied(), ); } TerminatorKind::UnwindTerminate(reason) => { codegen_unwind_terminate(fx, source_info.span, *reason); } TerminatorKind::UnwindResume => { - // FIXME implement unwinding + if cfg!(feature = "unwinding") { + let exception_ptr = fx.bcx.use_var(fx.exception_slot); + fx.lib_call( + "_Unwind_Resume", + vec![AbiParam::new(fx.pointer_type)], + vec![], + &[exception_ptr], + ); + } fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap()); } TerminatorKind::Unreachable => { @@ -929,7 +953,7 @@ fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { | StatementKind::AscribeUserType(..) => {} StatementKind::Coverage { .. } => unreachable!(), - StatementKind::Intrinsic(ref intrinsic) => match &**intrinsic { + StatementKind::Intrinsic(intrinsic) => match &**intrinsic { // We ignore `assume` intrinsics, they are only useful for optimizations NonDivergingIntrinsic::Assume(_) => {} NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { @@ -1060,7 +1084,7 @@ pub(crate) fn codegen_panic_nounwind<'tcx>( msg_str: &str, span: Span, ) { - let msg_ptr = fx.anonymous_str(msg_str); + let msg_ptr = crate::constant::pointer_for_anonymous_str(fx, msg_str); let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); let args = [msg_ptr, msg_len]; @@ -1085,7 +1109,7 @@ fn codegen_panic_inner<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, lang_item: rustc_hir::LangItem, args: &[Value], - _unwind: UnwindAction, + unwind: UnwindAction, span: Span, ) { fx.bcx.set_cold_block(fx.bcx.current_block().unwrap()); @@ -1101,14 +1125,23 @@ fn codegen_panic_inner<'tcx>( let symbol_name = fx.tcx.symbol_name(instance).name; - // FIXME implement cleanup on exceptions + let sig = Signature { + params: args.iter().map(|&arg| AbiParam::new(fx.bcx.func.dfg.value_type(arg))).collect(), + returns: vec![], + call_conv: fx.target_config.default_call_conv, + }; + let func_id = fx.module.declare_function(symbol_name, Linkage::Import, &sig).unwrap(); + let func_ref = fx.module.declare_func_in_func(func_id, fx.bcx.func); + if fx.clif_comments.enabled() { + fx.add_comment(func_ref, format!("{:?}", symbol_name)); + } - fx.lib_call( - symbol_name, - args.iter().map(|&arg| AbiParam::new(fx.bcx.func.dfg.value_type(arg))).collect(), - vec![], - args, - ); + let nop_inst = fx.bcx.ins().nop(); + if fx.clif_comments.enabled() { + fx.add_comment(nop_inst, format!("panic {}", symbol_name)); + } + + codegen_call_with_unwind_action(fx, span, CallTarget::Direct(func_ref), unwind, args, None); fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap()); } diff --git a/src/codegen_f16_f128.rs b/src/codegen_f16_f128.rs index c0f6d9d853db..91f7220667ff 100644 --- a/src/codegen_f16_f128.rs +++ b/src/codegen_f16_f128.rs @@ -1,5 +1,6 @@ use rustc_target::spec::Arch; +use crate::compiler_builtins::CMP_RESULT_TY; use crate::prelude::*; pub(crate) fn f16_to_f32(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { @@ -74,15 +75,11 @@ pub(crate) fn fcmp(fx: &mut FunctionCx<'_, '_, '_>, cc: FloatCC, lhs: Value, rhs let res = fx.lib_call( name, vec![AbiParam::new(types::F128), AbiParam::new(types::F128)], - // FIXME(rust-lang/compiler-builtins#919): This should be `I64` on non-AArch64 - // architectures, but switching it before compiler-builtins is fixed causes test - // failures. - vec![AbiParam::new(types::I32)], + vec![AbiParam::new(CMP_RESULT_TY)], &[lhs, rhs], )[0]; - let zero = fx.bcx.ins().iconst(types::I32, 0); - let res = fx.bcx.ins().icmp(int_cc, res, zero); - res + let zero = fx.bcx.ins().iconst(CMP_RESULT_TY, 0); + fx.bcx.ins().icmp(int_cc, res, zero) } _ => unreachable!("{ty:?}"), } diff --git a/src/common.rs b/src/common.rs index de3d2f31af10..38676eaac3d5 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,11 +1,12 @@ use cranelift_codegen::isa::TargetFrontendConfig; -use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; use rustc_abi::{Float, Integer, Primitive}; use rustc_index::IndexVec; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, }; +use rustc_span::Symbol; use rustc_span::source_map::Spanned; use rustc_target::callconv::FnAbi; use rustc_target::spec::{Arch, HasTargetSpec, Target}; @@ -256,7 +257,7 @@ pub(crate) fn create_wrapper_function( .map(|param| func.dfg.append_block_param(block, param.value_type)) .collect::>(); - let callee_func_ref = module.declare_func_in_func(callee_func_id, &mut bcx.func); + let callee_func_ref = module.declare_func_in_func(callee_func_id, bcx.func); let call_inst = bcx.ins().call(callee_func_ref, &args); let results = bcx.inst_results(call_inst).to_vec(); // Clone to prevent borrow error @@ -268,14 +269,15 @@ pub(crate) fn create_wrapper_function( } pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { - pub(crate) cx: &'clif mut crate::CodegenCx, pub(crate) module: &'m mut dyn Module, + pub(crate) debug_context: Option<&'clif mut DebugContext>, pub(crate) tcx: TyCtxt<'tcx>, pub(crate) target_config: TargetFrontendConfig, // Cached from module pub(crate) pointer_type: Type, // Cached from module pub(crate) constants_cx: ConstantCx, pub(crate) func_debug_cx: Option, + pub(crate) cgu_name: Symbol, pub(crate) instance: Instance<'tcx>, pub(crate) symbol_name: String, pub(crate) mir: &'tcx Body<'tcx>, @@ -288,10 +290,13 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { /// When `#[track_caller]` is used, the implicit caller location is stored in this variable. pub(crate) caller_location: Option>, + /// During cleanup the exception pointer will be stored in this variable. + pub(crate) exception_slot: Variable, + pub(crate) clif_comments: crate::pretty_clif::CommentWriter, - /// This should only be accessed by `CPlace::new_var`. - pub(crate) next_ssa_var: u32, + pub(crate) inline_asm: String, + pub(crate) inline_asm_index: u32, } impl<'tcx> LayoutOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> { @@ -369,7 +374,7 @@ pub(crate) fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> { pub(crate) fn create_stack_slot(&mut self, size: u32, align: u32) -> Pointer { assert!( - size % align == 0, + size.is_multiple_of(align), "size must be a multiple of alignment (size={size}, align={align})" ); @@ -379,7 +384,7 @@ pub(crate) fn create_stack_slot(&mut self, size: u32, align: u32) -> Pointer { kind: StackSlotKind::ExplicitSlot, // FIXME Don't force the size to a multiple of bytes once Cranelift gets // a way to specify stack slot alignment. - size: (size + abi_align - 1) / abi_align * abi_align, + size: size.div_ceil(abi_align) * abi_align, align_shift: 4, }); Pointer::stack_slot(stack_slot) @@ -401,7 +406,7 @@ pub(crate) fn create_stack_slot(&mut self, size: u32, align: u32) -> Pointer { } pub(crate) fn set_debug_loc(&mut self, source_info: mir::SourceInfo) { - if let Some(debug_context) = &mut self.cx.debug_context { + if let Some(debug_context) = &mut self.debug_context { let (file_id, line, column) = debug_context.get_span_loc(self.tcx, self.mir.span, source_info.span); @@ -417,21 +422,6 @@ pub(crate) fn get_caller_location(&mut self, source_info: mir::SourceInfo) -> CV crate::constant::codegen_const_value(self, const_loc, self.tcx.caller_location_ty()) }) } - - pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value { - let mut data = DataDescription::new(); - data.define(msg.as_bytes().to_vec().into_boxed_slice()); - let msg_id = self.module.declare_anonymous_data(false, false).unwrap(); - - // Ignore DuplicateDefinition error, as the data will be the same - let _ = self.module.define_data(msg_id, &data); - - let local_msg_id = self.module.declare_data_in_func(msg_id, self.bcx.func); - if self.clif_comments.enabled() { - self.add_comment(local_msg_id, msg); - } - self.bcx.ins().global_value(self.pointer_type, local_msg_id) - } } pub(crate) struct FullyMonomorphizedLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>); diff --git a/src/compiler_builtins.rs b/src/compiler_builtins.rs index 6eea19211fa1..ca9157daae58 100644 --- a/src/compiler_builtins.rs +++ b/src/compiler_builtins.rs @@ -3,11 +3,34 @@ #[cfg(feature = "jit")] use std::ffi::c_void; +use cranelift_codegen::ir::{Type, types}; + // FIXME replace with core::ffi::c_size_t once stabilized #[allow(non_camel_case_types)] #[cfg(feature = "jit")] type size_t = usize; +// Needs to stay in sync with compiler-builtins + +// Aarch64 uses `int` rather than a pointer-sized value. +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] +#[cfg(feature = "jit")] +type CmpResult = i32; +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] +pub(crate) const CMP_RESULT_TY: Type = types::I32; + +// In compiler-rt, LLP64 ABIs use `long long` and everything else uses `long`. In effect, +// this means the return value is always pointer-sized. +#[cfg(not(any(target_arch = "aarch64", target_arch = "arm64ec")))] +#[cfg(feature = "jit")] +type CmpResult = isize; +#[cfg(not(any(target_arch = "aarch64", target_arch = "arm64ec")))] +#[cfg(target_pointer_width = "32")] +pub(crate) const CMP_RESULT_TY: Type = types::I32; +#[cfg(not(any(target_arch = "aarch64", target_arch = "arm64ec")))] +#[cfg(target_pointer_width = "64")] +pub(crate) const CMP_RESULT_TY: Type = types::I64; + macro_rules! builtin_functions { ( $register:ident; @@ -18,7 +41,7 @@ macro_rules! builtin_functions { ) => { #[cfg(feature = "jit")] #[allow(improper_ctypes)] - extern "C" { + unsafe extern "C" { $( $(#[$attr])? fn $name($($arg_name: $arg_ty),*) -> $ret_ty; @@ -85,15 +108,18 @@ pub(crate) fn $register(builder: &mut cranelift_jit::JITBuilder) { fn __divtf3(a: f128, b: f128) -> f128; fn fmodf(a: f32, b: f32) -> f32; fn fmod(a: f64, b: f64) -> f64; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn fmodf128(a: f128, b: f128) -> f128; // float comparison - fn __eqtf2(a: f128, b: f128) -> i32; - fn __netf2(a: f128, b: f128) -> i32; - fn __lttf2(a: f128, b: f128) -> i32; - fn __letf2(a: f128, b: f128) -> i32; - fn __gttf2(a: f128, b: f128) -> i32; - fn __getf2(a: f128, b: f128) -> i32; + fn __eqtf2(a: f128, b: f128) -> CmpResult; + fn __netf2(a: f128, b: f128) -> CmpResult; + fn __lttf2(a: f128, b: f128) -> CmpResult; + fn __letf2(a: f128, b: f128) -> CmpResult; + fn __gttf2(a: f128, b: f128) -> CmpResult; + fn __getf2(a: f128, b: f128) -> CmpResult; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn fminimumf128(a: f128, b: f128) -> f128; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn fmaximumf128(a: f128, b: f128) -> f128; // Cranelift float libcalls fn fmaf(a: f32, b: f32, c: f32) -> f32; @@ -127,16 +153,27 @@ pub(crate) fn $register(builder: &mut cranelift_jit::JITBuilder) { fn sin(f: f64) -> f64; fn cosf(f: f32) -> f32; fn cos(f: f64) -> f64; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn fmaf128(a: f128, b: f128, c: f128) -> f128; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn floorf16(f: f16) -> f16; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn floorf128(f: f128) -> f128; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn ceilf16(f: f16) -> f16; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn ceilf128(f: f128) -> f128; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn truncf16(f: f16) -> f16; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn truncf128(f: f128) -> f128; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn rintf16(f: f16) -> f16; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn rintf128(f: f128) -> f128; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn sqrtf16(f: f16) -> f16; + #[cfg(not(all(target_os = "windows", target_env = "gnu")))] fn sqrtf128(f: f128) -> f128; // FIXME(f16_f128): Add other float intrinsics as compiler-builtins gains support (meaning they // are available on all targets). diff --git a/src/config.rs b/src/config.rs index d328b33a704f..31bc0374460f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,5 @@ /// Configuration of cg_clif as passed in through `-Cllvm-args` and various env vars. -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct BackendConfig { /// Should the crate be AOT compiled or JIT executed. /// diff --git a/src/constant.rs b/src/constant.rs index 3243e12e6999..2b65b8290681 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -3,6 +3,7 @@ use std::cmp::Ordering; use cranelift_module::*; +use rustc_const_eval::interpret::CTFE_ALLOC_SALT; use rustc_data_structures::fx::FxHashSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{ @@ -64,7 +65,7 @@ pub(crate) fn codegen_tls_ref<'tcx>( // For a declaration the stated mutability doesn't matter. false, ); - let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + let local_data_id = fx.module.declare_data_in_func(data_id, fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(local_data_id, format!("tls {:?}", def_id)); } @@ -110,7 +111,7 @@ pub(crate) fn codegen_const_value<'tcx>( ConstValue::Scalar(x) => match x { Scalar::Int(int) => { if fx.clif_type(layout.ty).is_some() { - return CValue::const_val(fx, layout, int); + CValue::const_val(fx, layout, int) } else { let raw_val = int.size().truncate(int.to_bits(int.size())); let val = match int.size().bytes() { @@ -140,11 +141,7 @@ pub(crate) fn codegen_const_value<'tcx>( let base_addr = match fx.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { if alloc.inner().len() == 0 { - let val = alloc.inner().align.bytes().wrapping_add(offset.bytes()); - fx.bcx.ins().iconst( - fx.pointer_type, - fx.tcx.truncate_to_target_usize(val) as i64, - ) + fx.bcx.ins().iconst(fx.pointer_type, alloc.inner().align.bytes() as i64) } else { let data_id = data_id_for_alloc_id( &mut fx.constants_cx, @@ -153,17 +150,16 @@ pub(crate) fn codegen_const_value<'tcx>( alloc.inner().mutability, ); let local_data_id = - fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + fx.module.declare_data_in_func(data_id, fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(local_data_id, format!("{:?}", alloc_id)); } - fx.bcx.ins().global_value(fx.pointer_type, local_data_id) + fx.bcx.ins().symbol_value(fx.pointer_type, local_data_id) } } GlobalAlloc::Function { instance, .. } => { let func_id = crate::abi::import_function(fx.tcx, fx.module, instance); - let local_func_id = - fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); + let local_func_id = fx.module.declare_func_in_func(func_id, fx.bcx.func); fx.bcx.ins().func_addr(fx.pointer_type, local_func_id) } GlobalAlloc::VTable(ty, dyn_ty) => { @@ -176,9 +172,8 @@ pub(crate) fn codegen_const_value<'tcx>( fx.tcx.instantiate_bound_regions_with_erased(principal) }), ); - let local_data_id = - fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); - fx.bcx.ins().global_value(fx.pointer_type, local_data_id) + let local_data_id = fx.module.declare_data_in_func(data_id, fx.bcx.func); + fx.bcx.ins().symbol_value(fx.pointer_type, local_data_id) } GlobalAlloc::TypeId { .. } => { return CValue::const_val( @@ -194,16 +189,26 @@ pub(crate) fn codegen_const_value<'tcx>( // For a declaration the stated mutability doesn't matter. false, ); - let local_data_id = - fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + let local_data_id = fx.module.declare_data_in_func(data_id, fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(local_data_id, format!("{:?}", def_id)); } - fx.bcx.ins().global_value(fx.pointer_type, local_data_id) + if fx + .tcx + .codegen_fn_attrs(def_id) + .flags + .contains(CodegenFnAttrFlags::THREAD_LOCAL) + { + fx.bcx.ins().tls_value(fx.pointer_type, local_data_id) + } else { + fx.bcx.ins().symbol_value(fx.pointer_type, local_data_id) + } } }; let val = if offset.bytes() != 0 { - fx.bcx.ins().iadd_imm(base_addr, i64::try_from(offset.bytes()).unwrap()) + fx.bcx + .ins() + .iadd_imm(base_addr, fx.tcx.truncate_to_target_usize(offset.bytes()) as i64) } else { base_addr }; @@ -211,32 +216,28 @@ pub(crate) fn codegen_const_value<'tcx>( } }, ConstValue::Indirect { alloc_id, offset } => CValue::by_ref( - pointer_for_allocation(fx, alloc_id) + Pointer::new(pointer_for_allocation(fx, alloc_id)) .offset_i64(fx, i64::try_from(offset.bytes()).unwrap()), layout, ), ConstValue::Slice { alloc_id, meta } => { - let ptr = pointer_for_allocation(fx, alloc_id).get_addr(fx); + let ptr = pointer_for_allocation(fx, alloc_id); let len = fx.bcx.ins().iconst(fx.pointer_type, meta as i64); CValue::by_val_pair(ptr, len, layout) } } } -fn pointer_for_allocation<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - alloc_id: AllocId, -) -> crate::pointer::Pointer { +fn pointer_for_allocation<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, alloc_id: AllocId) -> Value { let alloc = fx.tcx.global_alloc(alloc_id).unwrap_memory(); let data_id = data_id_for_alloc_id(&mut fx.constants_cx, fx.module, alloc_id, alloc.inner().mutability); - let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + let local_data_id = fx.module.declare_data_in_func(data_id, fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(local_data_id, format!("{:?}", alloc_id)); } - let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id); - crate::pointer::Pointer::new(global_ptr) + fx.bcx.ins().symbol_value(fx.pointer_type, local_data_id) } fn data_id_for_alloc_id( @@ -262,6 +263,11 @@ pub(crate) fn data_id_for_vtable<'tcx>( data_id_for_alloc_id(cx, module, alloc_id, Mutability::Not) } +pub(crate) fn pointer_for_anonymous_str(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) -> Value { + let alloc_id = fx.tcx.allocate_bytes_dedup(msg.as_bytes(), CTFE_ALLOC_SALT); + pointer_for_allocation(fx, alloc_id) +} + fn data_id_for_static( tcx: TyCtxt<'_>, module: &mut dyn Module, @@ -345,7 +351,7 @@ fn data_id_for_static( Linkage::Import }; - let data_id = match module.declare_data( + match module.declare_data( symbol_name, linkage, definition_writable, @@ -356,9 +362,7 @@ fn data_id_for_static( "attempt to declare `{symbol_name}` as static, but it was already declared as function" )), Err(err) => Err::<_, _>(err).unwrap(), - }; - - data_id + } } fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut ConstantCx) { @@ -368,6 +372,8 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant continue; } + let mut data = DataDescription::new(); + let (data_id, alloc, section_name) = match todo_item { TodoItem::Alloc(alloc_id) => { let alloc = match tcx.global_alloc(alloc_id) { @@ -386,7 +392,10 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant (data_id, alloc, None) } TodoItem::Static(def_id) => { - let section_name = tcx.codegen_fn_attrs(def_id).link_section; + let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); + let section_name = codegen_fn_attrs.link_section; + + data.set_used(codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); let alloc = tcx.eval_static_initializer(def_id).unwrap(); @@ -401,7 +410,6 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant } }; - let mut data = DataDescription::new(); let alloc = alloc.inner(); data.set_align(alloc.align.bytes()); @@ -594,7 +602,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( { return None; } - StatementKind::Intrinsic(ref intrinsic) => match **intrinsic { + StatementKind::Intrinsic(intrinsic) => match **intrinsic { NonDivergingIntrinsic::CopyNonOverlapping(..) => return None, NonDivergingIntrinsic::Assume(..) => {} }, diff --git a/src/debuginfo/emit.rs b/src/debuginfo/emit.rs index 0f4696b9337e..8016c5a3005a 100644 --- a/src/debuginfo/emit.rs +++ b/src/debuginfo/emit.rs @@ -96,7 +96,7 @@ pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) if jit_module.declarations().get_function_decl(func_id).name.as_deref() == Some("rust_eh_personality") { - extern "C" { + unsafe extern "C" { fn rust_eh_personality() -> !; } rust_eh_personality as *const u8 @@ -222,12 +222,12 @@ fn write_eh_pointer(&mut self, address: Address, eh_pe: gimli::DwEhPe, size: u8) gimli::DW_EH_PE_absptr => { self.relocs.push(DebugReloc { offset: self.len() as u32, - size: size.into(), + size, name: DebugRelocName::Symbol(symbol), addend, kind: object::RelocationKind::Absolute, }); - self.write_udata(0, size.into()) + self.write_udata(0, size) } _ => Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)), }, diff --git a/src/debuginfo/gcc_except_table.rs b/src/debuginfo/gcc_except_table.rs new file mode 100644 index 000000000000..ff1c6aacd2f9 --- /dev/null +++ b/src/debuginfo/gcc_except_table.rs @@ -0,0 +1,271 @@ +use gimli::write::{Address, Writer}; +use gimli::{DW_EH_PE_omit, DW_EH_PE_uleb128, Encoding, LittleEndian}; + +pub(super) struct GccExceptTable { + pub call_sites: CallSiteTable, + pub actions: ActionTable, + pub type_info: TypeInfoTable, +} + +impl GccExceptTable { + pub(super) fn write( + &self, + w: &mut W, + encoding: Encoding, + ) -> gimli::write::Result<()> { + // lpStartEncoding + w.write_u8(DW_EH_PE_omit.0)?; + // lpStart (omitted) + let type_info_padding = if self.type_info.type_info.is_empty() { + // ttypeEncoding + w.write_u8(DW_EH_PE_omit.0)?; + None + } else { + // ttypeEncoding + w.write_u8(self.type_info.ttype_encoding.0)?; + + // classInfoOffset + let class_info_offset_field_offset = w.len() as u64; + + // Note: The offset in classInfoOffset is relative to position right after classInfoOffset + // itself. + let class_info_offset_no_padding = self.call_sites.encoded_size() + + self.actions.encoded_size() + + self.type_info.encoded_size(encoding); + + let type_info_is_aligned = |type_info_padding: u64| { + (class_info_offset_field_offset + + gimli::leb128::write::uleb128_size( + class_info_offset_no_padding + type_info_padding, + ) as u64 + + self.call_sites.encoded_size() + + self.actions.encoded_size() + + type_info_padding) + .is_multiple_of(4) + }; + + let mut type_info_padding = 0; + while !type_info_is_aligned(type_info_padding) { + type_info_padding += 1; + } + + w.write_uleb128(class_info_offset_no_padding + type_info_padding)?; + + Some(type_info_padding) + }; + + // call site table + self.call_sites.write(w)?; + + // action table + self.actions.write(w)?; + + // align to 4 bytes + if let Some(type_info_padding) = type_info_padding { + for _ in 0..type_info_padding { + w.write_u8(0)?; + } + // In this case we calculated the expected padding amount and used it to write the + // classInfoOffset field. Assert that the expected value matched the actual value to catch + // any inconsistency. + assert!(w.len().is_multiple_of(4), "type_info must be aligned to 4 bytes"); + } else { + while !w.len().is_multiple_of(4) { + w.write_u8(0)?; + } + } + + // type_info + self.type_info.write(w, encoding)?; + + // exception specs (unused for rust) + + // align to 4 bytes + while !w.len().is_multiple_of(4) { + w.write_u8(0)?; + } + + Ok(()) + } +} + +pub(super) struct CallSiteTable(pub Vec); + +impl CallSiteTable { + fn encoded_size(&self) -> u64 { + let mut len = LenWriter(0); + self.write(&mut len).unwrap(); + len.0 as u64 + } + + fn write(&self, w: &mut W) -> gimli::write::Result<()> { + let callsite_table_length = self.0.iter().map(|call_site| call_site.encoded_size()).sum(); + + // callsiteEncoding + w.write_u8(DW_EH_PE_uleb128.0)?; + // callsiteTableLength + w.write_uleb128(callsite_table_length)?; + + for call_site in &self.0 { + call_site.write(w)?; + } + + Ok(()) + } +} + +pub(super) struct CallSite { + pub start: u64, + pub length: u64, + pub landing_pad: u64, + pub action_entry: Option, +} + +impl CallSite { + fn encoded_size(&self) -> u64 { + let mut len = LenWriter(0); + self.write(&mut len).unwrap(); + len.0 as u64 + } + + fn write(&self, w: &mut W) -> gimli::write::Result<()> { + w.write_uleb128(self.start)?; + w.write_uleb128(self.length)?; + w.write_uleb128(self.landing_pad)?; + w.write_uleb128(match self.action_entry { + Some(action_offset) => action_offset.0 + 1, + None => 0, + })?; + Ok(()) + } +} + +pub(super) struct ActionTable { + actions: Vec, + encoded_length: u64, +} + +impl ActionTable { + pub(super) fn new() -> ActionTable { + ActionTable { actions: vec![], encoded_length: 0 } + } + + pub(super) fn add(&mut self, action: Action) -> ActionOffset { + let id = ActionOffset(self.encoded_length); + self.encoded_length += action.encoded_size(self.encoded_length); + self.actions.push(action); + id + } + + fn encoded_size(&self) -> u64 { + let mut len = LenWriter(0); + self.write(&mut len).unwrap(); + len.0 as u64 + } + + fn write(&self, w: &mut W) -> gimli::write::Result<()> { + let action_table_start = w.len() as u64; + for action in &self.actions { + action.write(w, w.len() as u64 - action_table_start)?; + } + + Ok(()) + } +} + +#[derive(Copy, Clone)] +pub(super) struct ActionOffset(u64); + +pub(super) struct Action { + pub(super) kind: ActionKind, + pub(super) next_action: Option, +} + +impl Action { + fn encoded_size(&self, action_table_offset: u64) -> u64 { + let mut len = LenWriter(0); + self.write(&mut len, action_table_offset).unwrap(); + len.0 as u64 + } + + fn write(&self, w: &mut W, action_table_offset: u64) -> gimli::write::Result<()> { + // ttypeIndex + let ttype_index = match self.kind { + ActionKind::Catch(type_info_id) => type_info_id.0 as i64 + 1, + }; + w.write_sleb128(ttype_index)?; + // actionOffset + let action_offset_field_offset = + action_table_offset + gimli::leb128::write::sleb128_size(ttype_index) as u64; + w.write_sleb128(match self.next_action { + Some(next_action_offset) => { + next_action_offset.0 as i64 - action_offset_field_offset as i64 + } + None => 0, + })?; + Ok(()) + } +} + +#[derive(Copy, Clone)] +pub(super) enum ActionKind { + Catch(TypeInfoId), +} + +pub(super) struct TypeInfoTable { + ttype_encoding: gimli::DwEhPe, + type_info: Vec
, +} + +impl TypeInfoTable { + pub(super) fn new(ttype_encoding: gimli::DwEhPe) -> TypeInfoTable { + TypeInfoTable { ttype_encoding, type_info: vec![] } + } + + pub(super) fn add(&mut self, type_info: Address) -> TypeInfoId { + let id = TypeInfoId(self.type_info.len() as u64); + self.type_info.push(type_info); + id + } + + fn encoded_size(&self, encoding: Encoding) -> u64 { + let mut len = LenWriter(0); + self.write(&mut len, encoding).unwrap(); + len.0 as u64 + } + + fn write(&self, w: &mut W, encoding: Encoding) -> gimli::write::Result<()> { + for &type_info in self.type_info.iter().rev() { + w.write_eh_pointer(type_info, self.ttype_encoding, encoding.address_size)?; + } + + Ok(()) + } +} + +#[derive(Copy, Clone)] +pub(super) struct TypeInfoId(u64); + +struct LenWriter(usize); + +impl Writer for LenWriter { + type Endian = LittleEndian; + + fn endian(&self) -> LittleEndian { + LittleEndian + } + + fn len(&self) -> usize { + self.0 + } + + fn write(&mut self, bytes: &[u8]) -> gimli::write::Result<()> { + self.0 += bytes.len(); + Ok(()) + } + + fn write_at(&mut self, offset: usize, bytes: &[u8]) -> gimli::write::Result<()> { + assert!(offset + bytes.len() < self.0); + Ok(()) + } +} diff --git a/src/debuginfo/line_info.rs b/src/debuginfo/line_info.rs index fa7b39c836f6..6fe22f5c6dd9 100644 --- a/src/debuginfo/line_info.rs +++ b/src/debuginfo/line_info.rs @@ -6,9 +6,7 @@ use cranelift_codegen::MachSrcLoc; use cranelift_codegen::binemit::CodeOffset; use gimli::write::{AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable}; -use rustc_span::{ - FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm, hygiene, -}; +use rustc_span::{FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHashAlgorithm, hygiene}; use crate::debuginfo::FunctionDebugContext; use crate::debuginfo::emit::address_for_func; @@ -44,21 +42,27 @@ fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] { } } -const MD5_LEN: usize = 16; +fn make_file_info(source_file: &SourceFile, embed_source: bool) -> Option { + let has_md5 = source_file.src_hash.kind == SourceFileHashAlgorithm::Md5; + let has_source = embed_source && source_file.src.is_some(); -fn make_file_info(hash: SourceFileHash) -> Option { - if hash.kind == SourceFileHashAlgorithm::Md5 { - let mut buf = [0u8; MD5_LEN]; - buf.copy_from_slice(hash.hash_bytes()); - Some(FileInfo { - timestamp: 0, - size: 0, - md5: buf, - source: None, // FIXME implement -Zembed-source - }) - } else { - None + if !has_md5 && !has_source { + return None; } + + let mut info = FileInfo::default(); + + if has_md5 { + info.md5.copy_from_slice(source_file.src_hash.hash_bytes()); + } + + if embed_source { + if let Some(src) = &source_file.src { + info.source = Some(LineString::String(src.as_bytes().to_vec())); + } + } + + Some(info) } impl DebugContext { @@ -105,15 +109,19 @@ pub(crate) fn add_source_file(&mut self, source_file: &SourceFile) -> FileId { let file_name = LineString::new(file_name, line_program.encoding(), line_strings); - let info = make_file_info(source_file.src_hash); + let info = make_file_info(source_file, self.embed_source); - line_program.file_has_md5 &= info.is_some(); + let has_md5 = source_file.src_hash.kind == SourceFileHashAlgorithm::Md5; + line_program.file_has_md5 &= has_md5; line_program.add_file(file_name, dir_id, info) } filename => { - let dir_id = line_program.default_directory(); + // For anonymous sources, create an empty directory instead of using the default + let empty_dir = LineString::new(b"", line_program.encoding(), line_strings); + let dir_id = line_program.add_directory(empty_dir); + let dummy_file_name = LineString::new( - filename.display(self.filename_display_preference).to_string().into_bytes(), + filename.prefer_remapped_unconditionally().to_string().into_bytes(), line_program.encoding(), line_strings, ); diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 4c438742f3d2..494002f525c8 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -1,6 +1,7 @@ //! Handling of everything related to debuginfo. mod emit; +mod gcc_except_table; mod line_info; mod object; mod types; @@ -19,12 +20,13 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefIdMap; use rustc_session::Session; +use rustc_session::config::DebugInfo; use rustc_span::{FileNameDisplayPreference, SourceFileHash, StableSourceFileId}; use rustc_target::callconv::FnAbi; pub(crate) use self::emit::{DebugReloc, DebugRelocName}; pub(crate) use self::types::TypeDebugContext; -pub(crate) use self::unwind::UnwindContext; +pub(crate) use self::unwind::{EXCEPTION_HANDLER_CATCH, EXCEPTION_HANDLER_CLEANUP, UnwindContext}; use crate::debuginfo::emit::{address_for_data, address_for_func}; use crate::prelude::*; @@ -43,6 +45,7 @@ pub(crate) struct DebugContext { array_size_type: UnitEntryId, filename_display_preference: FileNameDisplayPreference, + embed_source: bool, } pub(crate) struct FunctionDebugContext { @@ -52,22 +55,37 @@ pub(crate) struct FunctionDebugContext { } impl DebugContext { - pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, cgu_name: &str) -> Self { + pub(crate) fn new( + tcx: TyCtxt<'_>, + isa: &dyn TargetIsa, + force_disable_debuginfo: bool, + cgu_name: &str, + ) -> Option { + if tcx.sess.opts.debuginfo == DebugInfo::None + || force_disable_debuginfo + || tcx.sess.target.options.is_like_windows + { + return None; + } + + let mut requested_dwarf_version = tcx.sess.dwarf_version(); + if tcx.sess.target.is_like_darwin && requested_dwarf_version > 4 { + // Apple’s shipped debuggers still expect DWARF <= 4 by default. + // Stay on v4 unless the user explicitly opts into a feature that + // only works with v5 (e.g. -Zembed-source). + if !tcx.sess.opts.unstable_opts.embed_source { + requested_dwarf_version = 4; + } + } + let encoding = Encoding { format: Format::Dwarf32, - // FIXME this should be configurable - // macOS doesn't seem to support DWARF > 3 - // 5 version is required for md5 file hash - version: if tcx.sess.target.is_like_darwin { - 3 - } else { - // FIXME change to version 5 once the gdb and lldb shipping with the latest debian - // support it. - 4 - }, + version: requested_dwarf_version as u16, address_size: isa.frontend_config().pointer_bytes(), }; + let embed_source = tcx.sess.opts.unstable_opts.embed_source && encoding.version >= 5; + let endian = match isa.endianness() { Endianness::Little => RunTimeEndian::Little, Endianness::Big => RunTimeEndian::Big, @@ -106,10 +124,14 @@ pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, cgu_name: &str) -> Self encoding, LineEncoding::default(), LineString::new(comp_dir.as_bytes(), encoding, &mut dwarf.line_strings), + None, LineString::new(name.as_bytes(), encoding, &mut dwarf.line_strings), file_info, ); line_program.file_has_md5 = file_has_md5; + if embed_source { + line_program.file_has_source = true; + } dwarf.unit.line_program = line_program; @@ -145,7 +167,7 @@ pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, cgu_name: &str) -> Self AttributeValue::Udata(isa.frontend_config().pointer_bytes().into()), ); - DebugContext { + Some(DebugContext { endian, dwarf, unit_range_list: RangeList(Vec::new()), @@ -154,7 +176,8 @@ pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, cgu_name: &str) -> Self namespace_map: DefIdMap::default(), array_size_type, filename_display_preference, - } + embed_source, + }) } fn item_namespace(&mut self, tcx: TyCtxt<'_>, def_id: DefId) -> UnitEntryId { diff --git a/src/debuginfo/types.rs b/src/debuginfo/types.rs index 0d49f32373ca..a292429cdfad 100644 --- a/src/debuginfo/types.rs +++ b/src/debuginfo/types.rs @@ -56,7 +56,7 @@ pub(crate) fn debug_type<'tcx>( // ty::FnDef(..) | ty::FnPtr(..) // ty::Closure(..) // ty::Adt(def, ..) - ty::Tuple(components) => self.tuple_type(tcx, type_dbg, ty, *components), + ty::Tuple(components) => self.tuple_type(tcx, type_dbg, ty, components), // ty::Param(_) // FIXME implement remaining types and add unreachable!() to the fallback branch _ => self.placeholder_for_type(tcx, type_dbg, ty), @@ -152,7 +152,7 @@ fn tuple_type<'tcx>( components: &'tcx [Ty<'tcx>], ) -> UnitEntryId { let components = components - .into_iter() + .iter() .map(|&ty| (ty, self.debug_type(tcx, type_dbg, ty))) .collect::>(); diff --git a/src/debuginfo/unwind.rs b/src/debuginfo/unwind.rs index 74b82a7139ab..ecaf88a26259 100644 --- a/src/debuginfo/unwind.rs +++ b/src/debuginfo/unwind.rs @@ -1,15 +1,23 @@ //! Unwind info generation (`.eh_frame`) +use cranelift_codegen::FinalizedMachExceptionHandler; use cranelift_codegen::ir::Endianness; use cranelift_codegen::isa::unwind::UnwindInfo; +use cranelift_module::DataId; use cranelift_object::ObjectProduct; -use gimli::RunTimeEndian; -use gimli::write::{CieId, EhFrame, FrameTable, Section}; +use gimli::write::{Address, CieId, EhFrame, FrameTable, Section}; +use gimli::{Encoding, Format, RunTimeEndian}; -use super::emit::address_for_func; +use super::emit::{DebugRelocName, address_for_data, address_for_func}; +use super::gcc_except_table::{ + Action, ActionKind, ActionTable, CallSite, CallSiteTable, GccExceptTable, TypeInfoTable, +}; use super::object::WriteDebugInfo; use crate::prelude::*; +pub(crate) const EXCEPTION_HANDLER_CLEANUP: u32 = 0; +pub(crate) const EXCEPTION_HANDLER_CATCH: u32 = 1; + pub(crate) struct UnwindContext { endian: RunTimeEndian, frame_table: FrameTable, @@ -25,10 +33,79 @@ pub(crate) fn new(module: &mut dyn Module, pic_eh_frame: bool) -> Self { let mut frame_table = FrameTable::default(); let cie_id = if let Some(mut cie) = module.isa().create_systemv_cie() { - if pic_eh_frame { - cie.fde_address_encoding = - gimli::DwEhPe(gimli::DW_EH_PE_pcrel.0 | gimli::DW_EH_PE_sdata4.0); + let ptr_encoding = if pic_eh_frame { + gimli::DwEhPe(gimli::DW_EH_PE_pcrel.0 | gimli::DW_EH_PE_sdata4.0) + } else { + gimli::DW_EH_PE_absptr + }; + + cie.fde_address_encoding = ptr_encoding; + + // FIXME only add personality function and lsda when necessary: https://github.com/rust-lang/rust/blob/1f76d219c906f0112bb1872f33aa977164c53fa6/compiler/rustc_codegen_ssa/src/mir/mod.rs#L200-L204 + if cfg!(feature = "unwinding") { + let code_ptr_encoding = if pic_eh_frame { + if module.isa().triple().architecture == target_lexicon::Architecture::X86_64 { + gimli::DwEhPe( + gimli::DW_EH_PE_indirect.0 + | gimli::DW_EH_PE_pcrel.0 + | gimli::DW_EH_PE_sdata4.0, + ) + } else if let target_lexicon::Architecture::Aarch64(_) = + module.isa().triple().architecture + { + gimli::DwEhPe( + gimli::DW_EH_PE_indirect.0 + | gimli::DW_EH_PE_pcrel.0 + | gimli::DW_EH_PE_sdata8.0, + ) + } else { + todo!() + } + } else { + gimli::DwEhPe(gimli::DW_EH_PE_indirect.0 | gimli::DW_EH_PE_absptr.0) + }; + + cie.lsda_encoding = Some(ptr_encoding); + + // FIXME use eh_personality lang item instead + let personality = module + .declare_function( + "rust_eh_personality", + Linkage::Import, + &Signature { + params: vec![ + AbiParam::new(types::I32), + AbiParam::new(types::I32), + AbiParam::new(types::I64), + AbiParam::new(module.target_config().pointer_type()), + AbiParam::new(module.target_config().pointer_type()), + ], + returns: vec![AbiParam::new(types::I32)], + call_conv: module.target_config().default_call_conv, + }, + ) + .unwrap(); + + // Use indirection here to support PIC the case where rust_eh_personality is defined in + // another DSO. + let personality_ref = module + .declare_data("DW.ref.rust_eh_personality", Linkage::Local, false, false) + .unwrap(); + + let mut personality_ref_data = DataDescription::new(); + // Note: Must not use define_zeroinit. The unwinder can't handle this being in the .bss + // section. + let pointer_bytes = usize::from(module.target_config().pointer_bytes()); + personality_ref_data.define(vec![0; pointer_bytes].into_boxed_slice()); + let personality_func_ref = + module.declare_func_in_data(personality, &mut personality_ref_data); + personality_ref_data.write_function_addr(0, personality_func_ref); + + module.define_data(personality_ref, &personality_ref_data).unwrap(); + + cie.personality = Some((code_ptr_encoding, address_for_data(personality_ref))); } + Some(frame_table.add_cie(cie)) } else { None @@ -63,8 +140,100 @@ pub(crate) fn add_function( match unwind_info { UnwindInfo::SystemV(unwind_info) => { - self.frame_table - .add_fde(self.cie_id.unwrap(), unwind_info.to_fde(address_for_func(func_id))); + let mut fde = unwind_info.to_fde(address_for_func(func_id)); + + // FIXME only add personality function and lsda when necessary: https://github.com/rust-lang/rust/blob/1f76d219c906f0112bb1872f33aa977164c53fa6/compiler/rustc_codegen_ssa/src/mir/mod.rs#L200-L204 + if cfg!(feature = "unwinding") { + // FIXME use unique symbol name derived from function name + let lsda = module.declare_anonymous_data(false, false).unwrap(); + + let encoding = Encoding { + format: Format::Dwarf32, + version: 1, + address_size: module.isa().frontend_config().pointer_bytes(), + }; + + let mut gcc_except_table_data = GccExceptTable { + call_sites: CallSiteTable(vec![]), + actions: ActionTable::new(), + type_info: TypeInfoTable::new(gimli::DW_EH_PE_udata4), + }; + + let catch_type = gcc_except_table_data.type_info.add(Address::Constant(0)); + let catch_action = gcc_except_table_data + .actions + .add(Action { kind: ActionKind::Catch(catch_type), next_action: None }); + + for call_site in context.compiled_code().unwrap().buffer.call_sites() { + if call_site.exception_handlers.is_empty() { + gcc_except_table_data.call_sites.0.push(CallSite { + start: u64::from(call_site.ret_addr - 1), + length: 1, + landing_pad: 0, + action_entry: None, + }); + } + for &handler in call_site.exception_handlers { + match handler { + FinalizedMachExceptionHandler::Tag(tag, landingpad) => { + match tag.as_u32() { + EXCEPTION_HANDLER_CLEANUP => { + gcc_except_table_data.call_sites.0.push(CallSite { + start: u64::from(call_site.ret_addr - 1), + length: 1, + landing_pad: u64::from(landingpad), + action_entry: None, + }) + } + EXCEPTION_HANDLER_CATCH => { + gcc_except_table_data.call_sites.0.push(CallSite { + start: u64::from(call_site.ret_addr - 1), + length: 1, + landing_pad: u64::from(landingpad), + action_entry: Some(catch_action), + }) + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } + } + + let mut gcc_except_table = super::emit::WriterRelocate::new(self.endian); + + gcc_except_table_data.write(&mut gcc_except_table, encoding).unwrap(); + + let mut data = DataDescription::new(); + data.define(gcc_except_table.writer.into_vec().into_boxed_slice()); + data.set_segment_section("", ".gcc_except_table"); + + for reloc in &gcc_except_table.relocs { + match reloc.name { + DebugRelocName::Section(_id) => unreachable!(), + DebugRelocName::Symbol(id) => { + let id = id.try_into().unwrap(); + if id & 1 << 31 == 0 { + let func_ref = module + .declare_func_in_data(FuncId::from_u32(id), &mut data); + data.write_function_addr(reloc.offset, func_ref); + } else { + let gv = module.declare_data_in_data( + DataId::from_u32(id & !(1 << 31)), + &mut data, + ); + data.write_data_addr(reloc.offset, gv, 0); + } + } + }; + } + + module.define_data(lsda, &data).unwrap(); + fde.lsda = Some(address_for_data(lsda)); + } + + self.frame_table.add_fde(self.cie_id.unwrap(), fde); } UnwindInfo::WindowsX64(_) | UnwindInfo::WindowsArm64(_) => { // Windows does not have debug info for its unwind info. @@ -116,7 +285,7 @@ pub(crate) unsafe fn register_jit(self, jit_module: &cranelift_jit::JITModule) { // Everything after this line up to the end of the file is loosely based on // https://github.com/bytecodealliance/wasmtime/blob/4471a82b0c540ff48960eca6757ccce5b1b5c3e4/crates/jit/src/unwind/systemv.rs #[cfg(target_os = "macos")] - { + unsafe { // On macOS, `__register_frame` takes a pointer to a single FDE let start = eh_frame.as_ptr(); let end = start.add(eh_frame.len()); @@ -138,12 +307,12 @@ pub(crate) unsafe fn register_jit(self, jit_module: &cranelift_jit::JITModule) { #[cfg(not(target_os = "macos"))] { // On other platforms, `__register_frame` will walk the FDEs until an entry of length 0 - __register_frame(eh_frame.as_ptr()); + unsafe { __register_frame(eh_frame.as_ptr()) }; } } } -extern "C" { +unsafe extern "C" { // libunwind import fn __register_frame(fde: *const u8); } diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 7bf1efc10653..760e23f2171b 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -24,9 +24,8 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::{CodegenUnit, MonoItem, MonoItemData, Visibility}; use rustc_session::Session; -use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType}; +use rustc_session::config::{OutFileName, OutputFilenames, OutputType}; -use crate::CodegenCx; use crate::base::CodegenedFunction; use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken}; use crate::debuginfo::TypeDebugContext; @@ -98,8 +97,8 @@ pub(crate) fn join( sess, &module_regular.name, &[ - ("o", &module_regular.object.as_ref().unwrap()), - ("asm.o", &module_global_asm.object.as_ref().unwrap()), + ("o", module_regular.object.as_ref().unwrap()), + ("asm.o", module_global_asm.object.as_ref().unwrap()), ], &[], ) @@ -107,7 +106,7 @@ pub(crate) fn join( rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir( sess, &module_regular.name, - &[("o", &module_regular.object.as_ref().unwrap())], + &[("o", module_regular.object.as_ref().unwrap())], &[], ) }; @@ -309,7 +308,7 @@ fn produce_final_output_artifacts( module.for_each_output(|path, ty| { if sess.opts.output_types.contains_key(&ty) { let descr = ty.shorthand(); - sess.dcx().emit_artifact_notification(&path, descr); + sess.dcx().emit_artifact_notification(path, descr); } }); } @@ -451,8 +450,8 @@ fn reuse_workproduct_for_cgu( tcx.sess.invocation_temp.as_deref(), ); let source_file_regular = rustc_incremental::in_incr_comp_dir_sess( - &tcx.sess, - &work_product.saved_files.get("o").expect("no saved object file in work product"), + tcx.sess, + work_product.saved_files.get("o").expect("no saved object file in work product"), ); if let Err(err) = rustc_fs_util::link_or_copy(&source_file_regular, &obj_out_regular) { @@ -467,7 +466,7 @@ fn reuse_workproduct_for_cgu( let obj_out_global_asm = crate::global_asm::add_file_stem_postfix(obj_out_regular.clone(), ".asm"); let source_file_global_asm = if let Some(asm_o) = work_product.saved_files.get("asm.o") { - let source_file_global_asm = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, asm_o); + let source_file_global_asm = rustc_incremental::in_incr_comp_dir_sess(tcx.sess, asm_o); if let Err(err) = rustc_fs_util::link_or_copy(&source_file_global_asm, &obj_out_global_asm) { return Err(format!( @@ -511,18 +510,14 @@ fn codegen_cgu_content( tcx: TyCtxt<'_>, module: &mut dyn Module, cgu_name: rustc_span::Symbol, -) -> (CodegenCx, Vec) { +) -> (Option, Vec, String) { let _timer = tcx.prof.generic_activity_with_arg("codegen cgu", cgu_name.as_str()); let cgu = tcx.codegen_unit(cgu_name); let mono_items = cgu.items_in_deterministic_order(tcx); - let mut cx = crate::CodegenCx::new( - tcx, - module.isa(), - tcx.sess.opts.debuginfo != DebugInfo::None, - cgu_name, - ); + let mut debug_context = DebugContext::new(tcx, module.isa(), false, cgu_name.as_str()); + let mut global_asm = String::new(); let mut type_dbg = TypeDebugContext::default(); super::predefine_mono_items(tcx, module, &mono_items); let mut codegened_functions = vec![]; @@ -532,7 +527,7 @@ fn codegen_cgu_content( let flags = tcx.codegen_instance_attrs(instance.def).flags; if flags.contains(CodegenFnAttrFlags::NAKED) { rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm( - &mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm }, + &mut GlobalAsmContext { tcx, global_asm: &mut global_asm }, instance, MonoItemData { linkage: RLinkage::External, @@ -548,7 +543,8 @@ fn codegen_cgu_content( } let codegened_function = crate::base::codegen_fn( tcx, - &mut cx, + cgu_name, + debug_context.as_mut(), &mut type_dbg, Function::new(), module, @@ -558,13 +554,13 @@ fn codegen_cgu_content( } MonoItem::Static(def_id) => { let data_id = crate::constant::codegen_static(tcx, module, def_id); - if let Some(debug_context) = &mut cx.debug_context { + if let Some(debug_context) = debug_context.as_mut() { debug_context.define_static(tcx, &mut type_dbg, def_id, data_id); } } MonoItem::GlobalAsm(item_id) => { rustc_codegen_ssa::base::codegen_global_asm( - &mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm }, + &mut GlobalAsmContext { tcx, global_asm: &mut global_asm }, item_id, ); } @@ -572,7 +568,7 @@ fn codegen_cgu_content( } crate::main_shim::maybe_create_entry_wrapper(tcx, module, false, cgu.is_primary()); - (cx, codegened_functions) + (debug_context, codegened_functions, global_asm) } fn module_codegen( @@ -585,13 +581,17 @@ fn module_codegen( ) -> OngoingModuleCodegen { let mut module = make_module(tcx.sess, cgu_name.as_str().to_string()); - let (mut cx, codegened_functions) = codegen_cgu_content(tcx, &mut module, cgu_name); + let (mut debug_context, codegened_functions, mut global_asm) = + codegen_cgu_content(tcx, &mut module, cgu_name); let cgu_name = cgu_name.as_str().to_owned(); let producer = crate::debuginfo::producer(tcx.sess); let profiler = tcx.prof.clone(); + let invocation_temp = tcx.sess.invocation_temp.clone(); + let output_filenames = tcx.output_filenames(()).clone(); + let should_write_ir = crate::pretty_clif::should_write_ir(tcx.sess); OngoingModuleCodegen::Async(std::thread::spawn(move || { profiler.clone().generic_activity_with_arg("compile functions", &*cgu_name).run(|| { @@ -602,10 +602,13 @@ fn module_codegen( let mut cached_context = Context::new(); for codegened_func in codegened_functions { crate::base::compile_fn( - &mut cx, &profiler, + &output_filenames, + should_write_ir, &mut cached_context, &mut module, + debug_context.as_mut(), + &mut global_asm, codegened_func, ); } @@ -616,8 +619,8 @@ fn module_codegen( crate::global_asm::compile_global_asm( &global_asm_config, &cgu_name, - &cx.global_asm, - cx.invocation_temp.as_deref(), + global_asm, + invocation_temp.as_deref(), ) })?; @@ -625,11 +628,11 @@ fn module_codegen( profiler.generic_activity_with_arg("write object file", &*cgu_name).run(|| { emit_cgu( &global_asm_config.output_filenames, - cx.invocation_temp.as_deref(), + invocation_temp.as_deref(), &profiler, cgu_name, module, - cx.debug_context, + debug_context, global_asm_object_file, &producer, ) @@ -681,7 +684,7 @@ pub(crate) fn run_aot(tcx: TyCtxt<'_>) -> Box { // Calculate the CGU reuse let cgu_reuse = tcx.sess.time("find_cgu_reuse", || { - cgus.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect::>() + cgus.iter().map(|cgu| determine_cgu_reuse(tcx, cgu)).collect::>() }); rustc_codegen_ssa::assert_module_sources::assert_module_sources(tcx, &|cgu_reuse_tracker| { @@ -695,7 +698,7 @@ pub(crate) fn run_aot(tcx: TyCtxt<'_>) -> Box { let disable_incr_cache = disable_incr_cache(); let (todo_cgus, done_cgus) = - cgus.into_iter().enumerate().partition::, _>(|&(i, _)| match cgu_reuse[i] { + cgus.iter().enumerate().partition::, _>(|&(i, _)| match cgu_reuse[i] { _ if disable_incr_cache => true, CguReuse::No => true, CguReuse::PreLto | CguReuse::PostLto => false, diff --git a/src/driver/jit.rs b/src/driver/jit.rs index fec46bf26975..9dba46363936 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -9,14 +9,14 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::MonoItem; use rustc_session::Session; +use rustc_session::config::OutputFilenames; use rustc_span::sym; -use crate::CodegenCx; use crate::debuginfo::TypeDebugContext; use crate::prelude::*; use crate::unwind_module::UnwindModule; -fn create_jit_module(tcx: TyCtxt<'_>) -> (UnwindModule, CodegenCx) { +fn create_jit_module(tcx: TyCtxt<'_>) -> (UnwindModule, Option) { let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string()); let isa = crate::build_isa(tcx.sess, true); @@ -25,7 +25,7 @@ fn create_jit_module(tcx: TyCtxt<'_>) -> (UnwindModule, CodegenCx) { jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info)); let mut jit_module = UnwindModule::new(JITModule::new(jit_builder), false); - let cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, sym::dummy_cgu_name); + let cx = DebugContext::new(tcx, jit_module.isa(), false, "dummy_cgu_name"); crate::allocator::codegen(tcx, &mut jit_module); @@ -33,13 +33,13 @@ fn create_jit_module(tcx: TyCtxt<'_>) -> (UnwindModule, CodegenCx) { } pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_args: Vec) -> ! { - // FIXME error on check mode or crate types other than bin in CodegenBackend::init() - if !tcx.crate_types().contains(&rustc_session::config::CrateType::Executable) { tcx.dcx().fatal("can't jit non-executable crate"); } - let (mut jit_module, mut cx) = create_jit_module(tcx); + let output_filenames = tcx.output_filenames(()); + let should_write_ir = crate::pretty_clif::should_write_ir(tcx.sess); + let (mut jit_module, mut debug_context) = create_jit_module(tcx); let mut cached_context = Context::new(); let cgus = tcx.collect_and_partition_mono_items(()).codegen_units; @@ -58,7 +58,9 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_args: Vec) -> ! { MonoItem::Fn(inst) => { codegen_and_compile_fn( tcx, - &mut cx, + &output_filenames, + should_write_ir, + debug_context.as_mut(), &mut cached_context, &mut jit_module, inst, @@ -75,10 +77,6 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_args: Vec) -> ! { } }); - if !cx.global_asm.is_empty() { - tcx.dcx().fatal("Inline asm is not supported in JIT mode"); - } - crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module, true, true); tcx.dcx().abort_if_errors(); @@ -120,7 +118,9 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_args: Vec) -> ! { fn codegen_and_compile_fn<'tcx>( tcx: TyCtxt<'tcx>, - cx: &mut crate::CodegenCx, + output_filenames: &OutputFilenames, + should_write_ir: bool, + mut debug_context: Option<&mut DebugContext>, cached_context: &mut Context, module: &mut dyn Module, instance: Instance<'tcx>, @@ -141,13 +141,28 @@ fn codegen_and_compile_fn<'tcx>( let cached_func = std::mem::replace(&mut cached_context.func, Function::new()); let codegened_func = crate::base::codegen_fn( tcx, - cx, + sym::dummy_cgu_name, + debug_context.as_deref_mut(), &mut TypeDebugContext::default(), cached_func, module, instance, ); - crate::base::compile_fn(cx, &tcx.prof, cached_context, module, codegened_func); + + let mut global_asm = String::new(); + crate::base::compile_fn( + &tcx.prof, + output_filenames, + should_write_ir, + cached_context, + module, + debug_context.as_deref_mut(), + &mut global_asm, + codegened_func, + ); + if !global_asm.is_empty() { + tcx.dcx().fatal("Inline asm is not supported in JIT mode"); + } }); } diff --git a/src/driver/mod.rs b/src/driver/mod.rs index 8f83c30b598d..9f2b7b4b09f2 100644 --- a/src/driver/mod.rs +++ b/src/driver/mod.rs @@ -38,16 +38,12 @@ fn predefine_mono_items<'tcx>( .codegen_instance_attrs(instance.def) .flags .contains(CodegenFnAttrFlags::NAKED); - module - .declare_function( - name, - // Naked functions are defined in a separate object - // file from the codegen unit rustc expects them to - // be defined in. - if is_naked { Linkage::Import } else { linkage }, - &sig, - ) - .unwrap(); + if is_naked { + // Naked functions are defined in a separate object + // file, so they can be declared on the fly. + continue; + } + module.declare_function(name, linkage, &sig).unwrap(); } MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {} } diff --git a/src/global_asm.rs b/src/global_asm.rs index 1306c6aa5179..8d8cdb14dbc6 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -171,7 +171,7 @@ pub(crate) fn new(tcx: TyCtxt<'_>) -> Self { pub(crate) fn compile_global_asm( config: &GlobalAsmConfig, cgu_name: &str, - global_asm: &str, + global_asm: String, invocation_temp: Option<&str>, ) -> Result, String> { if global_asm.is_empty() { @@ -205,6 +205,9 @@ pub(crate) fn compile_global_asm( return Err(format!("Failed to assemble `{}`", global_asm)); } } else { + // Escape { and } + let global_asm = global_asm.replace('{', "{{").replace('}', "}}"); + let mut child = Command::new(std::env::current_exe().unwrap()) // Avoid a warning about the jobserver fd not being passed .env_remove("CARGO_MAKEFLAGS") diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 120d6ff9e38e..08cabe9d695c 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -7,6 +7,7 @@ use rustc_hir::LangItem; use rustc_span::sym; use rustc_target::asm::*; +use rustc_target::spec::Arch; use target_lexicon::BinaryFormat; use crate::prelude::*; @@ -51,6 +52,26 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( return; } + if fx.tcx.sess.target.arch == Arch::S390x + && template.len() == 3 + && template[0] == InlineAsmTemplatePiece::String("stfle 0(".into()) + && let InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: None, span: _ } = + template[1] + && template[2] == InlineAsmTemplatePiece::String(")".into()) + { + // FIXME no inline asm support for s390x yet, but stdarch needs it for feature detection + match destination { + Some(destination) => { + let destination_block = fx.get_block(destination); + fx.bcx.ins().jump(destination_block, &[]); + } + None => { + fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap()); + } + } + return; + } + let operands = operands .iter() .map(|operand| match *operand { @@ -103,11 +124,12 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( // be exported from the main codegen unit and may thus be unreachable from the // object file created by an external assembler. let wrapper_name = format!( - "__inline_asm_{}_wrapper_n{}", - fx.cx.cgu_name.as_str().replace('.', "__").replace('-', "_"), - fx.cx.inline_asm_index + "{}__inline_asm_{}_wrapper_n{}", + fx.symbol_name, + fx.cgu_name.as_str().replace('.', "__").replace('-', "_"), + fx.inline_asm_index, ); - fx.cx.inline_asm_index += 1; + fx.inline_asm_index += 1; let sig = get_function_sig(fx.tcx, fx.target_config.default_call_conv, instance); create_wrapper_function(fx.module, sig, &wrapper_name, symbol.name); @@ -166,14 +188,15 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>( asm_gen.allocate_stack_slots(); let asm_name = format!( - "__inline_asm_{}_n{}", - fx.cx.cgu_name.as_str().replace('.', "__").replace('-', "_"), - fx.cx.inline_asm_index + "{}__inline_asm_{}_n{}", + fx.symbol_name, + fx.cgu_name.as_str().replace('.', "__").replace('-', "_"), + fx.inline_asm_index, ); - fx.cx.inline_asm_index += 1; + fx.inline_asm_index += 1; let generated_asm = asm_gen.generate_asm_wrapper(&asm_name); - fx.cx.global_asm.push_str(&generated_asm); + fx.inline_asm.push_str(&generated_asm); let mut inputs = Vec::new(); let mut outputs = Vec::new(); @@ -546,20 +569,6 @@ fn generate_asm_wrapper(&self, asm_name: &str) -> String { .emit(&mut generated_asm, InlineAsmArch::X86_64, *modifier) .unwrap(), }, - InlineAsmArch::AArch64 => match reg { - InlineAsmReg::AArch64(reg) if reg.vreg_index().is_some() => { - // rustc emits v0 rather than q0 - reg.emit( - &mut generated_asm, - InlineAsmArch::AArch64, - Some(modifier.unwrap_or('q')), - ) - .unwrap() - } - _ => reg - .emit(&mut generated_asm, InlineAsmArch::AArch64, *modifier) - .unwrap(), - }, _ => reg.emit(&mut generated_asm, self.arch, *modifier).unwrap(), } } @@ -827,6 +836,7 @@ fn call_inline_asm<'tcx>( } let stack_slot_addr = stack_slot.get_addr(fx); + // FIXME use try_call once unwinding inline assembly is supported fx.bcx.ins().call(inline_asm_func, &[stack_slot_addr]); for (offset, place) in outputs { diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index ed40901ac9b8..a78c6e0a4e7a 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -3,7 +3,7 @@ macro_rules! intrinsic_args { ($fx:expr, $args:expr => ($($arg:tt),*); $intrinsic:expr) => { - #[allow(unused_parens)] + #[allow(unused_parens, clippy::unused_unit)] let ($($arg),*) = if let [$($arg),*] = $args { ($(codegen_operand($fx, &($arg).node)),*) } else { @@ -17,17 +17,21 @@ macro_rules! intrinsic_args { mod llvm_x86; mod simd; -use cranelift_codegen::ir::AtomicRmwOp; +use cranelift_codegen::ir::{ + AtomicRmwOp, BlockArg, ExceptionTableData, ExceptionTableItem, ExceptionTag, +}; use rustc_middle::ty; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_span::source_map::Spanned; use rustc_span::{Symbol, sym}; +use rustc_target::spec::PanicStrategy; pub(crate) use self::llvm::codegen_llvm_intrinsic_call; use crate::cast::clif_intcast; use crate::codegen_f16_f128; +use crate::debuginfo::EXCEPTION_HANDLER_CATCH; use crate::prelude::*; fn bug_on_incorrect_arg_count(intrinsic: impl std::fmt::Display) -> ! { @@ -479,7 +483,7 @@ fn codegen_float_intrinsic_call<'tcx>( }; let input_tys: Vec<_> = vec![AbiParam::new(clif_ty), lib_call_arg_param(fx.tcx, types::I32, true)]; - let ret_val = fx.lib_call(name, input_tys, vec![AbiParam::new(clif_ty)], &args)[0]; + let ret_val = fx.lib_call(name, input_tys, vec![AbiParam::new(clif_ty)], args)[0]; let ret_val = if intrinsic == sym::powif16 { codegen_f16_f128::f32_to_f16(fx, ret_val) } else { @@ -501,7 +505,7 @@ fn codegen_float_intrinsic_call<'tcx>( } _ => { let input_tys: Vec<_> = args.iter().map(|_| AbiParam::new(clif_ty)).collect(); - let ret_val = fx.lib_call(name, input_tys, vec![AbiParam::new(clif_ty)], &args)[0]; + let ret_val = fx.lib_call(name, input_tys, vec![AbiParam::new(clif_ty)], args)[0]; CValue::by_val(ret_val, fx.layout_of(ty)) } }; @@ -1337,23 +1341,75 @@ fn codegen_regular_intrinsic_call<'tcx>( } sym::catch_unwind => { + let ret_block = fx.get_block(destination.unwrap()); + intrinsic_args!(fx, args => (f, data, catch_fn); intrinsic); let f = f.load_scalar(fx); let data = data.load_scalar(fx); - let _catch_fn = catch_fn.load_scalar(fx); + let catch_fn = catch_fn.load_scalar(fx); - // FIXME once unwinding is supported, change this to actually catch panics let f_sig = fx.bcx.func.import_signature(Signature { call_conv: fx.target_config.default_call_conv, params: vec![AbiParam::new(pointer_ty(fx.tcx))], returns: vec![], }); - fx.bcx.ins().call_indirect(f_sig, f, &[data]); + if cfg!(not(feature = "unwinding")) + || fx.tcx.sess.panic_strategy() == PanicStrategy::Abort + { + fx.bcx.ins().call_indirect(f_sig, f, &[data]); - let layout = fx.layout_of(fx.tcx.types.i32); - let ret_val = CValue::by_val(fx.bcx.ins().iconst(types::I32, 0), layout); - ret.write_cvalue(fx, ret_val); + let layout = fx.layout_of(fx.tcx.types.i32); + let ret_val = CValue::by_val(fx.bcx.ins().iconst(types::I32, 0), layout); + ret.write_cvalue(fx, ret_val); + + fx.bcx.ins().jump(ret_block, &[]); + } else { + let catch_fn_sig = fx.bcx.func.import_signature(Signature { + call_conv: fx.target_config.default_call_conv, + params: vec![ + AbiParam::new(pointer_ty(fx.tcx)), + AbiParam::new(pointer_ty(fx.tcx)), + ], + returns: vec![], + }); + + let fallthrough_block = fx.bcx.create_block(); + let fallthrough_block_call = fx.bcx.func.dfg.block_call(fallthrough_block, &[]); + let catch_block = fx.bcx.create_block(); + let catch_block_call = + fx.bcx.func.dfg.block_call(catch_block, &[BlockArg::TryCallExn(0)]); + let exception_table = + fx.bcx.func.dfg.exception_tables.push(ExceptionTableData::new( + f_sig, + fallthrough_block_call, + [ExceptionTableItem::Tag( + ExceptionTag::with_number(EXCEPTION_HANDLER_CATCH).unwrap(), + catch_block_call, + )], + )); + + fx.bcx.ins().try_call_indirect(f, &[data], exception_table); + + fx.bcx.seal_block(fallthrough_block); + fx.bcx.switch_to_block(fallthrough_block); + let layout = fx.layout_of(fx.tcx.types.i32); + let ret_val = CValue::by_val(fx.bcx.ins().iconst(types::I32, 0), layout); + ret.write_cvalue(fx, ret_val); + fx.bcx.ins().jump(ret_block, &[]); + + fx.bcx.seal_block(catch_block); + fx.bcx.switch_to_block(catch_block); + fx.bcx.set_cold_block(catch_block); + let exception = fx.bcx.append_block_param(catch_block, pointer_ty(fx.tcx)); + fx.bcx.ins().call_indirect(catch_fn_sig, catch_fn, &[data, exception]); + let layout = fx.layout_of(fx.tcx.types.i32); + let ret_val = CValue::by_val(fx.bcx.ins().iconst(types::I32, 1), layout); + ret.write_cvalue(fx, ret_val); + fx.bcx.ins().jump(ret_block, &[]); + } + + return Ok(()); } sym::fadd_fast diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index ca41381f0abc..0bce31beb8b8 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -813,7 +813,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( Endian::Big => lane_count - 1 - lane, Endian::Little => lane, }; - let m_lane = fx.bcx.ins().ushr_imm(m, u64::from(mask_lane) as i64); + let m_lane = fx.bcx.ins().ushr_imm(m, mask_lane.cast_signed()); let m_lane = fx.bcx.ins().band_imm(m_lane, 1); let a_lane = a.value_lane(fx, lane).load_scalar(fx); let b_lane = b.value_lane(fx, lane).load_scalar(fx); @@ -1059,6 +1059,15 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let ret_lane_layout = fx.layout_of(ret_lane_ty); let ptr_val = ptr.load_scalar(fx); + let alignment = generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0] + .unwrap_leaf() + .to_simd_alignment(); + + let memflags = match alignment { + SimdAlign::Unaligned => MemFlags::new().with_notrap(), + _ => MemFlags::trusted(), + }; + for lane_idx in 0..ret_lane_count { let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx); let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx); @@ -1074,12 +1083,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( fx.bcx.switch_to_block(if_enabled); let offset = lane_idx as i32 * lane_clif_ty.bytes() as i32; - let res = fx.bcx.ins().load( - lane_clif_ty, - MemFlags::trusted(), - ptr_val, - Offset32::new(offset), - ); + let res = fx.bcx.ins().load(lane_clif_ty, memflags, ptr_val, Offset32::new(offset)); fx.bcx.ins().jump(next, &[res.into()]); fx.bcx.switch_to_block(if_disabled); diff --git a/src/lib.rs b/src/lib.rs index b63773053d3f..4745243a6eab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_codegen_ssa; +extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_fs_util; @@ -35,6 +36,7 @@ extern crate rustc_driver; use std::any::Any; +use std::cell::OnceCell; use std::env; use std::sync::Arc; @@ -120,41 +122,8 @@ fn drop(&mut self) { } } -/// The codegen context holds any information shared between the codegen of individual functions -/// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module). -struct CodegenCx { - output_filenames: Arc, - invocation_temp: Option, - should_write_ir: bool, - global_asm: String, - inline_asm_index: usize, - debug_context: Option, - cgu_name: Symbol, -} - -impl CodegenCx { - fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, debug_info: bool, cgu_name: Symbol) -> Self { - assert_eq!(pointer_ty(tcx), isa.pointer_type()); - - let debug_context = if debug_info && !tcx.sess.target.options.is_like_windows { - Some(DebugContext::new(tcx, isa, cgu_name.as_str())) - } else { - None - }; - CodegenCx { - output_filenames: tcx.output_filenames(()).clone(), - invocation_temp: tcx.sess.invocation_temp.clone(), - should_write_ir: crate::pretty_clif::should_write_ir(tcx), - global_asm: String::new(), - inline_asm_index: 0, - debug_context, - cgu_name, - } - } -} - pub struct CraneliftCodegenBackend { - pub config: Option, + pub config: OnceCell, } impl CodegenBackend for CraneliftCodegenBackend { @@ -180,6 +149,15 @@ fn init(&self, sess: &Session) { sess.dcx() .fatal("`-Cinstrument-coverage` is LLVM specific and not supported by Cranelift"); } + + let config = self.config.get_or_init(|| { + BackendConfig::from_opts(&sess.opts.cg.llvm_args) + .unwrap_or_else(|err| sess.dcx().fatal(err)) + }); + + if config.jit_mode && !sess.opts.output_types.should_codegen() { + sess.dcx().fatal("JIT mode doesn't work with `cargo check`"); + } } fn target_config(&self, sess: &Session) -> TargetConfig { @@ -202,36 +180,23 @@ fn target_config(&self, sess: &Session) -> TargetConfig { // FIXME do `unstable_target_features` properly let unstable_target_features = target_features.clone(); - // FIXME(f16_f128): LLVM 20 (currently used by `rustc`) passes `f128` in XMM registers on - // Windows, whereas LLVM 21+ and Cranelift pass it indirectly. This means that `f128` won't - // work when linking against a LLVM-built sysroot. - let has_reliable_f128 = !sess.target.is_like_windows; - let has_reliable_f16 = match sess.target.arch { - // FIXME(f16_f128): LLVM 20 does not support `f16` on s390x, meaning the required - // builtins are not available in `compiler-builtins`. - Arch::S390x => false, - // FIXME(f16_f128): `rustc_codegen_llvm` currently disables support on Windows GNU - // targets due to GCC using a different ABI than LLVM. Therefore `f16` won't be - // available when using a LLVM-built sysroot. - Arch::X86_64 - if sess.target.os == "windows" - && sess.target.env == "gnu" - && sess.target.abi != "llvm" => - { - false - } - _ => true, - }; + // FIXME(f16_f128): `rustc_codegen_llvm` currently disables support on Windows GNU + // targets due to GCC using a different ABI than LLVM. Therefore `f16` and `f128` + // won't be available when using a LLVM-built sysroot. + let has_reliable_f16_f128 = !(sess.target.arch == Arch::X86_64 + && sess.target.os == "windows" + && sess.target.env == "gnu" + && sess.target.abi != "llvm"); TargetConfig { target_features, unstable_target_features, // `rustc_codegen_cranelift` polyfills functionality not yet // available in Cranelift. - has_reliable_f16, - has_reliable_f16_math: has_reliable_f16, - has_reliable_f128, - has_reliable_f128_math: has_reliable_f128, + has_reliable_f16: has_reliable_f16_f128, + has_reliable_f16_math: has_reliable_f16_f128, + has_reliable_f128: has_reliable_f16_f128, + has_reliable_f128_math: has_reliable_f16_f128, } } @@ -241,13 +206,10 @@ fn print_version(&self) { fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box { info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE)); - let config = self.config.clone().unwrap_or_else(|| { - BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) - .unwrap_or_else(|err| tcx.sess.dcx().fatal(err)) - }); + let config = self.config.get().unwrap(); if config.jit_mode { #[cfg(feature = "jit")] - driver::jit::run_jit(tcx, config.jit_args); + driver::jit::run_jit(tcx, config.jit_args.clone()); #[cfg(not(feature = "jit"))] tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift"); @@ -294,8 +256,8 @@ fn build_isa(sess: &Session, jit: bool) -> Arc { flags_builder.set("enable_verifier", enable_verifier).unwrap(); flags_builder.set("regalloc_checker", enable_verifier).unwrap(); - let mut frame_ptr = sess.target.options.frame_pointer.clone(); - frame_ptr.ratchet(sess.opts.cg.force_frame_pointers); + let frame_ptr = + { sess.target.options.frame_pointer }.ratchet(sess.opts.cg.force_frame_pointers); let preserve_frame_pointer = frame_ptr != rustc_target::spec::FramePointer::MayOmit; flags_builder .set("preserve_frame_pointers", if preserve_frame_pointer { "true" } else { "false" }) @@ -391,7 +353,7 @@ fn build_isa(sess: &Session, jit: bool) -> Arc { } /// This is the entrypoint for a hot plugged rustc_codegen_cranelift -#[no_mangle] +#[unsafe(no_mangle)] pub fn __rustc_codegen_backend() -> Box { - Box::new(CraneliftCodegenBackend { config: None }) + Box::new(CraneliftCodegenBackend { config: OnceCell::new() }) } diff --git a/src/main_shim.rs b/src/main_shim.rs index bf756860b649..c3e4bf1f0c27 100644 --- a/src/main_shim.rs +++ b/src/main_shim.rs @@ -93,7 +93,7 @@ fn create_entry_fn( let arg_argv = bcx.append_block_param(block, m.target_config().pointer_type()); let arg_sigpipe = bcx.ins().iconst(types::I8, sigpipe as i64); - let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func); + let main_func_ref = m.declare_func_in_func(main_func_id, bcx.func); let result = if ignore_lang_start_wrapper { // ignoring #[lang = "start"] as we are running in the jit @@ -123,7 +123,7 @@ fn create_entry_fn( let report_sig = get_function_sig(tcx, m.target_config().default_call_conv, report); let report_func_id = m.declare_function(report_name, Linkage::Import, &report_sig).unwrap(); - let report_func_ref = m.declare_func_in_func(report_func_id, &mut bcx.func); + let report_func_ref = m.declare_func_in_func(report_func_id, bcx.func); // FIXME do proper abi handling instead of expecting the pass mode to be identical // for returns and arguments. @@ -148,7 +148,7 @@ fn create_entry_fn( let main_val = bcx.ins().func_addr(m.target_config().pointer_type(), main_func_ref); - let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func); + let func_ref = m.declare_func_in_func(start_func_id, bcx.func); let call_inst = bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv, arg_sigpipe]); bcx.inst_results(call_inst)[0] diff --git a/src/pretty_clif.rs b/src/pretty_clif.rs index 9400ae9fcff0..2878fa7aa298 100644 --- a/src/pretty_clif.rs +++ b/src/pretty_clif.rs @@ -64,6 +64,7 @@ use cranelift_codegen::ir::entities::AnyEntity; use cranelift_codegen::write::{FuncWriter, PlainWriter}; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_session::Session; use rustc_session::config::{OutputFilenames, OutputType}; use rustc_target::callconv::FnAbi; @@ -83,7 +84,7 @@ pub(crate) fn new<'tcx>( instance: Instance<'tcx>, fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, ) -> Self { - let enabled = should_write_ir(tcx); + let enabled = should_write_ir(tcx.sess); let global_comments = if enabled { with_no_trimmed_paths!({ vec![ @@ -247,8 +248,8 @@ pub(crate) fn add_post_comment + AsRef>( } } -pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool { - tcx.sess.opts.output_types.contains_key(&OutputType::LlvmAssembly) +pub(crate) fn should_write_ir(sess: &Session) -> bool { + sess.opts.output_types.contains_key(&OutputType::LlvmAssembly) } pub(crate) fn write_ir_file( @@ -311,7 +312,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ::cranelift_codegen::write::decorate_function( &mut &self.clif_comments, &mut clif, - &self.bcx.func, + self.bcx.func, ) .unwrap(); writeln!(f, "\n{}", clif) diff --git a/src/unsize.rs b/src/unsize.rs index c97eb3874b02..3dbb689cccd2 100644 --- a/src/unsize.rs +++ b/src/unsize.rs @@ -134,7 +134,7 @@ pub(crate) fn coerce_unsized_into<'tcx>( (ty::Pat(a, _), ty::Pat(b, _)) => { let src = src.cast_pat_ty_to_base(fx.layout_of(*a)); let dst = dst.place_transmute_type(fx, *b); - return coerce_unsized_into(fx, src, dst); + coerce_unsized_into(fx, src, dst) } (&ty::Ref(..), &ty::Ref(..)) | (&ty::Ref(..), &ty::RawPtr(..)) diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 9dcd4a33d44f..5b76a4cb9779 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -310,13 +310,13 @@ pub(crate) fn const_val( fx.bcx.ins().iconst(clif_ty, raw_val as i64) } ty::Float(FloatTy::F16) => { - fx.bcx.ins().f16const(Ieee16::with_bits(u16::try_from(const_val).unwrap())) + fx.bcx.ins().f16const(Ieee16::with_bits(u16::from(const_val))) } ty::Float(FloatTy::F32) => { - fx.bcx.ins().f32const(Ieee32::with_bits(u32::try_from(const_val).unwrap())) + fx.bcx.ins().f32const(Ieee32::with_bits(u32::from(const_val))) } ty::Float(FloatTy::F64) => { - fx.bcx.ins().f64const(Ieee64::with_bits(u64::try_from(const_val).unwrap())) + fx.bcx.ins().f64const(Ieee64::with_bits(u64::from(const_val))) } ty::Float(FloatTy::F128) => { let value = fx @@ -324,7 +324,7 @@ pub(crate) fn const_val( .func .dfg .constants - .insert(Ieee128::with_bits(u128::try_from(const_val).unwrap()).into()); + .insert(Ieee128::with_bits(u128::from(const_val)).into()); fx.bcx.ins().f128const(value) } _ => panic!( @@ -401,9 +401,7 @@ pub(crate) fn new_var( local: Local, layout: TyAndLayout<'tcx>, ) -> CPlace<'tcx> { - let var = Variable::from_u32(fx.next_ssa_var); - fx.next_ssa_var += 1; - fx.bcx.declare_var(var, fx.clif_type(layout.ty).unwrap()); + let var = fx.bcx.declare_var(fx.clif_type(layout.ty).unwrap()); CPlace { inner: CPlaceInner::Var(local, var), layout } } @@ -412,14 +410,9 @@ pub(crate) fn new_var_pair( local: Local, layout: TyAndLayout<'tcx>, ) -> CPlace<'tcx> { - let var1 = Variable::from_u32(fx.next_ssa_var); - fx.next_ssa_var += 1; - let var2 = Variable::from_u32(fx.next_ssa_var); - fx.next_ssa_var += 1; - let (ty1, ty2) = fx.clif_pair_type(layout.ty).unwrap(); - fx.bcx.declare_var(var1, ty1); - fx.bcx.declare_var(var2, ty2); + let var1 = fx.bcx.declare_var(ty1); + let var2 = fx.bcx.declare_var(ty2); CPlace { inner: CPlaceInner::VarPair(local, var1, var2), layout } } diff --git a/src/vtable.rs b/src/vtable.rs index 423cc8d225be..b5d241d8f39f 100644 --- a/src/vtable.rs +++ b/src/vtable.rs @@ -84,5 +84,5 @@ pub(crate) fn get_vtable<'tcx>( if fx.clif_comments.enabled() { fx.add_comment(local_data_id, "vtable"); } - fx.bcx.ins().global_value(fx.pointer_type, local_data_id) + fx.bcx.ins().symbol_value(fx.pointer_type, local_data_id) } From 9d292ca475cf182d404f5c1f4b6eaf07ac8bfb21 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 8 Nov 2025 15:03:47 +0000 Subject: [PATCH 036/585] Add missing --check-cfg --- build_system/build_sysroot.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 72140c651a9a..70504ee8007d 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -52,7 +52,8 @@ pub(crate) fn build_sysroot( .arg(dirs.source_dir.join("scripts").join(format!("{wrapper}.rs"))) .arg("-o") .arg(&wrapper_path) - .arg("-Cstrip=debuginfo"); + .arg("-Cstrip=debuginfo") + .arg("--check-cfg=cfg(support_panic_unwind)"); if panic_unwind_support { build_cargo_wrapper_cmd.arg("--cfg").arg("support_panic_unwind"); } From a44af2ba0a111c7495cb01027fba44cf9855de92 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 8 Nov 2025 15:04:45 +0000 Subject: [PATCH 037/585] Add missing --check-cfg --- build_system/build_sysroot.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 72140c651a9a..70504ee8007d 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -52,7 +52,8 @@ pub(crate) fn build_sysroot( .arg(dirs.source_dir.join("scripts").join(format!("{wrapper}.rs"))) .arg("-o") .arg(&wrapper_path) - .arg("-Cstrip=debuginfo"); + .arg("-Cstrip=debuginfo") + .arg("--check-cfg=cfg(support_panic_unwind)"); if panic_unwind_support { build_cargo_wrapper_cmd.arg("--cfg").arg("support_panic_unwind"); } From 35a99c1d41a5d1b0751aec83242c86d66526155c Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sun, 9 Nov 2025 12:39:18 -0500 Subject: [PATCH 038/585] rustc_target: hide TargetOptions::vendor --- src/abi/mod.rs | 4 ++-- src/codegen_f16_f128.rs | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 9ac282df5b5e..09d71f5dd557 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -916,8 +916,8 @@ pub(crate) fn codegen_call_with_unwind_action( pub(crate) fn lib_call_arg_param(tcx: TyCtxt<'_>, ty: Type, is_signed: bool) -> AbiParam { let param = AbiParam::new(ty); if ty.is_int() && u64::from(ty.bits()) < tcx.data_layout.pointer_size().bits() { - match (&tcx.sess.target.arch, tcx.sess.target.vendor.as_ref()) { - (Arch::X86_64, _) | (Arch::AArch64, "apple") => match (ty, is_signed) { + match (&tcx.sess.target.arch, tcx.sess.target.is_like_darwin) { + (Arch::X86_64, _) | (Arch::AArch64, true) => match (ty, is_signed) { (types::I8 | types::I16, true) => param.sext(), (types::I8 | types::I16, false) => param.uext(), _ => param, diff --git a/src/codegen_f16_f128.rs b/src/codegen_f16_f128.rs index 91f7220667ff..86bff32dc623 100644 --- a/src/codegen_f16_f128.rs +++ b/src/codegen_f16_f128.rs @@ -5,7 +5,7 @@ pub(crate) fn f16_to_f32(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { let (value, arg_ty) = - if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64 { + if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 { ( fx.bcx.ins().bitcast(types::I16, MemFlags::new(), value), lib_call_arg_param(fx.tcx, types::I16, false), @@ -22,8 +22,7 @@ fn f16_to_f64(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { } pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { - let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64 - { + let ret_ty = if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 { types::I16 } else { types::F16 @@ -38,8 +37,7 @@ pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value } fn f64_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { - let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64 - { + let ret_ty = if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 { types::I16 } else { types::F16 From ff7b6cc27956d1d51e6651c3207fa97c9496e2bb Mon Sep 17 00:00:00 2001 From: Voxell Paladynee Date: Tue, 11 Nov 2025 04:33:12 +0100 Subject: [PATCH 039/585] doc(core::panic::Location::caller): clarify semantics with visual example without changing doctests --- library/core/src/panic/location.rs | 80 +++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs index 8176af03d13a..f37f5370997e 100644 --- a/library/core/src/panic/location.rs +++ b/library/core/src/panic/location.rs @@ -105,38 +105,72 @@ impl<'a> Location<'a> { /// ```standalone_crate /// use std::panic::Location; /// - /// /// Returns the [`Location`] at which it is called. + /// /// ``` + /// /// |1 |11 |21 |31 |41 + /// /// +-|---------|---------|---------|---------|-------- + /// /// 15 | #[track_caller] + /// /// 16 | fn new_location() -> &'static Location<'static> { + /// /// 17 | Location::caller() + /// /// | ------------------| the value of this expression depends on the caller, + /// /// | | since the function is marked #[track_caller] + /// /// 18 | } + /// /// ``` /// #[track_caller] - /// fn get_caller_location() -> &'static Location<'static> { + /// fn new_location() -> &'static Location<'static> { /// Location::caller() /// } /// - /// /// Returns a [`Location`] from within this function's definition. - /// fn get_just_one_location() -> &'static Location<'static> { - /// get_caller_location() + /// /// ``` + /// /// |1 |5 |11 |21 |31 |41 |51 + /// /// +-|---|-----|---------|---------|---------|---------|--- + /// /// 29 | fn constant_location() -> &'static Location<'static> { + /// /// 30 | new_location() + /// /// | ^ any invocation of constant_location() points here, + /// /// | no matter the location it is called from + /// /// 31 | } + /// /// ``` + /// fn constant_location() -> &'static Location<'static> { + /// new_location() /// } /// - /// let fixed_location = get_just_one_location(); - /// assert_eq!(fixed_location.file(), file!()); - /// assert_eq!(fixed_location.line(), 14); - /// assert_eq!(fixed_location.column(), 5); + /// fn main() { + /// // |1 |5 |11 |21 |31 |41 |51 + /// // +-|---|-----|---------|---------|---------|---------|--- + /// // 29 | fn constant_location() -> &'static Location<'static> { + /// // 30 | new_location() + /// // | ^ `let constant` points here + /// // 31 | } + /// let constant = constant_location(); + /// assert_eq!(constant.file(), file!()); + /// assert_eq!((constant.line(), constant.column()), (30, 5)); /// - /// // running the same untracked function in a different location gives us the same result - /// let second_fixed_location = get_just_one_location(); - /// assert_eq!(fixed_location.file(), second_fixed_location.file()); - /// assert_eq!(fixed_location.line(), second_fixed_location.line()); - /// assert_eq!(fixed_location.column(), second_fixed_location.column()); + /// let constant_2 = constant_location(); + /// assert_eq!( + /// (constant.file(), constant.line(), constant.column()), + /// (constant_2.file(), constant_2.line(), constant_2.column()) + /// ); /// - /// let this_location = get_caller_location(); - /// assert_eq!(this_location.file(), file!()); - /// assert_eq!(this_location.line(), 28); - /// assert_eq!(this_location.column(), 21); + /// // |1 |11 |16 |21 |31 + /// // +-|---------|----|----|---------|------ + /// // 55 | let here = new_location(); + /// // | ^ `let here` points here, as `new_location()` is the callsite + /// // 56 | assert_eq!(here.file(), file!()); + /// let here = new_location(); + /// assert_eq!(here.file(), file!()); + /// assert_eq!((here.line(), here.column()), (55, 16)); /// - /// // running the tracked function in a different location produces a different value - /// let another_location = get_caller_location(); - /// assert_eq!(this_location.file(), another_location.file()); - /// assert_ne!(this_location.line(), another_location.line()); - /// assert_ne!(this_location.column(), another_location.column()); + /// // |1 |11 |21 ||32 |41 |51 + /// // +-|---------|---------|---------||--------|---------|------ + /// // 64 | let yet_another_location = new_location(); + /// // | ^ `let yet_another_location` points here + /// // 65 | assert_eq!(here.file(), yet_another_location.file()); + /// let yet_another_location = new_location(); + /// assert_eq!(here.file(), yet_another_location.file()); + /// assert_ne!( + /// (here.line(), here.column()), + /// (yet_another_location.line(), yet_another_location.column()) + /// ); + /// } /// ``` #[must_use] #[stable(feature = "track_caller", since = "1.46.0")] From 032ba980b1717457201515ab5476b82dba4f7f1e Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 5 Nov 2025 12:37:09 -0500 Subject: [PATCH 040/585] rustc_target: introduce Abi Improve type safety by using an enum rather than strings. --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4745243a6eab..19058dac832f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,7 @@ use rustc_session::Session; use rustc_session::config::OutputFilenames; use rustc_span::{Symbol, sym}; -use rustc_target::spec::Arch; +use rustc_target::spec::{Abi, Arch}; pub use crate::config::*; use crate::prelude::*; @@ -186,7 +186,7 @@ fn target_config(&self, sess: &Session) -> TargetConfig { let has_reliable_f16_f128 = !(sess.target.arch == Arch::X86_64 && sess.target.os == "windows" && sess.target.env == "gnu" - && sess.target.abi != "llvm"); + && sess.target.abi != Abi::Llvm); TargetConfig { target_features, From 46f27590af7a87efa24904166b1123a0bdea49b0 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 5 Nov 2025 12:37:09 -0500 Subject: [PATCH 041/585] rustc_target: introduce Env Improve type safety by using an enum rather than strings. --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 19058dac832f..2175869085a3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,7 @@ use rustc_session::Session; use rustc_session::config::OutputFilenames; use rustc_span::{Symbol, sym}; -use rustc_target::spec::{Abi, Arch}; +use rustc_target::spec::{Abi, Arch, Env}; pub use crate::config::*; use crate::prelude::*; @@ -185,7 +185,7 @@ fn target_config(&self, sess: &Session) -> TargetConfig { // won't be available when using a LLVM-built sysroot. let has_reliable_f16_f128 = !(sess.target.arch == Arch::X86_64 && sess.target.os == "windows" - && sess.target.env == "gnu" + && sess.target.env == Env::Gnu && sess.target.abi != Abi::Llvm); TargetConfig { From d1c33c3e84cf76e30e5b9b851da865fa8c948baa Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 5 Nov 2025 16:32:20 -0500 Subject: [PATCH 042/585] rustc_target: introduce Os Improve type safety by using an enum rather than strings. --- src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2175869085a3..5fdecd014ac0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,7 @@ use rustc_session::Session; use rustc_session::config::OutputFilenames; use rustc_span::{Symbol, sym}; -use rustc_target::spec::{Abi, Arch, Env}; +use rustc_target::spec::{Abi, Arch, Env, Os}; pub use crate::config::*; use crate::prelude::*; @@ -163,15 +163,15 @@ fn init(&self, sess: &Session) { fn target_config(&self, sess: &Session) -> TargetConfig { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] let target_features = match sess.target.arch { - Arch::X86_64 if sess.target.os != "none" => { + Arch::X86_64 if sess.target.os != Os::None => { // x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled vec![sym::fxsr, sym::sse, sym::sse2, Symbol::intern("x87")] } - Arch::AArch64 => match &*sess.target.os { - "none" => vec![], + Arch::AArch64 => match &sess.target.os { + Os::None => vec![], // On macOS the aes, sha2 and sha3 features are enabled by default and ring // fails to compile on macOS when they are not present. - "macos" => vec![sym::neon, sym::aes, sym::sha2, sym::sha3], + Os::MacOs => vec![sym::neon, sym::aes, sym::sha2, sym::sha3], // AArch64 mandates Neon support _ => vec![sym::neon], }, @@ -184,7 +184,7 @@ fn target_config(&self, sess: &Session) -> TargetConfig { // targets due to GCC using a different ABI than LLVM. Therefore `f16` and `f128` // won't be available when using a LLVM-built sysroot. let has_reliable_f16_f128 = !(sess.target.arch == Arch::X86_64 - && sess.target.os == "windows" + && sess.target.os == Os::Windows && sess.target.env == Env::Gnu && sess.target.abi != Abi::Llvm); From a7ee7c8cbef695faf8449d09c542d12127a6aba9 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Thu, 11 Sep 2025 15:09:21 +0000 Subject: [PATCH 043/585] slice iter: more cleanup --- library/core/src/slice/iter.rs | 110 +++++++++++++------------------ library/coretests/tests/slice.rs | 7 ++ 2 files changed, 52 insertions(+), 65 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 8ca78941a8a5..925910400ead 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1415,26 +1415,21 @@ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> DoubleEndedIterator for Windows<'a, T> { #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.size.get() > self.v.len() { - None - } else { - let ret = Some(&self.v[self.v.len() - self.size.get()..]); - self.v = &self.v[..self.v.len() - 1]; - ret - } + fn next_back(&mut self) -> Option { + self.nth_back(0) } #[inline] fn nth_back(&mut self, n: usize) -> Option { - let (end, overflow) = self.v.len().overflowing_sub(n); - if end < self.size.get() || overflow { + if let Some(end) = self.v.len().checked_sub(n) + && let Some(start) = end.checked_sub(self.size.get()) + { + let res = &self.v[start..end]; + self.v = &self.v[..end - 1]; + Some(res) + } else { self.v = &self.v[..0]; // cheaper than &[] None - } else { - let ret = &self.v[end - self.size.get()..end]; - self.v = &self.v[..end - 1]; - Some(ret) } } } @@ -1523,9 +1518,7 @@ fn size_hint(&self) -> (usize, Option) { if self.v.is_empty() { (0, Some(0)) } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; + let n = self.v.len().div_ceil(self.chunk_size); (n, Some(n)) } } @@ -1613,7 +1606,7 @@ fn nth_back(&mut self, n: usize) -> Option { None } else { let start = (len - 1 - n) * self.chunk_size; - let end = (start + self.chunk_size).min(self.v.len()); + let end = start + (self.v.len() - start).min(self.chunk_size); let nth_back = &self.v[start..end]; self.v = &self.v[..start]; Some(nth_back) @@ -1702,9 +1695,7 @@ fn size_hint(&self) -> (usize, Option) { if self.v.is_empty() { (0, Some(0)) } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; + let n = self.v.len().div_ceil(self.chunk_size); (n, Some(n)) } } @@ -1903,13 +1894,10 @@ impl<'a, T> Iterator for ChunksExact<'a, T> { #[inline] fn next(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.chunk_size); - self.v = snd; - Some(fst) - } + self.v.split_at_checked(self.chunk_size).and_then(|(chunk, rest)| { + self.v = rest; + Some(chunk) + }) } #[inline] @@ -1925,14 +1913,14 @@ fn count(self) -> usize { #[inline] fn nth(&mut self, n: usize) -> Option { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { + if let Some(start) = n.checked_mul(self.chunk_size) + && start < self.v.len() + { + self.v = &self.v[start..]; + self.next() + } else { self.v = &self.v[..0]; // cheaper than &[] None - } else { - let (_, snd) = self.v.split_at(start); - self.v = snd; - self.next() } } @@ -2061,15 +2049,11 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { #[inline] fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - // SAFETY: self.chunk_size is inbounds because we compared above against self.v.len() - let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) }; - self.v = tail; - // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *head }) - } + // SAFETY: we have `&mut self`, so are allowed to temporarily materialize a mut slice + unsafe { &mut *self.v }.split_at_mut_checked(self.chunk_size).and_then(|(chunk, rest)| { + self.v = rest; + Some(chunk) + }) } #[inline] @@ -2085,15 +2069,15 @@ fn count(self) -> usize { #[inline] fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { + if let Some(start) = n.checked_mul(self.chunk_size) + && start < self.v.len() + { + // SAFETY: `start < self.v.len()` + self.v = unsafe { self.v.split_at_mut(start).1 }; + self.next() + } else { self.v = &mut []; None - } else { - // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (_, snd) = unsafe { self.v.split_at_mut(start) }; - self.v = snd; - self.next() } } @@ -2341,9 +2325,7 @@ fn size_hint(&self) -> (usize, Option) { if self.v.is_empty() { (0, Some(0)) } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; + let n = self.v.len().div_ceil(self.chunk_size); (n, Some(n)) } } @@ -2355,17 +2337,17 @@ fn count(self) -> usize { #[inline] fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { + if let Some(end) = n.checked_mul(self.chunk_size) + && end < self.v.len() + { + let end = self.v.len() - end; + let rest = &self.v[..end]; + let (rest, chunk) = rest.split_at(end.saturating_sub(self.chunk_size)); + self.v = rest; + Some(chunk) + } else { self.v = &self.v[..0]; // cheaper than &[] None - } else { - // Can't underflow because of the check above - let end = self.v.len() - end; - let start = end.saturating_sub(self.chunk_size); - let nth = &self.v[start..end]; - self.v = &self.v[0..start]; - Some(nth) } } @@ -2508,9 +2490,7 @@ fn size_hint(&self) -> (usize, Option) { if self.v.is_empty() { (0, Some(0)) } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; + let n = self.v.len().div_ceil(self.chunk_size); (n, Some(n)) } } diff --git a/library/coretests/tests/slice.rs b/library/coretests/tests/slice.rs index 110c4e5f3b40..6f60f71e8a47 100644 --- a/library/coretests/tests/slice.rs +++ b/library/coretests/tests/slice.rs @@ -432,6 +432,13 @@ fn test_chunks_exact_mut_zip_aliasing() { assert_eq!(first, (&mut [0, 1][..], &[6, 7][..])); } +#[test] +fn test_chunks_zst() { + const SIZE: usize = 16; + let mut it = [(); usize::MAX].chunks(SIZE); + assert_eq!(it.nth_back(0), Some(&[(); SIZE - 1][..])); +} + #[test] fn test_rchunks_mut_zip_aliasing() { let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; From b60788e90534fdb6581ba2d8691ee636baf1981f Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Tue, 4 Nov 2025 07:39:34 +0000 Subject: [PATCH 044/585] slice iter: rm all overflowing_* and switch conditions to mv dependent code close --- library/core/src/slice/iter.rs | 136 ++++++++++++++++----------------- 1 file changed, 64 insertions(+), 72 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 925910400ead..8e972fefbe82 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1601,15 +1601,15 @@ fn next_back(&mut self) -> Option<&'a [T]> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &self.v[..0]; // cheaper than &[] - None - } else { + if n < len { let start = (len - 1 - n) * self.chunk_size; let end = start + (self.v.len() - start).min(self.chunk_size); let nth_back = &self.v[start..end]; self.v = &self.v[..start]; Some(nth_back) + } else { + self.v = &self.v[..0]; // cheaper than &[] + None } } } @@ -1770,10 +1770,7 @@ fn next_back(&mut self) -> Option<&'a mut [T]> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { + if n < len { let start = (len - 1 - n) * self.chunk_size; let end = match start.checked_add(self.chunk_size) { Some(res) => cmp::min(self.v.len(), res), @@ -1786,6 +1783,9 @@ fn nth_back(&mut self, n: usize) -> Option { self.v = head; // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth_back }) + } else { + self.v = &mut []; + None } } } @@ -1952,15 +1952,15 @@ fn next_back(&mut self) -> Option<&'a [T]> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &self.v[..0]; // cheaper than &[] - None - } else { + if n < len { let start = (len - 1 - n) * self.chunk_size; let end = start + self.chunk_size; let nth_back = &self.v[start..end]; self.v = &self.v[..start]; Some(nth_back) + } else { + self.v = &self.v[..0]; // cheaper than &[] + None } } } @@ -2111,10 +2111,7 @@ fn next_back(&mut self) -> Option<&'a mut [T]> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { + if n < len { let start = (len - 1 - n) * self.chunk_size; let end = start + self.chunk_size; // SAFETY: The self.v contract ensures that any split_at_mut is valid. @@ -2124,6 +2121,9 @@ fn nth_back(&mut self, n: usize) -> Option { self.v = head; // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth_back }) + } else { + self.v = &mut []; + None } } } @@ -2307,16 +2307,12 @@ fn next(&mut self) -> Option<&'a [T]> { if self.v.is_empty() { None } else { - let len = self.v.len(); - let chunksz = cmp::min(len, self.chunk_size); - // SAFETY: split_at_unchecked just requires the argument be less - // than the length. This could only happen if the expression `len - - // chunksz` overflows. This could only happen if `chunksz > len`, - // which is impossible as we initialize it as the `min` of `len` and - // `self.chunk_size`. - let (fst, snd) = unsafe { self.v.split_at_unchecked(len - chunksz) }; - self.v = fst; - Some(snd) + let idx = self.v.len().saturating_sub(self.chunk_size); + // SAFETY: self.chunk_size() > 0, so 0 <= idx < self.v.len(). + // Thus `idx` is in-bounds for `self.v` and can be used as a valid argument for `split_at_mut_unchecked`. + let (rest, chunk) = unsafe { self.v.split_at_unchecked(idx) }; + self.v = rest; + Some(chunk) } } @@ -2389,17 +2385,16 @@ fn next_back(&mut self) -> Option<&'a [T]> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &self.v[..0]; // cheaper than &[] - None - } else { - // can't underflow because `n < len` + if n < len { let offset_from_end = (len - 1 - n) * self.chunk_size; let end = self.v.len() - offset_from_end; let start = end.saturating_sub(self.chunk_size); let nth_back = &self.v[start..end]; self.v = &self.v[end..]; Some(nth_back) + } else { + self.v = &self.v[..0]; // cheaper than &[] + None } } } @@ -2471,17 +2466,13 @@ fn next(&mut self) -> Option<&'a mut [T]> { if self.v.is_empty() { None } else { - let sz = cmp::min(self.v.len(), self.chunk_size); - let len = self.v.len(); - // SAFETY: split_at_mut_unchecked just requires the argument be less - // than the length. This could only happen if the expression - // `len - sz` overflows. This could only happen if `sz > - // len`, which is impossible as we initialize it as the `min` of - // `self.v.len()` (e.g. `len`) and `self.chunk_size`. - let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) }; - self.v = head; + let idx = self.v.len().saturating_sub(self.chunk_size); + // SAFETY: self.chunk_size() > 0, so 0 <= idx < self.v.len(). + // Thus `idx` is in-bounds for `self.v` and can be used as a valid argument for `split_at_mut_unchecked`. + let (rest, chunk) = unsafe { self.v.split_at_mut_unchecked(idx) }; + self.v = rest; // SAFETY: Nothing else points to or will point to the contents of this slice. - Some(unsafe { &mut *tail }) + Some(unsafe { &mut *chunk }) } } @@ -2502,12 +2493,9 @@ fn count(self) -> usize { #[inline] fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - // Can't underflow because of the check above + if let Some(end) = n.checked_mul(self.chunk_size) + && end < self.v.len() + { let end = self.v.len() - end; let start = match end.checked_sub(self.chunk_size) { Some(sum) => sum, @@ -2522,6 +2510,9 @@ fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { self.v = head; // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth }) + } else { + self.v = &mut []; + None } } @@ -2566,10 +2557,7 @@ fn next_back(&mut self) -> Option<&'a mut [T]> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { + if n < len { // can't underflow because `n < len` let offset_from_end = (len - 1 - n) * self.chunk_size; let end = self.v.len() - offset_from_end; @@ -2581,6 +2569,9 @@ fn nth_back(&mut self, n: usize) -> Option { self.v = tail; // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth_back }) + } else { + self.v = &mut []; + None } } } @@ -2711,14 +2702,14 @@ fn count(self) -> usize { #[inline] fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { + if let Some(end) = n.checked_mul(self.chunk_size) + && end < self.v.len() + { + self.v = &self.v[..self.v.len() - end]; + self.next() + } else { self.v = &self.v[..0]; // cheaper than &[] None - } else { - let (fst, _) = self.v.split_at(self.v.len() - end); - self.v = fst; - self.next() } } @@ -2751,10 +2742,7 @@ fn next_back(&mut self) -> Option<&'a [T]> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &self.v[..0]; // cheaper than &[] - None - } else { + if n < len { // now that we know that `n` corresponds to a chunk, // none of these operations can underflow/overflow let offset = (len - n) * self.chunk_size; @@ -2763,6 +2751,9 @@ fn nth_back(&mut self, n: usize) -> Option { let nth_back = &self.v[start..end]; self.v = &self.v[end..]; Some(nth_back) + } else { + self.v = &self.v[..0]; // cheaper than &[] + None } } } @@ -2875,16 +2866,17 @@ fn count(self) -> usize { #[inline] fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - let len = self.v.len(); + if let Some(end) = n.checked_mul(self.chunk_size) + && end < self.v.len() + { + let idx = self.v.len() - end; // SAFETY: The self.v contract ensures that any split_at_mut is valid. - let (fst, _) = unsafe { self.v.split_at_mut(len - end) }; + let (fst, _) = unsafe { self.v.split_at_mut(idx) }; self.v = fst; self.next() + } else { + self.v = &mut []; + None } } @@ -2919,10 +2911,7 @@ fn next_back(&mut self) -> Option<&'a mut [T]> { #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { + if n < len { // now that we know that `n` corresponds to a chunk, // none of these operations can underflow/overflow let offset = (len - n) * self.chunk_size; @@ -2935,6 +2924,9 @@ fn nth_back(&mut self, n: usize) -> Option { self.v = tail; // SAFETY: Nothing else points to or will point to the contents of this slice. Some(unsafe { &mut *nth_back }) + } else { + self.v = &mut []; + None } } } From a842469f0d7ac75d92464ecd1b5b7cef289e0bed Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Nov 2025 16:08:59 +0000 Subject: [PATCH 045/585] Adjust for rust-lang/rust default branch rename --- scripts/rustup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/rustup.sh b/scripts/rustup.sh index fdfd03029b16..1a82193303e2 100755 --- a/scripts/rustup.sh +++ b/scripts/rustup.sh @@ -43,7 +43,7 @@ case $1 in cg_clif=$(pwd) pushd ../rust - git pull origin master + git pull origin main branch=sync_cg_clif-$(date +%Y-%m-%d) git checkout -b "$branch" "$cg_clif/git-fixed-subtree.sh" pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/rust-lang/rustc_codegen_cranelift.git main @@ -63,7 +63,7 @@ case $1 in cg_clif=$(pwd) pushd ../rust - git fetch origin master + git fetch origin main git -c advice.detachedHead=false checkout "$RUST_VERS" "$cg_clif/git-fixed-subtree.sh" push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust popd From 614349ab2cf3a7a9afee52dc6ed50ab0914a5fbd Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Nov 2025 16:18:36 +0000 Subject: [PATCH 046/585] Rustup to rustc 1.93.0-nightly (b6d7ff3aa 2025-11-14) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 17c2cc5ac660..3aeb07e469a3 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-11-08" +channel = "nightly-2025-11-15" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 95b5bbac7ca87573d35d1cde09f938f577dd3a4a Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Thu, 13 Nov 2025 23:00:13 -0800 Subject: [PATCH 047/585] Fix division syntax in doc comments `mod` is a keyword in Rust, and since we're talking about remainders we should be using division syntax here. --- library/core/src/num/f128.rs | 3 ++- library/core/src/num/f16.rs | 3 ++- library/core/src/num/int_macros.rs | 3 ++- library/core/src/num/uint_macros.rs | 3 ++- library/std/src/num/f32.rs | 3 ++- library/std/src/num/f64.rs | 3 ++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index e7101537b298..50b8cd56e914 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1704,7 +1704,8 @@ pub fn div_euclid(self, rhs: f128) -> f128 { q } - /// Calculates the least nonnegative remainder of `self (mod rhs)`. + /// Calculates the least nonnegative remainder of `self` when + /// divided by `rhs`. /// /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in /// most cases. However, due to a floating point round-off error it can diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index aa8342a22ad5..80342c27802f 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1679,7 +1679,8 @@ pub fn div_euclid(self, rhs: f16) -> f16 { q } - /// Calculates the least nonnegative remainder of `self (mod rhs)`. + /// Calculates the least nonnegative remainder of `self` when + /// divided by `rhs`. /// /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in /// most cases. However, due to a floating point round-off error it can diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 70e764de9069..ab75074ca66b 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -3124,7 +3124,8 @@ pub const fn div_euclid(self, rhs: Self) -> Self { } - /// Calculates the least nonnegative remainder of `self (mod rhs)`. + /// Calculates the least nonnegative remainder of `self` when + /// divided by `rhs`. /// /// This is done as if by the Euclidean division algorithm -- given /// `r = self.rem_euclid(rhs)`, the result satisfies diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index d38d3a1a5ad4..5720df816093 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -3399,7 +3399,8 @@ pub const fn div_euclid(self, rhs: Self) -> Self { } - /// Calculates the least remainder of `self (mod rhs)`. + /// Calculates the least remainder of `self` when divided by + /// `rhs`. /// /// Since, for the positive integers, all common /// definitions of division are equal, this diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index c9e192201aff..0d209b051f4a 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -252,7 +252,8 @@ pub fn div_euclid(self, rhs: f32) -> f32 { core::f32::math::div_euclid(self, rhs) } - /// Calculates the least nonnegative remainder of `self (mod rhs)`. + /// Calculates the least nonnegative remainder of `self` when divided by + /// `rhs`. /// /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in /// most cases. However, due to a floating point round-off error it can diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 11874f9280f0..43de685ad8ba 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -252,7 +252,8 @@ pub fn div_euclid(self, rhs: f64) -> f64 { core::f64::math::div_euclid(self, rhs) } - /// Calculates the least nonnegative remainder of `self (mod rhs)`. + /// Calculates the least nonnegative remainder of `self` when divided by + /// `rhs`. /// /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in /// most cases. However, due to a floating point round-off error it can From ee16aed94c380d031f757c6552eca1afecb0245e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 Jun 2025 09:03:40 +0000 Subject: [PATCH 048/585] Fortify test. --- ...g.aggregate.JumpThreading.panic-abort.diff | 53 +++++++++---------- ....aggregate.JumpThreading.panic-unwind.diff | 53 +++++++++---------- tests/mir-opt/jump_threading.rs | 37 ++++++++++++- 3 files changed, 87 insertions(+), 56 deletions(-) diff --git a/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-abort.diff index a7551c3fb5b7..89d04c557f12 100644 --- a/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-abort.diff @@ -1,51 +1,50 @@ - // MIR for `aggregate` before JumpThreading + // MIR for `aggregate` after JumpThreading - fn aggregate(_1: u8) -> u8 { - debug x => _1; + fn aggregate() -> u8 { let mut _0: u8; + let _1: u8; let _2: u8; - let _3: u8; - let mut _4: (u8, u8); - let mut _5: bool; - let mut _6: u8; + let mut _3: (u8, u8); + let mut _4: bool; + let mut _5: u8; scope 1 { - debug a => _2; - debug b => _3; + debug a => _1; + debug b => _2; } bb0: { - StorageLive(_4); - _4 = const aggregate::FOO; - StorageLive(_2); - _2 = copy (_4.0: u8); StorageLive(_3); - _3 = copy (_4.1: u8); - StorageDead(_4); + _3 = const aggregate::FOO; + StorageLive(_1); + _1 = copy (_3.0: u8); + StorageLive(_2); + _2 = copy (_3.1: u8); + StorageDead(_3); + StorageLive(_4); StorageLive(_5); - StorageLive(_6); - _6 = copy _2; - _5 = Eq(move _6, const 7_u8); -- switchInt(move _5) -> [0: bb2, otherwise: bb1]; + _5 = copy _1; + _4 = Eq(move _5, const 7_u8); +- switchInt(move _4) -> [0: bb2, otherwise: bb1]; + goto -> bb2; } bb1: { - StorageDead(_6); - _0 = copy _3; - goto -> bb3; - } - - bb2: { - StorageDead(_6); + StorageDead(_5); _0 = copy _2; goto -> bb3; } - bb3: { + bb2: { StorageDead(_5); - StorageDead(_3); + _0 = copy _1; + goto -> bb3; + } + + bb3: { + StorageDead(_4); StorageDead(_2); + StorageDead(_1); return; } } diff --git a/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-unwind.diff index a7551c3fb5b7..89d04c557f12 100644 --- a/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-unwind.diff @@ -1,51 +1,50 @@ - // MIR for `aggregate` before JumpThreading + // MIR for `aggregate` after JumpThreading - fn aggregate(_1: u8) -> u8 { - debug x => _1; + fn aggregate() -> u8 { let mut _0: u8; + let _1: u8; let _2: u8; - let _3: u8; - let mut _4: (u8, u8); - let mut _5: bool; - let mut _6: u8; + let mut _3: (u8, u8); + let mut _4: bool; + let mut _5: u8; scope 1 { - debug a => _2; - debug b => _3; + debug a => _1; + debug b => _2; } bb0: { - StorageLive(_4); - _4 = const aggregate::FOO; - StorageLive(_2); - _2 = copy (_4.0: u8); StorageLive(_3); - _3 = copy (_4.1: u8); - StorageDead(_4); + _3 = const aggregate::FOO; + StorageLive(_1); + _1 = copy (_3.0: u8); + StorageLive(_2); + _2 = copy (_3.1: u8); + StorageDead(_3); + StorageLive(_4); StorageLive(_5); - StorageLive(_6); - _6 = copy _2; - _5 = Eq(move _6, const 7_u8); -- switchInt(move _5) -> [0: bb2, otherwise: bb1]; + _5 = copy _1; + _4 = Eq(move _5, const 7_u8); +- switchInt(move _4) -> [0: bb2, otherwise: bb1]; + goto -> bb2; } bb1: { - StorageDead(_6); - _0 = copy _3; - goto -> bb3; - } - - bb2: { - StorageDead(_6); + StorageDead(_5); _0 = copy _2; goto -> bb3; } - bb3: { + bb2: { StorageDead(_5); - StorageDead(_3); + _0 = copy _1; + goto -> bb3; + } + + bb3: { + StorageDead(_4); StorageDead(_2); + StorageDead(_1); return; } } diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index 009e1060700c..b1d9602bd46c 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -449,9 +449,17 @@ fn disappearing_bb(x: u8) -> u8 { } /// Verify that we can thread jumps when we assign from an aggregate constant. -fn aggregate(x: u8) -> u8 { +fn aggregate() -> u8 { // CHECK-LABEL: fn aggregate( + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; // CHECK-NOT: switchInt( + // CHECK: [[a2:_.*]] = copy [[a]]; + // CHECK: {{_.*}} = Eq(move [[a2]], const 7_u8); + // CHECK-NEXT: goto -> [[bb:bb.*]]; + // CHECK: [[bb]]: { + // CHECK-NOT: } + // CHECK: _0 = copy [[a]]; const FOO: (u8, u8) = (5, 13); @@ -508,7 +516,16 @@ fn assume(a: u8, b: bool) -> u8 { /// Verify that jump threading succeeds seeing through copies of aggregates. fn aggregate_copy() -> u32 { // CHECK-LABEL: fn aggregate_copy( + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: debug c => [[c:_.*]]; // CHECK-NOT: switchInt( + // CHECK: [[c2:_.*]] = copy [[c]]; + // CHECK: {{_.*}} = Eq(move [[c2]], const 2_u32); + // CHECK-NEXT: goto -> [[bb:bb.*]]; + // CHECK: [[bb]]: { + // CHECK-NOT: } + // CHECK: _0 = const 13_u32; const Foo: (u32, u32) = (5, 3); @@ -532,6 +549,14 @@ fn floats() -> u32 { pub fn bitwise_not() -> i32 { // CHECK-LABEL: fn bitwise_not( + // CHECK: debug a => [[a:_.*]]; + // CHECK: [[a2:_.*]] = copy [[a]]; + // CHECK: [[not:_.*]] = Not(move [[a2]]); + // CHECK: {{_.*}} = Eq(move [[not]], const 0_i32); + // CHECK-NEXT: goto -> [[bb:bb.*]]; + // CHECK: [[bb]]: { + // CHECK-NOT: } + // CHECK: _0 = const 0_i32; // Test for #131195, which was optimizing `!a == b` into `a != b`. let a = 1; @@ -540,6 +565,14 @@ pub fn bitwise_not() -> i32 { pub fn logical_not() -> i32 { // CHECK-LABEL: fn logical_not( + // CHECK: debug a => [[a:_.*]]; + // CHECK: [[a2:_.*]] = copy [[a]]; + // CHECK: [[not:_.*]] = Not(move [[a2]]); + // CHECK: {{_.*}} = Eq(move [[not]], const true); + // CHECK-NEXT: goto -> [[bb:bb.*]]; + // CHECK: [[bb]]: { + // CHECK-NOT: } + // CHECK: _0 = const 1_i32; let a = false; if !a == true { 1 } else { 0 } @@ -557,7 +590,7 @@ fn main() { mutable_ref(); renumbered_bb(true); disappearing_bb(7); - aggregate(7); + aggregate(); assume(7, false); floats(); bitwise_not(); From bd8db4548e5aaf36a6387415cd0834e3ef5c30c9 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 21 Sep 2025 02:10:54 +0000 Subject: [PATCH 049/585] Add tests. --- tests/mir-opt/jump_threading.rs | 27 +++++++++ ...g.two_reads.JumpThreading.panic-abort.diff | 55 +++++++++++++++++++ ....two_reads.JumpThreading.panic-unwind.diff | 55 +++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-abort.diff create mode 100644 tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-unwind.diff diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index b1d9602bd46c..ab8840db3837 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -77,6 +77,32 @@ fn identity(x: Result) -> Result { Ok(x?) } +fn two_reads() -> i32 { + // CHECK-LABEL: fn two_reads( + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: debug c => [[c:_.*]]; + // CHECK: bb0: { + // CHECK: [[a]] = const 2_i32; + // CHECK: [[b]] = copy [[a]]; + // CHECK: [[c]] = copy [[a]]; + // CHECK: [[tmp:_.*]] = copy [[c]]; + // CHECK: [[eq:_.*]] = Eq(move [[tmp]], const 2_i32); + // CHECK: switchInt(move [[eq]]) -> [0: bb2, otherwise: bb1]; + // CHECK: bb1: { + // CHECK: _0 = const 0_i32; + // CHECK: goto -> bb3; + // CHECK: bb2: { + // CHECK: _0 = const 1_i32; + // CHECK: goto -> bb3; + // CHECK: bb3: { + // CHECK: return; + let a = 2; + let b = a; + let c = a; + if c == 2 { 0 } else { 1 } +} + enum DFA { A, B, @@ -599,6 +625,7 @@ fn main() { // EMIT_MIR jump_threading.too_complex.JumpThreading.diff // EMIT_MIR jump_threading.identity.JumpThreading.diff +// EMIT_MIR jump_threading.two_reads.JumpThreading.diff // EMIT_MIR jump_threading.custom_discr.JumpThreading.diff // EMIT_MIR jump_threading.dfa.JumpThreading.diff // EMIT_MIR jump_threading.multiple_match.JumpThreading.diff diff --git a/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-abort.diff new file mode 100644 index 000000000000..9962a5724b3f --- /dev/null +++ b/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-abort.diff @@ -0,0 +1,55 @@ +- // MIR for `two_reads` before JumpThreading ++ // MIR for `two_reads` after JumpThreading + + fn two_reads() -> i32 { + let mut _0: i32; + let _1: i32; + let mut _4: bool; + let mut _5: i32; + scope 1 { + debug a => _1; + let _2: i32; + scope 2 { + debug b => _2; + let _3: i32; + scope 3 { + debug c => _3; + } + } + } + + bb0: { + StorageLive(_1); + _1 = const 2_i32; + StorageLive(_2); + _2 = copy _1; + StorageLive(_3); + _3 = copy _1; + StorageLive(_4); + StorageLive(_5); + _5 = copy _3; + _4 = Eq(move _5, const 2_i32); + switchInt(move _4) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + StorageDead(_5); + _0 = const 0_i32; + goto -> bb3; + } + + bb2: { + StorageDead(_5); + _0 = const 1_i32; + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-unwind.diff new file mode 100644 index 000000000000..9962a5724b3f --- /dev/null +++ b/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-unwind.diff @@ -0,0 +1,55 @@ +- // MIR for `two_reads` before JumpThreading ++ // MIR for `two_reads` after JumpThreading + + fn two_reads() -> i32 { + let mut _0: i32; + let _1: i32; + let mut _4: bool; + let mut _5: i32; + scope 1 { + debug a => _1; + let _2: i32; + scope 2 { + debug b => _2; + let _3: i32; + scope 3 { + debug c => _3; + } + } + } + + bb0: { + StorageLive(_1); + _1 = const 2_i32; + StorageLive(_2); + _2 = copy _1; + StorageLive(_3); + _3 = copy _1; + StorageLive(_4); + StorageLive(_5); + _5 = copy _3; + _4 = Eq(move _5, const 2_i32); + switchInt(move _4) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + StorageDead(_5); + _0 = const 0_i32; + goto -> bb3; + } + + bb2: { + StorageDead(_5); + _0 = const 1_i32; + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + return; + } + } + From 4f24d70395f8677e682016cfe3713c0bfedc4df0 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 21 Sep 2025 02:12:06 +0000 Subject: [PATCH 050/585] Extend value_analysis API. --- .../rustc_mir_dataflow/src/value_analysis.rs | 70 +++++++++++++------ 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index bf5ec8f459e6..969e9b3a4dd8 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -24,9 +24,7 @@ pub struct PlaceIndex {} rustc_index::newtype_index!( /// This index uniquely identifies a tracked place and therefore a slot in [`State`]. - /// - /// It is an implementation detail of this module. - struct ValueIndex {} + pub struct ValueIndex {} ); /// See [`State`]. @@ -211,22 +209,9 @@ pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map<'_>) /// The target place must have been flooded before calling this method. pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map<'_>) { let State::Reachable(values) = self else { return }; - - // If both places are tracked, we copy the value to the target. - // If the target is tracked, but the source is not, we do nothing, as invalidation has - // already been performed. - if let Some(target_value) = map.places[target].value_index - && let Some(source_value) = map.places[source].value_index - { - values.insert(target_value, values.get(source_value).clone()); - } - for target_child in map.children(target) { - // Try to find corresponding child and recurse. Reasoning is similar as above. - let projection = map.places[target_child].proj_elem.unwrap(); - if let Some(source_child) = map.projections.get(&(source, projection)) { - self.insert_place_idx(target_child, *source_child, map); - } - } + map.for_each_value_pair(target, source, &mut |target, source| { + values.insert(target, values.get(source).clone()); + }); } /// Helper method to interpret `target = result`. @@ -677,6 +662,26 @@ pub fn find_len(&self, place: PlaceRef<'_>) -> Option { self.find_extra(place, [TrackElem::DerefLen]) } + /// Locates the value corresponding to the given place. + pub fn value(&self, place: PlaceIndex) -> Option { + self.places[place].value_index + } + + /// Locates the value corresponding to the given place. + pub fn find_value(&self, place: PlaceRef<'_>) -> Option { + self.value(self.find(place)?) + } + + /// Locates the value corresponding to the given discriminant. + pub fn find_discr_value(&self, place: PlaceRef<'_>) -> Option { + self.value(self.find_discr(place)?) + } + + /// Locates the value corresponding to the given length. + pub fn find_len_value(&self, place: PlaceRef<'_>) -> Option { + self.value(self.find_len(place)?) + } + /// Iterate over all direct children. fn children(&self, parent: PlaceIndex) -> impl Iterator { Children::new(self, parent) @@ -689,7 +694,7 @@ fn children(&self, parent: PlaceIndex) -> impl Iterator { /// /// `tail_elem` allows to support discriminants that are not a place in MIR, but that we track /// as such. - fn for_each_aliasing_place( + pub fn for_each_aliasing_place( &self, place: PlaceRef<'_>, tail_elem: Option, @@ -778,6 +783,31 @@ pub fn for_each_projection_value( } } } + + /// Recursively iterates on each value contained in `target`, paired with matching projection + /// inside `source`. + pub fn for_each_value_pair( + &self, + target: PlaceIndex, + source: PlaceIndex, + f: &mut impl FnMut(ValueIndex, ValueIndex), + ) { + // If both places are tracked, we copy the value to the target. + // If the target is tracked, but the source is not, we do nothing, as invalidation has + // already been performed. + if let Some(target_value) = self.places[target].value_index + && let Some(source_value) = self.places[source].value_index + { + f(target_value, source_value) + } + for target_child in self.children(target) { + // Try to find corresponding child and recurse. Reasoning is similar as above. + let projection = self.places[target_child].proj_elem.unwrap(); + if let Some(source_child) = self.projections.get(&(source, projection)) { + self.for_each_value_pair(target_child, *source_child, f); + } + } + } } /// This is the information tracked for every [`PlaceIndex`] and is stored by [`Map`]. From d67e3e6c5a8046cda3343781ed4459c9a1be8811 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 19 Jun 2025 22:42:05 +0000 Subject: [PATCH 051/585] Use a simpler condition set in jump threading. --- .../rustc_mir_transform/src/jump_threading.rs | 249 +++++++++++------- tests/coverage/conditions.cov-map | 246 ++++++++--------- tests/mir-opt/jump_threading.rs | 2 +- ...g.two_reads.JumpThreading.panic-abort.diff | 3 +- ....two_reads.JumpThreading.panic-unwind.diff | 3 +- 5 files changed, 262 insertions(+), 241 deletions(-) diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 492f5ca82a07..9b420ab18112 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -38,7 +38,7 @@ use rustc_arena::DroplessArena; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; use rustc_middle::bug; @@ -47,7 +47,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, ScalarInt, TyCtxt}; use rustc_mir_dataflow::lattice::HasBottom; -use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, State, TrackElem}; +use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, TrackElem, ValueIndex}; use rustc_span::DUMMY_SP; use tracing::{debug, instrument, trace}; @@ -134,6 +134,7 @@ struct TOFinder<'a, 'tcx> { /// to `value`, jump to `target`. #[derive(Copy, Clone, Debug)] struct Condition { + place: ValueIndex, value: ScalarInt, polarity: Polarity, target: BasicBlock, @@ -146,8 +147,14 @@ enum Polarity { } impl Condition { - fn matches(&self, value: ScalarInt) -> bool { - (self.value == value) == (self.polarity == Polarity::Eq) + fn matches(&self, place: ValueIndex, value: ScalarInt) -> bool { + self.place == place && (self.value == value) == (self.polarity == Polarity::Eq) + } + + fn into_opportunity(self, match_bb: Option) -> ThreadingOpportunity { + trace!(?self, "registering"); + let chain = match_bb.into_iter().collect(); + ThreadingOpportunity { chain, target: self.target } } } @@ -163,29 +170,50 @@ fn is_bottom(&self) -> bool { } impl<'a> ConditionSet<'a> { + fn is_empty(self) -> bool { + self.0.is_empty() + } + fn iter(self) -> impl Iterator { self.0.iter().copied() } - fn iter_matches(self, value: ScalarInt) -> impl Iterator { - self.iter().filter(move |c| c.matches(value)) + fn iter_matches(self, place: ValueIndex, value: ScalarInt) -> impl Iterator { + self.iter().filter(move |c| c.matches(place, value)) } - fn map( + fn register_matches( + &self, + place: ValueIndex, + value: ScalarInt, + match_bb: Option, + opportunities: &mut Vec, + ) { + self.iter_matches(place, value) + .for_each(|cond| opportunities.push(cond.into_opportunity(match_bb))) + } + + fn filter(self, arena: &'a DroplessArena, f: impl Fn(Condition) -> bool) -> ConditionSet<'a> { + let set = arena.alloc_from_iter(self.iter().filter(|&c| f(c))); + ConditionSet(set) + } + + fn filter_map( self, arena: &'a DroplessArena, f: impl Fn(Condition) -> Option, - ) -> Option> { - let set = arena.try_alloc_from_iter(self.iter().map(|c| f(c).ok_or(()))).ok()?; - Some(ConditionSet(set)) + ) -> ConditionSet<'a> { + let set = arena.alloc_from_iter(self.iter().filter_map(|c| f(c))); + ConditionSet(set) + } + + fn map(self, arena: &'a DroplessArena, f: impl Fn(Condition) -> Condition) -> ConditionSet<'a> { + let set = arena.alloc_from_iter(self.iter().map(|c| f(c))); + ConditionSet(set) } } impl<'a, 'tcx> TOFinder<'a, 'tcx> { - fn is_empty(&self, state: &State>) -> bool { - state.all_bottom() - } - /// Recursion entry point to find threading opportunities. #[instrument(level = "trace", skip(self))] fn start_from_switch(&mut self, bb: BasicBlock) { @@ -200,27 +228,24 @@ fn start_from_switch(&mut self, bb: BasicBlock) { let discr_ty = discr.ty(self.body, self.tcx).ty; let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return }; - let Some(discr) = self.map.find(discr.as_ref()) else { return }; + let Some(discr) = self.map.find_value(discr.as_ref()) else { return }; debug!(?discr); let cost = CostChecker::new(self.tcx, self.typing_env, None, self.body); - let mut state = State::new_reachable(); let conds = if let Some((value, then, else_)) = targets.as_static_if() { let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) else { return }; self.arena.alloc_from_iter([ - Condition { value, polarity: Polarity::Eq, target: then }, - Condition { value, polarity: Polarity::Ne, target: else_ }, + Condition { place: discr, value, polarity: Polarity::Eq, target: then }, + Condition { place: discr, value, polarity: Polarity::Ne, target: else_ }, ]) } else { self.arena.alloc_from_iter(targets.iter().filter_map(|(value, target)| { let value = ScalarInt::try_from_uint(value, discr_layout.size)?; - Some(Condition { value, polarity: Polarity::Eq, target }) + Some(Condition { place: discr, value, polarity: Polarity::Eq, target }) })) }; - let conds = ConditionSet(conds); - state.insert_value_idx(discr, conds, &self.map); - + let state = ConditionSet(conds); self.find_opportunity(bb, state, cost, 0) } @@ -230,7 +255,7 @@ fn start_from_switch(&mut self, bb: BasicBlock) { fn find_opportunity( &mut self, bb: BasicBlock, - mut state: State>, + mut state: ConditionSet<'a>, mut cost: CostChecker<'_, 'tcx>, depth: usize, ) { @@ -243,7 +268,7 @@ fn find_opportunity( for (statement_index, stmt) in self.body.basic_blocks[bb].statements.iter().enumerate().rev() { - if self.is_empty(&state) { + if state.is_empty() { return; } @@ -260,11 +285,11 @@ fn find_opportunity( // _1 = 5 // Whatever happens here, it won't change the result of a `SwitchInt`. // _1 = 6 if let Some((lhs, tail)) = self.mutated_statement(stmt) { - state.flood_with_tail_elem(lhs.as_ref(), tail, &self.map, ConditionSet::BOTTOM); + self.flood_state(lhs, tail, &mut state); } } - if self.is_empty(&state) || depth >= MAX_BACKTRACK { + if state.is_empty() || depth >= MAX_BACKTRACK { return; } @@ -280,13 +305,13 @@ fn find_opportunity( self.process_switch_int(discr, targets, bb, &mut state); self.find_opportunity(pred, state, cost, depth + 1); } - _ => self.recurse_through_terminator(pred, || state, &cost, depth), + _ => self.recurse_through_terminator(pred, state, &cost, depth), } } else if let &[ref predecessors @ .., last_pred] = &predecessors[..] { for &pred in predecessors { - self.recurse_through_terminator(pred, || state.clone(), &cost, depth); + self.recurse_through_terminator(pred, state, &cost, depth); } - self.recurse_through_terminator(last_pred, || state, &cost, depth); + self.recurse_through_terminator(last_pred, state, &cost, depth); } let new_tos = &mut self.opportunities[last_non_rec..]; @@ -313,6 +338,23 @@ fn find_opportunity( } } + /// Remove all conditions in the state that alias given place. + fn flood_state( + &self, + place: Place<'tcx>, + extra_elem: Option, + state: &mut ConditionSet<'a>, + ) { + let mut places_to_exclude = FxHashSet::default(); + self.map.for_each_aliasing_place(place.as_ref(), extra_elem, &mut |vi| { + places_to_exclude.insert(vi); + }); + if places_to_exclude.is_empty() { + return; + } + *state = state.filter(self.arena, |c| !places_to_exclude.contains(&c.place)); + } + /// Extract the mutated place from a statement. /// /// This method returns the `Place` so we can flood the state in case of a partial assignment. @@ -359,17 +401,12 @@ fn process_immediate( bb: BasicBlock, lhs: PlaceIndex, rhs: ImmTy<'tcx>, - state: &mut State>, + state: &mut ConditionSet<'a>, ) { - let register_opportunity = |c: Condition| { - debug!(?bb, ?c.target, "register"); - self.opportunities.push(ThreadingOpportunity { chain: vec![bb], target: c.target }) - }; - - if let Some(conditions) = state.try_get_idx(lhs, &self.map) + if let Some(lhs) = self.map.value(lhs) && let Immediate::Scalar(Scalar::Int(int)) = *rhs { - conditions.iter_matches(int).for_each(register_opportunity); + state.register_matches(lhs, int, Some(bb), &mut self.opportunities); } } @@ -380,7 +417,7 @@ fn process_constant( bb: BasicBlock, lhs: PlaceIndex, constant: OpTy<'tcx>, - state: &mut State>, + state: &mut ConditionSet<'a>, ) { self.map.for_each_projection_value( lhs, @@ -402,27 +439,38 @@ fn process_constant( } }, &mut |place, op| { - if let Some(conditions) = state.try_get_idx(place, &self.map) + if let Some(place) = self.map.value(place) && let Some(imm) = self.ecx.read_immediate_raw(op).discard_err() && let Some(imm) = imm.right() && let Immediate::Scalar(Scalar::Int(int)) = *imm { - conditions.iter_matches(int).for_each(|c: Condition| { - self.opportunities - .push(ThreadingOpportunity { chain: vec![bb], target: c.target }) - }) + state.register_matches(place, int, Some(bb), &mut self.opportunities); } }, ); } + #[instrument(level = "trace", skip(self))] + fn process_copy(&mut self, lhs: PlaceIndex, rhs: PlaceIndex, state: &mut ConditionSet<'a>) { + let mut renames = FxHashMap::default(); + self.map.for_each_value_pair(rhs, lhs, &mut |rhs, lhs| { + renames.insert(lhs, rhs); + }); + *state = state.map(self.arena, |mut c| { + if let Some(rhs) = renames.get(&c.place) { + c.place = *rhs + } + c + }); + } + #[instrument(level = "trace", skip(self))] fn process_operand( &mut self, bb: BasicBlock, lhs: PlaceIndex, rhs: &Operand<'tcx>, - state: &mut State>, + state: &mut ConditionSet<'a>, ) { match rhs { // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. @@ -437,7 +485,7 @@ fn process_operand( // Transfer the conditions on the copied rhs. Operand::Move(rhs) | Operand::Copy(rhs) => { let Some(rhs) = self.map.find(rhs.as_ref()) else { return }; - state.insert_place_idx(rhs, lhs, &self.map); + self.process_copy(lhs, rhs, state) } } } @@ -447,16 +495,16 @@ fn process_assign( &mut self, bb: BasicBlock, lhs_place: &Place<'tcx>, - rhs: &Rvalue<'tcx>, - state: &mut State>, + rvalue: &Rvalue<'tcx>, + state: &mut ConditionSet<'a>, ) { let Some(lhs) = self.map.find(lhs_place.as_ref()) else { return }; - match rhs { + match rvalue { Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state), // Transfer the conditions on the copy rhs. Rvalue::Discriminant(rhs) => { let Some(rhs) = self.map.find_discr(rhs.as_ref()) else { return }; - state.insert_place_idx(rhs, lhs, &self.map); + self.process_copy(lhs, rhs, state) } // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. Rvalue::Aggregate(box kind, operands) => { @@ -488,32 +536,30 @@ fn process_assign( } } // Transfer the conditions on the copy rhs, after inverting the value of the condition. - Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => { - let layout = self.ecx.layout_of(place.ty(self.body, self.tcx).ty).unwrap(); - let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return }; - let Some(place) = self.map.find(place.as_ref()) else { return }; - let Some(conds) = conditions.map(self.arena, |mut cond| { - cond.value = self - .ecx - .unary_op(UnOp::Not, &ImmTy::from_scalar_int(cond.value, layout)) - .discard_err()? - .to_scalar_int() - .discard_err()?; + Rvalue::UnaryOp(UnOp::Not, Operand::Move(operand) | Operand::Copy(operand)) => { + let layout = self.ecx.layout_of(operand.ty(self.body, self.tcx).ty).unwrap(); + let Some(lhs) = self.map.value(lhs) else { return }; + let Some(operand) = self.map.find_value(operand.as_ref()) else { return }; + *state = state.filter_map(self.arena, |mut cond| { + if cond.place == lhs { + cond.place = operand; + cond.value = self + .ecx + .unary_op(UnOp::Not, &ImmTy::from_scalar_int(cond.value, layout)) + .discard_err()? + .to_scalar_int() + .discard_err()?; + } Some(cond) - }) else { - return; - }; - state.insert_value_idx(place, conds, &self.map); + }); } // We expect `lhs ?= A`. We found `lhs = Eq(rhs, B)`. // Create a condition on `rhs ?= B`. Rvalue::BinaryOp( op, - box (Operand::Move(place) | Operand::Copy(place), Operand::Constant(value)) - | box (Operand::Constant(value), Operand::Move(place) | Operand::Copy(place)), + box (Operand::Move(operand) | Operand::Copy(operand), Operand::Constant(value)) + | box (Operand::Constant(value), Operand::Move(operand) | Operand::Copy(operand)), ) => { - let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return }; - let Some(place) = self.map.find(place.as_ref()) else { return }; let equals = match op { BinOp::Eq => ScalarInt::TRUE, BinOp::Ne => ScalarInt::FALSE, @@ -526,20 +572,28 @@ fn process_assign( // Avoid handling them, though this could be extended in the future. return; } + let Some(lhs) = self.map.value(lhs) else { return }; + let Some(operand) = self.map.find_value(operand.as_ref()) else { return }; let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.typing_env) else { return; }; - let Some(conds) = conditions.map(self.arena, |c| { - Some(Condition { - value, - polarity: if c.matches(equals) { Polarity::Eq } else { Polarity::Ne }, - ..c - }) - }) else { - return; - }; - state.insert_value_idx(place, conds, &self.map); + *state = state.map(self.arena, |c| { + if c.place == lhs { + Condition { + place: operand, + value, + polarity: if c.matches(lhs, equals) { + Polarity::Eq + } else { + Polarity::Ne + }, + ..c + } + } else { + c + } + }); } _ => {} @@ -551,13 +605,8 @@ fn process_statement( &mut self, bb: BasicBlock, stmt: &Statement<'tcx>, - state: &mut State>, + state: &mut ConditionSet<'a>, ) { - let register_opportunity = |c: Condition| { - debug!(?bb, ?c.target, "register"); - self.opportunities.push(ThreadingOpportunity { chain: vec![bb], target: c.target }) - }; - // Below, `lhs` is the return value of `mutated_statement`, // the place to which `conditions` apply. @@ -581,8 +630,8 @@ fn process_statement( StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume( Operand::Copy(place) | Operand::Move(place), )) => { - let Some(conditions) = state.try_get(place.as_ref(), &self.map) else { return }; - conditions.iter_matches(ScalarInt::TRUE).for_each(register_opportunity) + let Some(place) = self.map.find_value(place.as_ref()) else { return }; + state.register_matches(place, ScalarInt::TRUE, Some(bb), &mut self.opportunities) } StatementKind::Assign(box (lhs_place, rhs)) => { self.process_assign(bb, lhs_place, rhs, state) @@ -595,8 +644,7 @@ fn process_statement( fn recurse_through_terminator( &mut self, bb: BasicBlock, - // Pass a closure that may clone the state, as we don't want to do it each time. - state: impl FnOnce() -> State>, + mut state: ConditionSet<'a>, cost: &CostChecker<'_, 'tcx>, depth: usize, ) { @@ -627,9 +675,8 @@ fn recurse_through_terminator( }; // We can recurse through this terminator. - let mut state = state(); if let Some(place_to_flood) = place_to_flood { - state.flood_with(place_to_flood.as_ref(), &self.map, ConditionSet::BOTTOM); + self.flood_state(place_to_flood, None, &mut state); } self.find_opportunity(bb, state, cost.clone(), depth + 1) } @@ -640,7 +687,7 @@ fn process_switch_int( discr: &Operand<'tcx>, targets: &SwitchTargets, target_bb: BasicBlock, - state: &mut State>, + state: &mut ConditionSet<'a>, ) { debug_assert_ne!(target_bb, START_BLOCK); debug_assert_eq!(self.body.basic_blocks.predecessors()[target_bb].len(), 1); @@ -650,7 +697,7 @@ fn process_switch_int( let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return; }; - let Some(conditions) = state.try_get(discr.as_ref(), &self.map) else { return }; + let Some(discr) = self.map.find_value(discr.as_ref()) else { return }; if let Some((value, _)) = targets.iter().find(|&(_, target)| target == target_bb) { let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) else { return }; @@ -660,10 +707,10 @@ fn process_switch_int( // through the `SwitchInt` before arriving here. Therefore, we know that // `discr == value`. If one condition can be fulfilled by `discr == value`, // that's an opportunity. - for c in conditions.iter_matches(value) { - debug!(?target_bb, ?c.target, "register"); - self.opportunities.push(ThreadingOpportunity { chain: vec![], target: c.target }); - } + // + // The TO starts with `target_bb`, which will be added by `find_opportunity`, so we + // start with an empty bb chain. + state.register_matches(discr, value, None, &mut self.opportunities); } else if let Some((value, _, else_bb)) = targets.as_static_if() && target_bb == else_bb { @@ -672,11 +719,11 @@ fn process_switch_int( // We only know that `discr != value`. That's much weaker information than // the equality we had in the previous arm. All we can conclude is that // the replacement condition `discr != value` can be threaded, and nothing else. - for c in conditions.iter() { - if c.value == value && c.polarity == Polarity::Ne { - debug!(?target_bb, ?c.target, "register"); - self.opportunities - .push(ThreadingOpportunity { chain: vec![], target: c.target }); + for c in state.iter() { + if c.place == discr && c.value == value && c.polarity == Polarity::Ne { + // The TO starts with `target_bb`, which will be added by `find_opportunity`, + // so we start with an empty bb chain. + self.opportunities.push(c.into_opportunity(None)); } } } diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map index c6eba8c8b3ab..1872f14aede0 100644 --- a/tests/coverage/conditions.cov-map +++ b/tests/coverage/conditions.cov-map @@ -1,92 +1,72 @@ Function name: conditions::main -Raw bytes (642): 0x[01, 01, 54, 05, 09, 01, 05, 09, 5d, 09, 27, 5d, 61, 27, 65, 5d, 61, 09, 23, 27, 65, 5d, 61, 01, 03, 03, 0d, 11, 51, 11, 4f, 51, 55, 4f, 59, 51, 55, 11, 4b, 4f, 59, 51, 55, 03, 9f, 01, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 9f, 01, 15, 0d, 11, 19, 45, 19, 97, 01, 45, 49, 97, 01, 4d, 45, 49, 19, 93, 01, 97, 01, 4d, 45, 49, 9f, 01, 8f, 02, 0d, 11, 15, 19, 15, 19, 15, 19, 15, 19, 15, 19, 1d, 21, 15, 19, 8f, 02, 1d, 15, 19, 21, 39, 21, e3, 01, 39, 3d, e3, 01, 41, 39, 3d, 21, df, 01, e3, 01, 41, 39, 3d, 8f, 02, cb, 02, 15, 19, 1d, 21, 8f, 02, cb, 02, 15, 19, 1d, 21, 8f, 02, cb, 02, 15, 19, 1d, 21, 8f, 02, cb, 02, 15, 19, 1d, 21, 25, 29, 1d, 21, cb, 02, 25, 1d, 21, 29, 2d, 29, c3, 02, 2d, 31, c3, 02, 35, 2d, 31, 29, bf, 02, c3, 02, 35, 2d, 31, cb, 02, cf, 02, 1d, 21, 25, 29, 52, 01, 03, 01, 00, 0a, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0c, 01, 00, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 05, 01, 09, 00, 17, 05, 01, 09, 00, 0a, 06, 01, 0f, 00, 1c, 09, 01, 0c, 00, 19, 0a, 00, 1d, 00, 2a, 0e, 00, 2e, 00, 3c, 23, 00, 3d, 02, 0a, 1e, 02, 09, 00, 0a, 09, 01, 09, 00, 17, 09, 01, 09, 00, 12, 2a, 02, 09, 00, 0f, 03, 03, 09, 00, 16, 03, 00, 19, 00, 1a, 03, 01, 08, 00, 0c, 03, 00, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 0d, 00, 16, 02, 06, 2e, 02, 0f, 00, 1c, 11, 01, 0c, 00, 19, 32, 00, 1d, 00, 2a, 36, 00, 2e, 00, 3c, 4b, 00, 3d, 02, 0a, 46, 02, 09, 00, 0a, 11, 01, 09, 00, 17, 52, 02, 09, 00, 0f, 9f, 01, 03, 08, 00, 0c, 9f, 01, 01, 0d, 00, 1a, 9f, 01, 00, 1d, 00, 1e, 9f, 01, 01, 0c, 00, 10, 9f, 01, 00, 11, 02, 0a, 00, 02, 09, 00, 0a, 9f, 01, 02, 0c, 00, 19, 15, 00, 1a, 02, 0a, 72, 04, 11, 00, 1e, 19, 01, 10, 00, 1d, 7a, 00, 21, 00, 2e, 7e, 00, 32, 00, 40, 93, 01, 00, 41, 02, 0e, 8e, 01, 02, 0d, 00, 0e, 19, 01, 0d, 00, 1b, 9a, 01, 02, 0d, 00, 13, 00, 02, 05, 00, 06, 8f, 02, 02, 09, 00, 16, 8f, 02, 00, 19, 00, 1a, 8f, 02, 01, 08, 00, 0c, 8f, 02, 00, 0d, 02, 06, 00, 02, 05, 00, 06, cb, 02, 02, 09, 00, 0a, 8f, 02, 00, 10, 00, 1d, 1d, 00, 1e, 02, 06, be, 01, 02, 0f, 00, 1c, 21, 01, 0c, 00, 19, c6, 01, 00, 1d, 00, 2a, ca, 01, 00, 2e, 00, 3c, df, 01, 00, 3d, 02, 0a, da, 01, 02, 09, 00, 0a, 21, 01, 09, 00, 17, 8a, 02, 02, 0d, 00, 20, 8a, 02, 00, 23, 00, 2c, 8a, 02, 01, 09, 00, 11, 8a, 02, 01, 09, 00, 0f, cf, 02, 03, 09, 00, 0a, cb, 02, 00, 10, 00, 1d, 25, 00, 1e, 02, 06, 9e, 02, 02, 0f, 00, 1c, 29, 01, 0c, 00, 19, a6, 02, 00, 1d, 00, 2a, aa, 02, 00, 2e, 00, 3c, bf, 02, 00, 3d, 02, 0a, ba, 02, 02, 09, 00, 0a, 29, 01, 09, 00, 17, c6, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] +Raw bytes (581): 0x[01, 01, 40, 05, 09, 01, 05, 09, 51, 09, 13, 51, 55, 01, 03, 03, 0d, 11, 49, 11, 27, 49, 4d, 03, 63, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 63, 15, 0d, 11, 19, 41, 19, 5b, 41, 45, 63, bf, 01, 0d, 11, 15, 19, 15, 19, 15, 19, 15, 19, 15, 19, 1d, 21, 15, 19, bf, 01, 1d, 15, 19, 21, 39, 21, 93, 01, 39, 3d, bf, 01, fb, 01, 15, 19, 1d, 21, bf, 01, fb, 01, 15, 19, 1d, 21, bf, 01, fb, 01, 15, 19, 1d, 21, bf, 01, fb, 01, 15, 19, 1d, 21, 25, 29, 1d, 21, fb, 01, 25, 1d, 21, 29, 2d, 29, f3, 01, 2d, 31, f3, 01, 35, 2d, 31, 29, ef, 01, f3, 01, 35, 2d, 31, fb, 01, ff, 01, 1d, 21, 25, 29, 52, 01, 03, 01, 00, 0a, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0c, 01, 00, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 05, 01, 09, 00, 17, 05, 01, 09, 00, 0a, 06, 01, 0f, 00, 1c, 09, 01, 0c, 00, 19, 0a, 00, 1d, 00, 2a, 0e, 00, 2e, 00, 3c, 09, 00, 3d, 02, 0a, 00, 02, 09, 00, 0a, 09, 01, 09, 00, 17, 09, 01, 09, 00, 12, 16, 02, 09, 00, 0f, 03, 03, 09, 00, 16, 03, 00, 19, 00, 1a, 03, 01, 08, 00, 0c, 03, 00, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 0d, 00, 16, 02, 06, 1a, 02, 0f, 00, 1c, 11, 01, 0c, 00, 19, 1e, 00, 1d, 00, 2a, 22, 00, 2e, 00, 3c, 11, 00, 3d, 02, 0a, 00, 02, 09, 00, 0a, 11, 01, 09, 00, 17, 2a, 02, 09, 00, 0f, 63, 03, 08, 00, 0c, 63, 01, 0d, 00, 1a, 63, 00, 1d, 00, 1e, 63, 01, 0c, 00, 10, 63, 00, 11, 02, 0a, 00, 02, 09, 00, 0a, 63, 02, 0c, 00, 19, 15, 00, 1a, 02, 0a, 4a, 04, 11, 00, 1e, 19, 01, 10, 00, 1d, 52, 00, 21, 00, 2e, 56, 00, 32, 00, 40, 19, 00, 41, 02, 0e, 00, 02, 0d, 00, 0e, 19, 01, 0d, 00, 1b, 5e, 02, 0d, 00, 13, 00, 02, 05, 00, 06, bf, 01, 02, 09, 00, 16, bf, 01, 00, 19, 00, 1a, bf, 01, 01, 08, 00, 0c, bf, 01, 00, 0d, 02, 06, 00, 02, 05, 00, 06, fb, 01, 02, 09, 00, 0a, bf, 01, 00, 10, 00, 1d, 1d, 00, 1e, 02, 06, 82, 01, 02, 0f, 00, 1c, 21, 01, 0c, 00, 19, 8a, 01, 00, 1d, 00, 2a, 8e, 01, 00, 2e, 00, 3c, 21, 00, 3d, 02, 0a, 00, 02, 09, 00, 0a, 21, 01, 09, 00, 17, ba, 01, 02, 0d, 00, 20, ba, 01, 00, 23, 00, 2c, ba, 01, 01, 09, 00, 11, ba, 01, 01, 09, 00, 0f, ff, 01, 03, 09, 00, 0a, fb, 01, 00, 10, 00, 1d, 25, 00, 1e, 02, 06, ce, 01, 02, 0f, 00, 1c, 29, 01, 0c, 00, 19, d6, 01, 00, 1d, 00, 2a, da, 01, 00, 2e, 00, 3c, ef, 01, 00, 3d, 02, 0a, ea, 01, 02, 09, 00, 0a, 29, 01, 09, 00, 17, f6, 01, 02, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/conditions.rs -Number of expressions: 84 +Number of expressions: 64 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(0), rhs = Counter(1) -- expression 2 operands: lhs = Counter(2), rhs = Counter(23) -- expression 3 operands: lhs = Counter(2), rhs = Expression(9, Add) -- expression 4 operands: lhs = Counter(23), rhs = Counter(24) -- expression 5 operands: lhs = Expression(9, Add), rhs = Counter(25) -- expression 6 operands: lhs = Counter(23), rhs = Counter(24) -- expression 7 operands: lhs = Counter(2), rhs = Expression(8, Add) -- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(25) -- expression 9 operands: lhs = Counter(23), rhs = Counter(24) -- expression 10 operands: lhs = Counter(0), rhs = Expression(0, Add) -- expression 11 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 12 operands: lhs = Counter(4), rhs = Counter(20) -- expression 13 operands: lhs = Counter(4), rhs = Expression(19, Add) -- expression 14 operands: lhs = Counter(20), rhs = Counter(21) -- expression 15 operands: lhs = Expression(19, Add), rhs = Counter(22) -- expression 16 operands: lhs = Counter(20), rhs = Counter(21) -- expression 17 operands: lhs = Counter(4), rhs = Expression(18, Add) -- expression 18 operands: lhs = Expression(19, Add), rhs = Counter(22) -- expression 19 operands: lhs = Counter(20), rhs = Counter(21) -- expression 20 operands: lhs = Expression(0, Add), rhs = Expression(39, Add) -- expression 21 operands: lhs = Counter(3), rhs = Counter(4) -- expression 22 operands: lhs = Counter(3), rhs = Counter(4) -- expression 23 operands: lhs = Counter(3), rhs = Counter(4) +- expression 2 operands: lhs = Counter(2), rhs = Counter(20) +- expression 3 operands: lhs = Counter(2), rhs = Expression(4, Add) +- expression 4 operands: lhs = Counter(20), rhs = Counter(21) +- expression 5 operands: lhs = Counter(0), rhs = Expression(0, Add) +- expression 6 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 7 operands: lhs = Counter(4), rhs = Counter(18) +- expression 8 operands: lhs = Counter(4), rhs = Expression(9, Add) +- expression 9 operands: lhs = Counter(18), rhs = Counter(19) +- expression 10 operands: lhs = Expression(0, Add), rhs = Expression(24, Add) +- expression 11 operands: lhs = Counter(3), rhs = Counter(4) +- expression 12 operands: lhs = Counter(3), rhs = Counter(4) +- expression 13 operands: lhs = Counter(3), rhs = Counter(4) +- expression 14 operands: lhs = Counter(3), rhs = Counter(4) +- expression 15 operands: lhs = Counter(3), rhs = Counter(4) +- expression 16 operands: lhs = Counter(3), rhs = Counter(4) +- expression 17 operands: lhs = Counter(3), rhs = Counter(4) +- expression 18 operands: lhs = Expression(24, Add), rhs = Counter(5) +- expression 19 operands: lhs = Counter(3), rhs = Counter(4) +- expression 20 operands: lhs = Counter(6), rhs = Counter(16) +- expression 21 operands: lhs = Counter(6), rhs = Expression(22, Add) +- expression 22 operands: lhs = Counter(16), rhs = Counter(17) +- expression 23 operands: lhs = Expression(24, Add), rhs = Expression(47, Add) - expression 24 operands: lhs = Counter(3), rhs = Counter(4) -- expression 25 operands: lhs = Counter(3), rhs = Counter(4) -- expression 26 operands: lhs = Counter(3), rhs = Counter(4) -- expression 27 operands: lhs = Counter(3), rhs = Counter(4) -- expression 28 operands: lhs = Expression(39, Add), rhs = Counter(5) -- expression 29 operands: lhs = Counter(3), rhs = Counter(4) -- expression 30 operands: lhs = Counter(6), rhs = Counter(17) -- expression 31 operands: lhs = Counter(6), rhs = Expression(37, Add) -- expression 32 operands: lhs = Counter(17), rhs = Counter(18) -- expression 33 operands: lhs = Expression(37, Add), rhs = Counter(19) -- expression 34 operands: lhs = Counter(17), rhs = Counter(18) -- expression 35 operands: lhs = Counter(6), rhs = Expression(36, Add) -- expression 36 operands: lhs = Expression(37, Add), rhs = Counter(19) -- expression 37 operands: lhs = Counter(17), rhs = Counter(18) -- expression 38 operands: lhs = Expression(39, Add), rhs = Expression(67, Add) -- expression 39 operands: lhs = Counter(3), rhs = Counter(4) -- expression 40 operands: lhs = Counter(5), rhs = Counter(6) +- expression 25 operands: lhs = Counter(5), rhs = Counter(6) +- expression 26 operands: lhs = Counter(5), rhs = Counter(6) +- expression 27 operands: lhs = Counter(5), rhs = Counter(6) +- expression 28 operands: lhs = Counter(5), rhs = Counter(6) +- expression 29 operands: lhs = Counter(5), rhs = Counter(6) +- expression 30 operands: lhs = Counter(7), rhs = Counter(8) +- expression 31 operands: lhs = Counter(5), rhs = Counter(6) +- expression 32 operands: lhs = Expression(47, Add), rhs = Counter(7) +- expression 33 operands: lhs = Counter(5), rhs = Counter(6) +- expression 34 operands: lhs = Counter(8), rhs = Counter(14) +- expression 35 operands: lhs = Counter(8), rhs = Expression(36, Add) +- expression 36 operands: lhs = Counter(14), rhs = Counter(15) +- expression 37 operands: lhs = Expression(47, Add), rhs = Expression(62, Add) +- expression 38 operands: lhs = Counter(5), rhs = Counter(6) +- expression 39 operands: lhs = Counter(7), rhs = Counter(8) +- expression 40 operands: lhs = Expression(47, Add), rhs = Expression(62, Add) - expression 41 operands: lhs = Counter(5), rhs = Counter(6) -- expression 42 operands: lhs = Counter(5), rhs = Counter(6) -- expression 43 operands: lhs = Counter(5), rhs = Counter(6) +- expression 42 operands: lhs = Counter(7), rhs = Counter(8) +- expression 43 operands: lhs = Expression(47, Add), rhs = Expression(62, Add) - expression 44 operands: lhs = Counter(5), rhs = Counter(6) - expression 45 operands: lhs = Counter(7), rhs = Counter(8) -- expression 46 operands: lhs = Counter(5), rhs = Counter(6) -- expression 47 operands: lhs = Expression(67, Add), rhs = Counter(7) -- expression 48 operands: lhs = Counter(5), rhs = Counter(6) -- expression 49 operands: lhs = Counter(8), rhs = Counter(14) -- expression 50 operands: lhs = Counter(8), rhs = Expression(56, Add) -- expression 51 operands: lhs = Counter(14), rhs = Counter(15) -- expression 52 operands: lhs = Expression(56, Add), rhs = Counter(16) -- expression 53 operands: lhs = Counter(14), rhs = Counter(15) -- expression 54 operands: lhs = Counter(8), rhs = Expression(55, Add) -- expression 55 operands: lhs = Expression(56, Add), rhs = Counter(16) -- expression 56 operands: lhs = Counter(14), rhs = Counter(15) -- expression 57 operands: lhs = Expression(67, Add), rhs = Expression(82, Add) -- expression 58 operands: lhs = Counter(5), rhs = Counter(6) -- expression 59 operands: lhs = Counter(7), rhs = Counter(8) -- expression 60 operands: lhs = Expression(67, Add), rhs = Expression(82, Add) -- expression 61 operands: lhs = Counter(5), rhs = Counter(6) +- expression 46 operands: lhs = Expression(47, Add), rhs = Expression(62, Add) +- expression 47 operands: lhs = Counter(5), rhs = Counter(6) +- expression 48 operands: lhs = Counter(7), rhs = Counter(8) +- expression 49 operands: lhs = Counter(9), rhs = Counter(10) +- expression 50 operands: lhs = Counter(7), rhs = Counter(8) +- expression 51 operands: lhs = Expression(62, Add), rhs = Counter(9) +- expression 52 operands: lhs = Counter(7), rhs = Counter(8) +- expression 53 operands: lhs = Counter(10), rhs = Counter(11) +- expression 54 operands: lhs = Counter(10), rhs = Expression(60, Add) +- expression 55 operands: lhs = Counter(11), rhs = Counter(12) +- expression 56 operands: lhs = Expression(60, Add), rhs = Counter(13) +- expression 57 operands: lhs = Counter(11), rhs = Counter(12) +- expression 58 operands: lhs = Counter(10), rhs = Expression(59, Add) +- expression 59 operands: lhs = Expression(60, Add), rhs = Counter(13) +- expression 60 operands: lhs = Counter(11), rhs = Counter(12) +- expression 61 operands: lhs = Expression(62, Add), rhs = Expression(63, Add) - expression 62 operands: lhs = Counter(7), rhs = Counter(8) -- expression 63 operands: lhs = Expression(67, Add), rhs = Expression(82, Add) -- expression 64 operands: lhs = Counter(5), rhs = Counter(6) -- expression 65 operands: lhs = Counter(7), rhs = Counter(8) -- expression 66 operands: lhs = Expression(67, Add), rhs = Expression(82, Add) -- expression 67 operands: lhs = Counter(5), rhs = Counter(6) -- expression 68 operands: lhs = Counter(7), rhs = Counter(8) -- expression 69 operands: lhs = Counter(9), rhs = Counter(10) -- expression 70 operands: lhs = Counter(7), rhs = Counter(8) -- expression 71 operands: lhs = Expression(82, Add), rhs = Counter(9) -- expression 72 operands: lhs = Counter(7), rhs = Counter(8) -- expression 73 operands: lhs = Counter(10), rhs = Counter(11) -- expression 74 operands: lhs = Counter(10), rhs = Expression(80, Add) -- expression 75 operands: lhs = Counter(11), rhs = Counter(12) -- expression 76 operands: lhs = Expression(80, Add), rhs = Counter(13) -- expression 77 operands: lhs = Counter(11), rhs = Counter(12) -- expression 78 operands: lhs = Counter(10), rhs = Expression(79, Add) -- expression 79 operands: lhs = Expression(80, Add), rhs = Counter(13) -- expression 80 operands: lhs = Counter(11), rhs = Counter(12) -- expression 81 operands: lhs = Expression(82, Add), rhs = Expression(83, Add) -- expression 82 operands: lhs = Counter(7), rhs = Counter(8) -- expression 83 operands: lhs = Counter(9), rhs = Counter(10) +- expression 63 operands: lhs = Counter(9), rhs = Counter(10) Number of file 0 mappings: 82 - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) @@ -103,16 +83,14 @@ Number of file 0 mappings: 82 = (c0 - c1) - Code(Counter(2)) at (prev + 1, 12) to (start + 0, 25) - Code(Expression(2, Sub)) at (prev + 0, 29) to (start + 0, 42) - = (c2 - c23) + = (c2 - c20) - Code(Expression(3, Sub)) at (prev + 0, 46) to (start + 0, 60) - = (c2 - (c23 + c24)) -- Code(Expression(8, Add)) at (prev + 0, 61) to (start + 2, 10) - = ((c23 + c24) + c25) -- Code(Expression(7, Sub)) at (prev + 2, 9) to (start + 0, 10) - = (c2 - ((c23 + c24) + c25)) + = (c2 - (c20 + c21)) +- Code(Counter(2)) at (prev + 0, 61) to (start + 2, 10) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 23) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 18) -- Code(Expression(10, Sub)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(5, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - (c1 + c2)) - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 22) = (c1 + c2) @@ -126,101 +104,95 @@ Number of file 0 mappings: 82 - Code(Expression(0, Add)) at (prev + 2, 8) to (start + 0, 21) = (c1 + c2) - Code(Counter(3)) at (prev + 0, 22) to (start + 2, 6) -- Code(Expression(11, Sub)) at (prev + 2, 15) to (start + 0, 28) +- Code(Expression(6, Sub)) at (prev + 2, 15) to (start + 0, 28) = ((c1 + c2) - c3) - Code(Counter(4)) at (prev + 1, 12) to (start + 0, 25) -- Code(Expression(12, Sub)) at (prev + 0, 29) to (start + 0, 42) - = (c4 - c20) -- Code(Expression(13, Sub)) at (prev + 0, 46) to (start + 0, 60) - = (c4 - (c20 + c21)) -- Code(Expression(18, Add)) at (prev + 0, 61) to (start + 2, 10) - = ((c20 + c21) + c22) -- Code(Expression(17, Sub)) at (prev + 2, 9) to (start + 0, 10) - = (c4 - ((c20 + c21) + c22)) +- Code(Expression(7, Sub)) at (prev + 0, 29) to (start + 0, 42) + = (c4 - c18) +- Code(Expression(8, Sub)) at (prev + 0, 46) to (start + 0, 60) + = (c4 - (c18 + c19)) +- Code(Counter(4)) at (prev + 0, 61) to (start + 2, 10) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(4)) at (prev + 1, 9) to (start + 0, 23) -- Code(Expression(20, Sub)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(10, Sub)) at (prev + 2, 9) to (start + 0, 15) = ((c1 + c2) - (c3 + c4)) -- Code(Expression(39, Add)) at (prev + 3, 8) to (start + 0, 12) +- Code(Expression(24, Add)) at (prev + 3, 8) to (start + 0, 12) = (c3 + c4) -- Code(Expression(39, Add)) at (prev + 1, 13) to (start + 0, 26) +- Code(Expression(24, Add)) at (prev + 1, 13) to (start + 0, 26) = (c3 + c4) -- Code(Expression(39, Add)) at (prev + 0, 29) to (start + 0, 30) +- Code(Expression(24, Add)) at (prev + 0, 29) to (start + 0, 30) = (c3 + c4) -- Code(Expression(39, Add)) at (prev + 1, 12) to (start + 0, 16) +- Code(Expression(24, Add)) at (prev + 1, 12) to (start + 0, 16) = (c3 + c4) -- Code(Expression(39, Add)) at (prev + 0, 17) to (start + 2, 10) +- Code(Expression(24, Add)) at (prev + 0, 17) to (start + 2, 10) = (c3 + c4) - Code(Zero) at (prev + 2, 9) to (start + 0, 10) -- Code(Expression(39, Add)) at (prev + 2, 12) to (start + 0, 25) +- Code(Expression(24, Add)) at (prev + 2, 12) to (start + 0, 25) = (c3 + c4) - Code(Counter(5)) at (prev + 0, 26) to (start + 2, 10) -- Code(Expression(28, Sub)) at (prev + 4, 17) to (start + 0, 30) +- Code(Expression(18, Sub)) at (prev + 4, 17) to (start + 0, 30) = ((c3 + c4) - c5) - Code(Counter(6)) at (prev + 1, 16) to (start + 0, 29) -- Code(Expression(30, Sub)) at (prev + 0, 33) to (start + 0, 46) - = (c6 - c17) -- Code(Expression(31, Sub)) at (prev + 0, 50) to (start + 0, 64) - = (c6 - (c17 + c18)) -- Code(Expression(36, Add)) at (prev + 0, 65) to (start + 2, 14) - = ((c17 + c18) + c19) -- Code(Expression(35, Sub)) at (prev + 2, 13) to (start + 0, 14) - = (c6 - ((c17 + c18) + c19)) +- Code(Expression(20, Sub)) at (prev + 0, 33) to (start + 0, 46) + = (c6 - c16) +- Code(Expression(21, Sub)) at (prev + 0, 50) to (start + 0, 64) + = (c6 - (c16 + c17)) +- Code(Counter(6)) at (prev + 0, 65) to (start + 2, 14) +- Code(Zero) at (prev + 2, 13) to (start + 0, 14) - Code(Counter(6)) at (prev + 1, 13) to (start + 0, 27) -- Code(Expression(38, Sub)) at (prev + 2, 13) to (start + 0, 19) +- Code(Expression(23, Sub)) at (prev + 2, 13) to (start + 0, 19) = ((c3 + c4) - (c5 + c6)) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) -- Code(Expression(67, Add)) at (prev + 2, 9) to (start + 0, 22) +- Code(Expression(47, Add)) at (prev + 2, 9) to (start + 0, 22) = (c5 + c6) -- Code(Expression(67, Add)) at (prev + 0, 25) to (start + 0, 26) +- Code(Expression(47, Add)) at (prev + 0, 25) to (start + 0, 26) = (c5 + c6) -- Code(Expression(67, Add)) at (prev + 1, 8) to (start + 0, 12) +- Code(Expression(47, Add)) at (prev + 1, 8) to (start + 0, 12) = (c5 + c6) -- Code(Expression(67, Add)) at (prev + 0, 13) to (start + 2, 6) +- Code(Expression(47, Add)) at (prev + 0, 13) to (start + 2, 6) = (c5 + c6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) -- Code(Expression(82, Add)) at (prev + 2, 9) to (start + 0, 10) +- Code(Expression(62, Add)) at (prev + 2, 9) to (start + 0, 10) = (c7 + c8) -- Code(Expression(67, Add)) at (prev + 0, 16) to (start + 0, 29) +- Code(Expression(47, Add)) at (prev + 0, 16) to (start + 0, 29) = (c5 + c6) - Code(Counter(7)) at (prev + 0, 30) to (start + 2, 6) -- Code(Expression(47, Sub)) at (prev + 2, 15) to (start + 0, 28) +- Code(Expression(32, Sub)) at (prev + 2, 15) to (start + 0, 28) = ((c5 + c6) - c7) - Code(Counter(8)) at (prev + 1, 12) to (start + 0, 25) -- Code(Expression(49, Sub)) at (prev + 0, 29) to (start + 0, 42) +- Code(Expression(34, Sub)) at (prev + 0, 29) to (start + 0, 42) = (c8 - c14) -- Code(Expression(50, Sub)) at (prev + 0, 46) to (start + 0, 60) +- Code(Expression(35, Sub)) at (prev + 0, 46) to (start + 0, 60) = (c8 - (c14 + c15)) -- Code(Expression(55, Add)) at (prev + 0, 61) to (start + 2, 10) - = ((c14 + c15) + c16) -- Code(Expression(54, Sub)) at (prev + 2, 9) to (start + 0, 10) - = (c8 - ((c14 + c15) + c16)) +- Code(Counter(8)) at (prev + 0, 61) to (start + 2, 10) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(8)) at (prev + 1, 9) to (start + 0, 23) -- Code(Expression(66, Sub)) at (prev + 2, 13) to (start + 0, 32) +- Code(Expression(46, Sub)) at (prev + 2, 13) to (start + 0, 32) = ((c5 + c6) - (c7 + c8)) -- Code(Expression(66, Sub)) at (prev + 0, 35) to (start + 0, 44) +- Code(Expression(46, Sub)) at (prev + 0, 35) to (start + 0, 44) = ((c5 + c6) - (c7 + c8)) -- Code(Expression(66, Sub)) at (prev + 1, 9) to (start + 0, 17) +- Code(Expression(46, Sub)) at (prev + 1, 9) to (start + 0, 17) = ((c5 + c6) - (c7 + c8)) -- Code(Expression(66, Sub)) at (prev + 1, 9) to (start + 0, 15) +- Code(Expression(46, Sub)) at (prev + 1, 9) to (start + 0, 15) = ((c5 + c6) - (c7 + c8)) -- Code(Expression(83, Add)) at (prev + 3, 9) to (start + 0, 10) +- Code(Expression(63, Add)) at (prev + 3, 9) to (start + 0, 10) = (c9 + c10) -- Code(Expression(82, Add)) at (prev + 0, 16) to (start + 0, 29) +- Code(Expression(62, Add)) at (prev + 0, 16) to (start + 0, 29) = (c7 + c8) - Code(Counter(9)) at (prev + 0, 30) to (start + 2, 6) -- Code(Expression(71, Sub)) at (prev + 2, 15) to (start + 0, 28) +- Code(Expression(51, Sub)) at (prev + 2, 15) to (start + 0, 28) = ((c7 + c8) - c9) - Code(Counter(10)) at (prev + 1, 12) to (start + 0, 25) -- Code(Expression(73, Sub)) at (prev + 0, 29) to (start + 0, 42) +- Code(Expression(53, Sub)) at (prev + 0, 29) to (start + 0, 42) = (c10 - c11) -- Code(Expression(74, Sub)) at (prev + 0, 46) to (start + 0, 60) +- Code(Expression(54, Sub)) at (prev + 0, 46) to (start + 0, 60) = (c10 - (c11 + c12)) -- Code(Expression(79, Add)) at (prev + 0, 61) to (start + 2, 10) +- Code(Expression(59, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c11 + c12) + c13) -- Code(Expression(78, Sub)) at (prev + 2, 9) to (start + 0, 10) +- Code(Expression(58, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c10 - ((c11 + c12) + c13)) - Code(Counter(10)) at (prev + 1, 9) to (start + 0, 23) -- Code(Expression(81, Sub)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(61, Sub)) at (prev + 2, 9) to (start + 0, 15) = ((c7 + c8) - (c9 + c10)) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c10 diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index ab8840db3837..ad46a02b83f4 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -88,7 +88,7 @@ fn two_reads() -> i32 { // CHECK: [[c]] = copy [[a]]; // CHECK: [[tmp:_.*]] = copy [[c]]; // CHECK: [[eq:_.*]] = Eq(move [[tmp]], const 2_i32); - // CHECK: switchInt(move [[eq]]) -> [0: bb2, otherwise: bb1]; + // CHECK: goto -> bb1; // CHECK: bb1: { // CHECK: _0 = const 0_i32; // CHECK: goto -> bb3; diff --git a/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-abort.diff index 9962a5724b3f..090e9d37b4f9 100644 --- a/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-abort.diff @@ -29,7 +29,8 @@ StorageLive(_5); _5 = copy _3; _4 = Eq(move _5, const 2_i32); - switchInt(move _4) -> [0: bb2, otherwise: bb1]; +- switchInt(move _4) -> [0: bb2, otherwise: bb1]; ++ goto -> bb1; } bb1: { diff --git a/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-unwind.diff index 9962a5724b3f..090e9d37b4f9 100644 --- a/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.two_reads.JumpThreading.panic-unwind.diff @@ -29,7 +29,8 @@ StorageLive(_5); _5 = copy _3; _4 = Eq(move _5, const 2_i32); - switchInt(move _4) -> [0: bb2, otherwise: bb1]; +- switchInt(move _4) -> [0: bb2, otherwise: bb1]; ++ goto -> bb1; } bb1: { From f12ab2790d9405df290ee4e890c60239c08a7fda Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 Jun 2025 23:32:54 +0000 Subject: [PATCH 052/585] Do not flood if state is empty. --- compiler/rustc_mir_transform/src/jump_threading.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 9b420ab18112..72c003e9c575 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -345,6 +345,9 @@ fn flood_state( extra_elem: Option, state: &mut ConditionSet<'a>, ) { + if state.is_empty() { + return; + } let mut places_to_exclude = FxHashSet::default(); self.map.for_each_aliasing_place(place.as_ref(), extra_elem, &mut |vi| { places_to_exclude.insert(vi); From acf3b6a6a6e74c3f9fd19948d30920e3a417ff3a Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 22 Jun 2025 08:38:50 +0000 Subject: [PATCH 053/585] Skip process_constant if state has no matching value. --- compiler/rustc_mir_dataflow/src/value_analysis.rs | 10 +++++++--- compiler/rustc_mir_transform/src/jump_threading.rs | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 969e9b3a4dd8..b1ff7ffc60ed 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -750,11 +750,15 @@ fn for_each_variant_sibling( } } + /// Return the range of value indices inside this place. + pub fn values_inside(&self, root: PlaceIndex) -> &[ValueIndex] { + let range = self.inner_values[root].clone(); + &self.inner_values_buffer[range] + } + /// Invoke a function on each value in the given place and all descendants. fn for_each_value_inside(&self, root: PlaceIndex, f: &mut impl FnMut(ValueIndex)) { - let range = self.inner_values[root].clone(); - let values = &self.inner_values_buffer[range]; - for &v in values { + for &v in self.values_inside(root) { f(v) } } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 72c003e9c575..1e793249c86b 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -422,6 +422,10 @@ fn process_constant( constant: OpTy<'tcx>, state: &mut ConditionSet<'a>, ) { + let values_inside = self.map.values_inside(lhs); + if !state.iter().any(|cond| values_inside.contains(&cond.place)) { + return; + } self.map.for_each_projection_value( lhs, constant, From f59dfc1a4a5c23f35a437e2c52607ff1f215903b Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 19 Jun 2025 21:24:45 +0000 Subject: [PATCH 054/585] Maintain a graph of fulfilled conditions. --- .../rustc_mir_transform/src/jump_threading.rs | 978 ++++++++++-------- ..._conditions.JumpThreading.panic-abort.diff | 335 ++++++ ...conditions.JumpThreading.panic-unwind.diff | 349 +++++++ ...ustom_discr.JumpThreading.panic-abort.diff | 12 +- ...stom_discr.JumpThreading.panic-unwind.diff | 12 +- ...ppearing_bb.JumpThreading.panic-abort.diff | 41 +- ...pearing_bb.JumpThreading.panic-unwind.diff | 41 +- ...icate_chain.JumpThreading.panic-abort.diff | 19 +- ...cate_chain.JumpThreading.panic-unwind.diff | 19 +- ...ng.identity.JumpThreading.panic-abort.diff | 15 +- ...g.identity.JumpThreading.panic-unwind.diff | 15 +- ...tiple_match.JumpThreading.panic-abort.diff | 19 +- ...iple_match.JumpThreading.panic-unwind.diff | 19 +- ...numbered_bb.JumpThreading.panic-abort.diff | 17 +- ...umbered_bb.JumpThreading.panic-unwind.diff | 17 +- tests/mir-opt/jump_threading.rs | 122 ++- ...too_complex.JumpThreading.panic-abort.diff | 11 +- ...oo_complex.JumpThreading.panic-unwind.diff | 11 +- .../derived_ord.demo_le.PreCodegen.after.mir | 44 +- tests/mir-opt/pre-codegen/derived_ord.rs | 29 +- ...ated_loop.PreCodegen.after.panic-abort.mir | 14 +- ...ward_loop.PreCodegen.after.panic-abort.mir | 14 +- ...ard_loop.PreCodegen.after.panic-unwind.mir | 14 +- ...e_const_switch.identity.JumpThreading.diff | 14 +- ...onst_switch.too_complex.JumpThreading.diff | 11 +- 25 files changed, 1567 insertions(+), 625 deletions(-) create mode 100644 tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff create mode 100644 tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 1e793249c86b..a99297bf2f9a 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -7,46 +7,63 @@ //! ------------/ \-------- ------------ //! //! -//! We proceed by walking the cfg backwards starting from each `SwitchInt` terminator, -//! looking for assignments that will turn the `SwitchInt` into a simple `Goto`. +//! This implementation is heavily inspired by the work outlined in [libfirm]. //! -//! The algorithm maintains a set of replacement conditions: -//! - `conditions[place]` contains `Condition { value, polarity: Eq, target }` -//! if assigning `value` to `place` turns the `SwitchInt` into `Goto { target }`. -//! - `conditions[place]` contains `Condition { value, polarity: Ne, target }` -//! if assigning anything different from `value` to `place` turns the `SwitchInt` -//! into `Goto { target }`. +//! The general algorithm proceeds in two phases: (1) walk the CFG backwards to construct a +//! graph of threading conditions, and (2) propagate fulfilled conditions forward by duplicating +//! blocks. +//! +//! # 1. Condition graph construction //! //! In this file, we denote as `place ?= value` the existence of a replacement condition //! on `place` with given `value`, irrespective of the polarity and target of that //! replacement condition. //! -//! We then walk the CFG backwards transforming the set of conditions. -//! When we find a fulfilling assignment, we record a `ThreadingOpportunity`. -//! All `ThreadingOpportunity`s are applied to the body, by duplicating blocks if required. +//! Inside a block, we associate with each condition `c` a set of targets: +//! - `Goto(target)` if fulfilling `c` changes the terminator into a `Goto { target }`; +//! - `Chain(target, c2)` if fulfilling `c` means that `c2` is fulfilled inside `target`. //! -//! The optimization search can be very heavy, as it performs a DFS on MIR starting from -//! each `SwitchInt` terminator. To manage the complexity, we: -//! - bound the maximum depth by a constant `MAX_BACKTRACK`; -//! - we only traverse `Goto` terminators. +//! Before walking a block `bb`, we construct the exit set of condition from its successors. +//! For each condition `c` in a successor `s`, we record that fulfilling `c` in `bb` will fulfill +//! `c` in `s`, as a `Chain(s, c)` condition. +//! +//! When encountering a `switchInt(place) -> [value: bb...]` terminator, we also record a +//! `place == value` condition for each `value`, and associate a `Goto(target)` condition. +//! +//! Then, we walk the statements backwards, transforming the set of conditions along the way, +//! resulting in a set of conditions at the block entry. //! //! We try to avoid creating irreducible control-flow by not threading through a loop header. //! -//! Likewise, applying the optimisation can create a lot of new MIR, so we bound the instruction +//! Applying the optimisation can create a lot of new MIR, so we bound the instruction //! cost by `MAX_COST`. +//! +//! # 2. Block duplication +//! +//! We now have the set of fulfilled conditions inside each block and their targets. +//! +//! For each block `bb` in reverse postorder, we apply in turn the target associated with each +//! fulfilled condition: +//! - for `Goto(target)`, change the terminator of `bb` into a `Goto { target }`; +//! - for `Chain(target, cond)`, duplicate `target` into a new block which fulfills the same +//! conditions and also fulfills `cond`. This is made efficient by maintaining a map of duplicates, +//! `duplicate[(target, cond)]` to avoid cloning blocks multiple times. +//! +//! [libfirm]: -use rustc_arena::DroplessArena; +use std::cell::OnceCell; + +use itertools::Itertools as _; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_index::IndexVec; -use rustc_index::bit_set::DenseBitSet; +use rustc_index::bit_set::{DenseBitSet, GrowableBitSet}; use rustc_middle::bug; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::{self, ScalarInt, TyCtxt}; -use rustc_mir_dataflow::lattice::HasBottom; use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, TrackElem, ValueIndex}; use rustc_span::DUMMY_SP; use tracing::{debug, instrument, trace}; @@ -55,8 +72,7 @@ pub(super) struct JumpThreading; -const MAX_BACKTRACK: usize = 5; -const MAX_COST: usize = 100; +const MAX_COST: u8 = 100; const MAX_PLACES: usize = 100; impl<'tcx> crate::MirPass<'tcx> for JumpThreading { @@ -76,33 +92,51 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } let typing_env = body.typing_env(tcx); - let arena = &DroplessArena::default(); let mut finder = TOFinder { tcx, typing_env, ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), body, - arena, map: Map::new(tcx, body, Some(MAX_PLACES)), maybe_loop_headers: loops::maybe_loop_headers(body), - opportunities: Vec::new(), + entry_states: IndexVec::from_elem(ConditionSet::default(), &body.basic_blocks), + costs: IndexVec::from_elem(OnceCell::new(), &body.basic_blocks), }; - for (bb, _) in traversal::preorder(body) { - finder.start_from_switch(bb); + for (bb, bbdata) in traversal::postorder(body) { + if bbdata.is_cleanup { + continue; + } + + let mut state = finder.populate_from_outgoing_edges(bb); + trace!("output_states[{bb:?}] = {state:?}"); + + finder.process_terminator(bb, &mut state); + trace!("pre_terminator_states[{bb:?}] = {state:?}"); + + for stmt in bbdata.statements.iter().rev() { + if state.is_empty() { + break; + } + + finder.process_statement(stmt, &mut state); + + // When a statement mutates a place, assignments to that place that happen + // above the mutation cannot fulfill a condition. + // _1 = 5 // Whatever happens here, it won't change the result of a `SwitchInt`. + // _1 = 6 + if let Some((lhs, tail)) = finder.mutated_statement(stmt) { + finder.flood_state(lhs, tail, &mut state); + } + } + + trace!("entry_states[{bb:?}] = {state:?}"); + finder.entry_states[bb] = state; } - let opportunities = finder.opportunities; - debug!(?opportunities); - if opportunities.is_empty() { - return; + if let Some(opportunities) = OpportunitySet::new(body, finder.entry_states) { + opportunities.apply(); } - - // Verify that we do not thread through a loop header. - for to in opportunities.iter() { - assert!(to.chain.iter().all(|&block| !finder.maybe_loop_headers.contains(block))); - } - OpportunitySet::new(body, opportunities).apply(body); } fn is_required(&self) -> bool { @@ -110,14 +144,6 @@ fn is_required(&self) -> bool { } } -#[derive(Debug)] -struct ThreadingOpportunity { - /// The list of `BasicBlock`s from the one that found the opportunity to the `SwitchInt`. - chain: Vec, - /// The `SwitchInt` will be replaced by `Goto { target }`. - target: BasicBlock, -} - struct TOFinder<'a, 'tcx> { tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, @@ -125,22 +151,31 @@ struct TOFinder<'a, 'tcx> { body: &'a Body<'tcx>, map: Map<'tcx>, maybe_loop_headers: DenseBitSet, - /// We use an arena to avoid cloning the slices when cloning `state`. - arena: &'a DroplessArena, - opportunities: Vec, + /// This stores the state of each visited block on entry, + /// and the current state of the block being visited. + // Invariant: for each `bb`, each condition in `entry_states[bb]` has a `chain` that + // starts with `bb`. + entry_states: IndexVec, + /// Pre-computed cost of duplicating each block. + costs: IndexVec>, +} + +rustc_index::newtype_index! { + #[derive(Ord, PartialOrd)] + #[debug_format = "_c{}"] + struct ConditionIndex {} } /// Represent the following statement. If we can prove that the current local is equal/not-equal /// to `value`, jump to `target`. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] struct Condition { place: ValueIndex, value: ScalarInt, polarity: Polarity, - target: BasicBlock, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] enum Polarity { Ne, Eq, @@ -150,192 +185,176 @@ impl Condition { fn matches(&self, place: ValueIndex, value: ScalarInt) -> bool { self.place == place && (self.value == value) == (self.polarity == Polarity::Eq) } +} - fn into_opportunity(self, match_bb: Option) -> ThreadingOpportunity { - trace!(?self, "registering"); - let chain = match_bb.into_iter().collect(); - ThreadingOpportunity { chain, target: self.target } +/// Represent the effect of fulfilling a condition. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +enum EdgeEffect { + /// If the condition is fulfilled, replace the current block's terminator by a single goto. + Goto { target: BasicBlock }, + /// If the condition is fulfilled, fulfill the condition `succ_condition` in `succ_block`. + Chain { succ_block: BasicBlock, succ_condition: ConditionIndex }, +} + +impl EdgeEffect { + fn block(self) -> BasicBlock { + match self { + EdgeEffect::Goto { target: bb } | EdgeEffect::Chain { succ_block: bb, .. } => bb, + } + } + + fn replace_block(&mut self, target: BasicBlock, new_target: BasicBlock) { + match self { + EdgeEffect::Goto { target: bb } | EdgeEffect::Chain { succ_block: bb, .. } => { + if *bb == target { + *bb = new_target + } + } + } } } -#[derive(Copy, Clone, Debug)] -struct ConditionSet<'a>(&'a [Condition]); - -impl HasBottom for ConditionSet<'_> { - const BOTTOM: Self = ConditionSet(&[]); - - fn is_bottom(&self) -> bool { - self.0.is_empty() - } +#[derive(Clone, Debug, Default)] +struct ConditionSet { + active: Vec<(ConditionIndex, Condition)>, + fulfilled: Vec, + targets: IndexVec>, + costs: IndexVec, } -impl<'a> ConditionSet<'a> { - fn is_empty(self) -> bool { - self.0.is_empty() +impl ConditionSet { + fn is_empty(&self) -> bool { + self.active.is_empty() } - fn iter(self) -> impl Iterator { - self.0.iter().copied() + #[tracing::instrument(level = "trace", skip(self))] + fn push_condition(&mut self, c: Condition, target: BasicBlock) { + let index = self.targets.push(vec![EdgeEffect::Goto { target }]); + self.costs.push(0); + self.active.push((index, c)); } - fn iter_matches(self, place: ValueIndex, value: ScalarInt) -> impl Iterator { - self.iter().filter(move |c| c.matches(place, value)) + /// Register fulfilled condition and remove it from the set. + fn fulfill_if(&mut self, f: impl Fn(Condition, &Vec) -> bool) { + self.active.retain(|&(index, condition)| { + let targets = &self.targets[index]; + if f(condition, targets) { + trace!(?index, ?condition, "fulfill"); + self.fulfilled.push(index); + false + } else { + true + } + }) } - fn register_matches( - &self, - place: ValueIndex, - value: ScalarInt, - match_bb: Option, - opportunities: &mut Vec, - ) { - self.iter_matches(place, value) - .for_each(|cond| opportunities.push(cond.into_opportunity(match_bb))) + /// Register fulfilled condition and remove them from the set. + fn fulfill_matches(&mut self, place: ValueIndex, value: ScalarInt) { + self.fulfill_if(|c, _| c.matches(place, value)) } - fn filter(self, arena: &'a DroplessArena, f: impl Fn(Condition) -> bool) -> ConditionSet<'a> { - let set = arena.alloc_from_iter(self.iter().filter(|&c| f(c))); - ConditionSet(set) + fn retain(&mut self, mut f: impl FnMut(Condition) -> bool) { + self.active.retain(|&(_, c)| f(c)) } - fn filter_map( - self, - arena: &'a DroplessArena, - f: impl Fn(Condition) -> Option, - ) -> ConditionSet<'a> { - let set = arena.alloc_from_iter(self.iter().filter_map(|c| f(c))); - ConditionSet(set) + fn retain_mut(&mut self, mut f: impl FnMut(Condition) -> Option) { + self.active.retain_mut(|(_, c)| { + if let Some(new) = f(*c) { + *c = new; + true + } else { + false + } + }) } - fn map(self, arena: &'a DroplessArena, f: impl Fn(Condition) -> Condition) -> ConditionSet<'a> { - let set = arena.alloc_from_iter(self.iter().map(|c| f(c))); - ConditionSet(set) + fn for_each_mut(&mut self, f: impl Fn(&mut Condition)) { + for (_, c) in &mut self.active { + f(c) + } } } impl<'a, 'tcx> TOFinder<'a, 'tcx> { - /// Recursion entry point to find threading opportunities. + /// Construct the condition set for `bb` from the terminator, without executing its effect. #[instrument(level = "trace", skip(self))] - fn start_from_switch(&mut self, bb: BasicBlock) { + fn populate_from_outgoing_edges(&mut self, bb: BasicBlock) -> ConditionSet { let bbdata = &self.body[bb]; - if bbdata.is_cleanup || self.maybe_loop_headers.contains(bb) { - return; - } - let Some((discr, targets)) = bbdata.terminator().kind.as_switch() else { return }; - let Some(discr) = discr.place() else { return }; - debug!(?discr, ?bb); - let discr_ty = discr.ty(self.body, self.tcx).ty; - let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return }; + // This should be the first time we populate `entry_states[bb]`. + debug_assert!(self.entry_states[bb].is_empty()); - let Some(discr) = self.map.find_value(discr.as_ref()) else { return }; - debug!(?discr); - - let cost = CostChecker::new(self.tcx, self.typing_env, None, self.body); - - let conds = if let Some((value, then, else_)) = targets.as_static_if() { - let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) else { return }; - self.arena.alloc_from_iter([ - Condition { place: discr, value, polarity: Polarity::Eq, target: then }, - Condition { place: discr, value, polarity: Polarity::Ne, target: else_ }, - ]) - } else { - self.arena.alloc_from_iter(targets.iter().filter_map(|(value, target)| { - let value = ScalarInt::try_from_uint(value, discr_layout.size)?; - Some(Condition { place: discr, value, polarity: Polarity::Eq, target }) - })) + let state_len = + bbdata.terminator().successors().map(|succ| self.entry_states[succ].active.len()).sum(); + let mut state = ConditionSet { + active: Vec::with_capacity(state_len), + targets: IndexVec::with_capacity(state_len), + fulfilled: Vec::new(), + costs: IndexVec::with_capacity(state_len), }; - let state = ConditionSet(conds); - self.find_opportunity(bb, state, cost, 0) + + // Use an index-set to deduplicate conditions coming from different successor blocks. + let mut known_conditions = + FxIndexSet::with_capacity_and_hasher(state_len, Default::default()); + let mut insert = |condition, succ_block, succ_condition, cost| { + let (index, new) = known_conditions.insert_full(condition); + let index = ConditionIndex::from_usize(index); + if new { + state.active.push((index, condition)); + let _index = state.targets.push(Vec::new()); + debug_assert_eq!(_index, index); + let _index = state.costs.push(u8::MAX); + debug_assert_eq!(_index, index); + } + let target = EdgeEffect::Chain { succ_block, succ_condition }; + debug_assert!( + !state.targets[index].contains(&target), + "duplicate targets for index={index:?} as {target:?} targets={:#?}", + &state.targets[index], + ); + state.targets[index].push(target); + state.costs[index] = std::cmp::min(state.costs[index], cost); + }; + + // A given block may have several times the same successor. + let mut seen = FxHashSet::default(); + for succ in bbdata.terminator().successors() { + if !seen.insert(succ) { + continue; + } + + // Do not thread through loop headers. + if self.maybe_loop_headers.contains(succ) { + continue; + } + + let succ_cost = self.cost(succ); + for &(succ_index, cond) in self.entry_states[succ].active.iter() { + let cost = self.entry_states[succ].costs[succ_index]; + if let Ok(cost) = ((cost as usize) + succ_cost).try_into() + && cost < MAX_COST + { + insert(cond, succ, succ_index, cost); + } + } + } + + let num_conditions = known_conditions.len(); + debug_assert_eq!(num_conditions, state.active.len()); + debug_assert_eq!(num_conditions, state.targets.len()); + debug_assert_eq!(num_conditions, state.costs.len()); + state.fulfilled.reserve(num_conditions); + + state } - /// Recursively walk statements backwards from this bb's terminator to find threading - /// opportunities. - #[instrument(level = "trace", skip(self, cost), ret)] - fn find_opportunity( - &mut self, - bb: BasicBlock, - mut state: ConditionSet<'a>, - mut cost: CostChecker<'_, 'tcx>, - depth: usize, - ) { - // Do not thread through loop headers. - if self.maybe_loop_headers.contains(bb) { - return; - } - - debug!(cost = ?cost.cost()); - for (statement_index, stmt) in - self.body.basic_blocks[bb].statements.iter().enumerate().rev() - { - if state.is_empty() { - return; - } - - cost.visit_statement(stmt, Location { block: bb, statement_index }); - if cost.cost() > MAX_COST { - return; - } - - // Attempt to turn the `current_condition` on `lhs` into a condition on another place. - self.process_statement(bb, stmt, &mut state); - - // When a statement mutates a place, assignments to that place that happen - // above the mutation cannot fulfill a condition. - // _1 = 5 // Whatever happens here, it won't change the result of a `SwitchInt`. - // _1 = 6 - if let Some((lhs, tail)) = self.mutated_statement(stmt) { - self.flood_state(lhs, tail, &mut state); - } - } - - if state.is_empty() || depth >= MAX_BACKTRACK { - return; - } - - let last_non_rec = self.opportunities.len(); - - let predecessors = &self.body.basic_blocks.predecessors()[bb]; - if let &[pred] = &predecessors[..] - && bb != START_BLOCK - { - let term = self.body.basic_blocks[pred].terminator(); - match term.kind { - TerminatorKind::SwitchInt { ref discr, ref targets } => { - self.process_switch_int(discr, targets, bb, &mut state); - self.find_opportunity(pred, state, cost, depth + 1); - } - _ => self.recurse_through_terminator(pred, state, &cost, depth), - } - } else if let &[ref predecessors @ .., last_pred] = &predecessors[..] { - for &pred in predecessors { - self.recurse_through_terminator(pred, state, &cost, depth); - } - self.recurse_through_terminator(last_pred, state, &cost, depth); - } - - let new_tos = &mut self.opportunities[last_non_rec..]; - debug!(?new_tos); - - // Try to deduplicate threading opportunities. - if new_tos.len() > 1 - && new_tos.len() == predecessors.len() - && predecessors - .iter() - .zip(new_tos.iter()) - .all(|(&pred, to)| to.chain == &[pred] && to.target == new_tos[0].target) - { - // All predecessors have a threading opportunity, and they all point to the same block. - debug!(?new_tos, "dedup"); - let first = &mut new_tos[0]; - *first = ThreadingOpportunity { chain: vec![bb], target: first.target }; - self.opportunities.truncate(last_non_rec + 1); - return; - } - - for op in self.opportunities[last_non_rec..].iter_mut() { - op.chain.push(bb); - } + fn cost(&self, bb: BasicBlock) -> usize { + *self.costs[bb].get_or_init(|| { + let bbdata = &self.body[bb]; + let mut cost = CostChecker::new(self.tcx, self.typing_env, None, self.body); + cost.visit_basic_block_data(bb, bbdata); + cost.cost() + }) } /// Remove all conditions in the state that alias given place. @@ -343,7 +362,7 @@ fn flood_state( &self, place: Place<'tcx>, extra_elem: Option, - state: &mut ConditionSet<'a>, + state: &mut ConditionSet, ) { if state.is_empty() { return; @@ -352,10 +371,11 @@ fn flood_state( self.map.for_each_aliasing_place(place.as_ref(), extra_elem, &mut |vi| { places_to_exclude.insert(vi); }); + trace!(?places_to_exclude, "flood_state"); if places_to_exclude.is_empty() { return; } - *state = state.filter(self.arena, |c| !places_to_exclude.contains(&c.place)); + state.retain(|c| !places_to_exclude.contains(&c.place)); } /// Extract the mutated place from a statement. @@ -398,32 +418,25 @@ fn mutated_statement( } } - #[instrument(level = "trace", skip(self))] - fn process_immediate( - &mut self, - bb: BasicBlock, - lhs: PlaceIndex, - rhs: ImmTy<'tcx>, - state: &mut ConditionSet<'a>, - ) { + #[instrument(level = "trace", skip(self, state))] + fn process_immediate(&mut self, lhs: PlaceIndex, rhs: ImmTy<'tcx>, state: &mut ConditionSet) { if let Some(lhs) = self.map.value(lhs) && let Immediate::Scalar(Scalar::Int(int)) = *rhs { - state.register_matches(lhs, int, Some(bb), &mut self.opportunities); + state.fulfill_matches(lhs, int) } } /// If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. - #[instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self, state))] fn process_constant( &mut self, - bb: BasicBlock, lhs: PlaceIndex, constant: OpTy<'tcx>, - state: &mut ConditionSet<'a>, + state: &mut ConditionSet, ) { let values_inside = self.map.values_inside(lhs); - if !state.iter().any(|cond| values_inside.contains(&cond.place)) { + if !state.active.iter().any(|&(_, cond)| values_inside.contains(&cond.place)) { return; } self.map.for_each_projection_value( @@ -451,34 +464,27 @@ fn process_constant( && let Some(imm) = imm.right() && let Immediate::Scalar(Scalar::Int(int)) = *imm { - state.register_matches(place, int, Some(bb), &mut self.opportunities); + state.fulfill_matches(place, int) } }, ); } - #[instrument(level = "trace", skip(self))] - fn process_copy(&mut self, lhs: PlaceIndex, rhs: PlaceIndex, state: &mut ConditionSet<'a>) { + #[instrument(level = "trace", skip(self, state))] + fn process_copy(&mut self, lhs: PlaceIndex, rhs: PlaceIndex, state: &mut ConditionSet) { let mut renames = FxHashMap::default(); self.map.for_each_value_pair(rhs, lhs, &mut |rhs, lhs| { renames.insert(lhs, rhs); }); - *state = state.map(self.arena, |mut c| { + state.for_each_mut(|c| { if let Some(rhs) = renames.get(&c.place) { c.place = *rhs } - c }); } - #[instrument(level = "trace", skip(self))] - fn process_operand( - &mut self, - bb: BasicBlock, - lhs: PlaceIndex, - rhs: &Operand<'tcx>, - state: &mut ConditionSet<'a>, - ) { + #[instrument(level = "trace", skip(self, state))] + fn process_operand(&mut self, lhs: PlaceIndex, rhs: &Operand<'tcx>, state: &mut ConditionSet) { match rhs { // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. Operand::Constant(constant) => { @@ -487,7 +493,7 @@ fn process_operand( else { return; }; - self.process_constant(bb, lhs, constant, state); + self.process_constant(lhs, constant, state); } // Transfer the conditions on the copied rhs. Operand::Move(rhs) | Operand::Copy(rhs) => { @@ -497,17 +503,16 @@ fn process_operand( } } - #[instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self, state))] fn process_assign( &mut self, - bb: BasicBlock, lhs_place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, - state: &mut ConditionSet<'a>, + state: &mut ConditionSet, ) { let Some(lhs) = self.map.find(lhs_place.as_ref()) else { return }; match rvalue { - Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state), + Rvalue::Use(operand) => self.process_operand(lhs, operand, state), // Transfer the conditions on the copy rhs. Rvalue::Discriminant(rhs) => { let Some(rhs) = self.map.find_discr(rhs.as_ref()) else { return }; @@ -526,7 +531,7 @@ fn process_assign( .discriminant_for_variant(agg_ty, *variant_index) .discard_err() { - self.process_immediate(bb, discr_target, discr_value, state); + self.process_immediate(discr_target, discr_value, state); } if let Some(idx) = self.map.apply(lhs, TrackElem::Variant(*variant_index)) { idx @@ -538,7 +543,7 @@ fn process_assign( }; for (field_index, operand) in operands.iter_enumerated() { if let Some(field) = self.map.apply(lhs, TrackElem::Field(field_index)) { - self.process_operand(bb, field, operand, state); + self.process_operand(field, operand, state); } } } @@ -547,17 +552,18 @@ fn process_assign( let layout = self.ecx.layout_of(operand.ty(self.body, self.tcx).ty).unwrap(); let Some(lhs) = self.map.value(lhs) else { return }; let Some(operand) = self.map.find_value(operand.as_ref()) else { return }; - *state = state.filter_map(self.arena, |mut cond| { - if cond.place == lhs { - cond.place = operand; - cond.value = self + state.retain_mut(|mut c| { + if c.place == lhs { + let value = self .ecx - .unary_op(UnOp::Not, &ImmTy::from_scalar_int(cond.value, layout)) + .unary_op(UnOp::Not, &ImmTy::from_scalar_int(c.value, layout)) .discard_err()? .to_scalar_int() .discard_err()?; + c.place = operand; + c.value = value; } - Some(cond) + Some(c) }); } // We expect `lhs ?= A`. We found `lhs = Eq(rhs, B)`. @@ -585,20 +591,13 @@ fn process_assign( else { return; }; - *state = state.map(self.arena, |c| { + state.for_each_mut(|c| { if c.place == lhs { - Condition { - place: operand, - value, - polarity: if c.matches(lhs, equals) { - Polarity::Eq - } else { - Polarity::Ne - }, - ..c - } - } else { - c + let polarity = + if c.matches(lhs, equals) { Polarity::Eq } else { Polarity::Ne }; + c.place = operand; + c.value = value; + c.polarity = polarity; } }); } @@ -607,13 +606,8 @@ fn process_assign( } } - #[instrument(level = "trace", skip(self))] - fn process_statement( - &mut self, - bb: BasicBlock, - stmt: &Statement<'tcx>, - state: &mut ConditionSet<'a>, - ) { + #[instrument(level = "trace", skip(self, state))] + fn process_statement(&mut self, stmt: &Statement<'tcx>, state: &mut ConditionSet) { // Below, `lhs` is the return value of `mutated_statement`, // the place to which `conditions` apply. @@ -631,61 +625,59 @@ fn process_statement( else { return; }; - self.process_immediate(bb, discr_target, discr, state) + self.process_immediate(discr_target, discr, state) } // If we expect `lhs ?= true`, we have an opportunity if we assume `lhs == true`. StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume( Operand::Copy(place) | Operand::Move(place), )) => { let Some(place) = self.map.find_value(place.as_ref()) else { return }; - state.register_matches(place, ScalarInt::TRUE, Some(bb), &mut self.opportunities) + state.fulfill_matches(place, ScalarInt::TRUE); } StatementKind::Assign(box (lhs_place, rhs)) => { - self.process_assign(bb, lhs_place, rhs, state) + self.process_assign(lhs_place, rhs, state) } _ => {} } } - #[instrument(level = "trace", skip(self, state, cost))] - fn recurse_through_terminator( - &mut self, - bb: BasicBlock, - mut state: ConditionSet<'a>, - cost: &CostChecker<'_, 'tcx>, - depth: usize, - ) { + /// Execute the terminator for block `bb` into state `entry_states[bb]`. + #[instrument(level = "trace", skip(self, state))] + fn process_terminator(&mut self, bb: BasicBlock, state: &mut ConditionSet) { let term = self.body.basic_blocks[bb].terminator(); let place_to_flood = match term.kind { - // We come from a target, so those are not possible. - TerminatorKind::UnwindResume - | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Return - | TerminatorKind::TailCall { .. } - | TerminatorKind::Unreachable - | TerminatorKind::CoroutineDrop => bug!("{term:?} has no terminators"), // Disallowed during optimizations. TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Yield { .. } => bug!("{term:?} invalid"), // Cannot reason about inline asm. - TerminatorKind::InlineAsm { .. } => return, + TerminatorKind::InlineAsm { .. } => { + state.active.clear(); + return; + } // `SwitchInt` is handled specially. - TerminatorKind::SwitchInt { .. } => return, - // We can recurse, no thing particular to do. - TerminatorKind::Goto { .. } => None, + TerminatorKind::SwitchInt { ref discr, ref targets } => { + return self.process_switch_int(discr, targets, state); + } + // These do not modify memory. + TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate(_) + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::CoroutineDrop + // Assertions can be no-op at codegen time, so treat them as such. + | TerminatorKind::Assert { .. } + | TerminatorKind::Goto { .. } => None, // Flood the overwritten place, and progress through. TerminatorKind::Drop { place: destination, .. } | TerminatorKind::Call { destination, .. } => Some(destination), - // Ignore, as this can be a no-op at codegen time. - TerminatorKind::Assert { .. } => None, + TerminatorKind::TailCall { .. } => Some(RETURN_PLACE.into()), }; - // We can recurse through this terminator. + // This terminator modifies `place_to_flood`, cleanup the associated conditions. if let Some(place_to_flood) = place_to_flood { - self.flood_state(place_to_flood, None, &mut state); + self.flood_state(place_to_flood, None, state); } - self.find_opportunity(bb, state, cost.clone(), depth + 1) } #[instrument(level = "trace", skip(self))] @@ -693,194 +685,262 @@ fn process_switch_int( &mut self, discr: &Operand<'tcx>, targets: &SwitchTargets, - target_bb: BasicBlock, - state: &mut ConditionSet<'a>, + state: &mut ConditionSet, ) { - debug_assert_ne!(target_bb, START_BLOCK); - debug_assert_eq!(self.body.basic_blocks.predecessors()[target_bb].len(), 1); - let Some(discr) = discr.place() else { return }; + let Some(discr_idx) = self.map.find_value(discr.as_ref()) else { return }; + let discr_ty = discr.ty(self.body, self.tcx).ty; - let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { - return; + let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return }; + + // Attempt to fulfill a condition using an outgoing branch's condition. + // Only support the case where there are no duplicated outgoing edges. + if targets.is_distinct() { + for &(index, c) in state.active.iter() { + if c.place != discr_idx { + continue; + } + + // Set of blocks `t` such that the edge `bb -> t` fulfills `c`. + let mut edges_fulfilling_condition = FxHashSet::default(); + + // On edge `bb -> tgt`, we know that `discr_idx == branch`. + for (branch, tgt) in targets.iter() { + if let Some(branch) = ScalarInt::try_from_uint(branch, discr_layout.size) + && c.matches(discr_idx, branch) + { + edges_fulfilling_condition.insert(tgt); + } + } + + // On edge `bb -> otherwise`, we only know that `discr` is different from all the + // constants in the switch. That's much weaker information than the equality we + // had in the previous arm. All we can conclude is that the replacement condition + // `discr != value` can be threaded, and nothing else. + if c.polarity == Polarity::Ne + && let Ok(value) = c.value.try_to_bits(discr_layout.size) + && targets.all_values().contains(&value.into()) + { + edges_fulfilling_condition.insert(targets.otherwise()); + } + + // Register that jumping to a `t` fulfills condition `c`. + // This does *not* mean that `c` is fulfilled in this block: inserting `index` in + // `fulfilled` is wrong if we have targets that jump to other blocks. + let condition_targets = &state.targets[index]; + + let new_edges: Vec<_> = condition_targets + .iter() + .copied() + .filter(|&target| match target { + EdgeEffect::Goto { .. } => false, + EdgeEffect::Chain { succ_block, .. } => { + edges_fulfilling_condition.contains(&succ_block) + } + }) + .collect(); + + if new_edges.len() == condition_targets.len() { + // If `new_edges == condition_targets`, do not bother creating a new + // `ConditionIndex`, we can use the existing one. + state.fulfilled.push(index); + } else { + // Fulfilling `index` may thread conditions that we do not want, + // so create a brand new index to immediately mark fulfilled. + let index = state.targets.push(new_edges); + let _index = state.costs.push(0); + debug_assert_eq!(_index, index); + state.fulfilled.push(index); + } + } + } + + // Introduce additional conditions of the form `discr ?= value` for each value in targets. + let mut mk_condition = |value, polarity, target| { + let c = Condition { place: discr_idx, value, polarity }; + state.push_condition(c, target); }; - let Some(discr) = self.map.find_value(discr.as_ref()) else { return }; - - if let Some((value, _)) = targets.iter().find(|&(_, target)| target == target_bb) { + if let Some((value, then_, else_)) = targets.as_static_if() { + // We have an `if`, generate both `discr == value` and `discr != value`. let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) else { return }; - debug_assert_eq!(targets.iter().filter(|&(_, target)| target == target_bb).count(), 1); - - // We are inside `target_bb`. Since we have a single predecessor, we know we passed - // through the `SwitchInt` before arriving here. Therefore, we know that - // `discr == value`. If one condition can be fulfilled by `discr == value`, - // that's an opportunity. - // - // The TO starts with `target_bb`, which will be added by `find_opportunity`, so we - // start with an empty bb chain. - state.register_matches(discr, value, None, &mut self.opportunities); - } else if let Some((value, _, else_bb)) = targets.as_static_if() - && target_bb == else_bb - { - let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) else { return }; - - // We only know that `discr != value`. That's much weaker information than - // the equality we had in the previous arm. All we can conclude is that - // the replacement condition `discr != value` can be threaded, and nothing else. - for c in state.iter() { - if c.place == discr && c.value == value && c.polarity == Polarity::Ne { - // The TO starts with `target_bb`, which will be added by `find_opportunity`, - // so we start with an empty bb chain. - self.opportunities.push(c.into_opportunity(None)); + mk_condition(value, Polarity::Eq, then_); + mk_condition(value, Polarity::Ne, else_); + } else { + // We have a general switch and we cannot express `discr != value0 && discr != value1`, + // so we only generate equality predicates. + for (value, target) in targets.iter() { + if let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) { + mk_condition(value, Polarity::Eq, target); } } } } } -struct OpportunitySet { - opportunities: Vec, - /// For each bb, give the TOs in which it appears. The pair corresponds to the index - /// in `opportunities` and the index in `ThreadingOpportunity::chain`. - involving_tos: IndexVec>, - /// Cache the number of predecessors for each block, as we clear the basic block cache.. - predecessors: IndexVec, +struct OpportunitySet<'a, 'tcx> { + basic_blocks: &'a mut IndexVec>, + entry_states: IndexVec, + /// Cache duplicated block. When cloning a basic block `bb` to fulfill a condition `c`, + /// record the target of this `bb with c` edge. + duplicates: FxHashMap<(BasicBlock, ConditionIndex), BasicBlock>, } -impl OpportunitySet { - fn new(body: &Body<'_>, opportunities: Vec) -> OpportunitySet { - let mut involving_tos = IndexVec::from_elem(Vec::new(), &body.basic_blocks); - for (index, to) in opportunities.iter().enumerate() { - for (ibb, &bb) in to.chain.iter().enumerate() { - involving_tos[bb].push((index, ibb)); - } - involving_tos[to.target].push((index, to.chain.len())); +impl<'a, 'tcx> OpportunitySet<'a, 'tcx> { + fn new( + body: &'a mut Body<'tcx>, + mut entry_states: IndexVec, + ) -> Option> { + trace!(def_id = ?body.source.def_id(), "apply"); + + if entry_states.iter().all(|state| state.fulfilled.is_empty()) { + return None; } - let predecessors = predecessor_count(body); - OpportunitySet { opportunities, involving_tos, predecessors } + + // Free some memory, because we will need to clone condition sets. + for state in entry_states.iter_mut() { + state.active = Default::default(); + state.costs = Default::default(); + } + let duplicates = Default::default(); + let basic_blocks = body.basic_blocks.as_mut(); + Some(OpportunitySet { basic_blocks, entry_states, duplicates }) } /// Apply the opportunities on the graph. - fn apply(&mut self, body: &mut Body<'_>) { - for i in 0..self.opportunities.len() { - self.apply_once(i, body); - } - } + #[instrument(level = "debug", skip(self))] + fn apply(mut self) { + let mut worklist = Vec::with_capacity(self.basic_blocks.len()); + worklist.push(START_BLOCK); - #[instrument(level = "trace", skip(self, body))] - fn apply_once(&mut self, index: usize, body: &mut Body<'_>) { - debug!(?self.predecessors); - debug!(?self.involving_tos); + // Use a `GrowableBitSet` and not a `DenseBitSet` as we are adding blocks. + let mut visited = GrowableBitSet::with_capacity(self.basic_blocks.len()); - // Check that `predecessors` satisfies its invariant. - debug_assert_eq!(self.predecessors, predecessor_count(body)); - - // Remove the TO from the vector to allow modifying the other ones later. - let op = &mut self.opportunities[index]; - debug!(?op); - let op_chain = std::mem::take(&mut op.chain); - let op_target = op.target; - debug_assert_eq!(op_chain.len(), op_chain.iter().collect::>().len()); - - let Some((current, chain)) = op_chain.split_first() else { return }; - let basic_blocks = body.basic_blocks.as_mut(); - - // Invariant: the control-flow is well-formed at the end of each iteration. - let mut current = *current; - for &succ in chain { - debug!(?current, ?succ); - - // `succ` must be a successor of `current`. If it is not, this means this TO is not - // satisfiable and a previous TO erased this edge, so we bail out. - if !basic_blocks[current].terminator().successors().any(|s| s == succ) { - debug!("impossible"); - return; - } - - // Fast path: `succ` is only used once, so we can reuse it directly. - if self.predecessors[succ] == 1 { - debug!("single"); - current = succ; + while let Some(bb) = worklist.pop() { + if !visited.insert(bb) { continue; } - let new_succ = basic_blocks.push(basic_blocks[succ].clone()); - debug!(?new_succ); + self.apply_once(bb); - // Replace `succ` by `new_succ` where it appears. - let mut num_edges = 0; - basic_blocks[current].terminator_mut().successors_mut(|s| { - if *s == succ { - *s = new_succ; - num_edges += 1; - } - }); - - // Update predecessors with the new block. - let _new_succ = self.predecessors.push(num_edges); - debug_assert_eq!(new_succ, _new_succ); - self.predecessors[succ] -= num_edges; - self.update_predecessor_count(basic_blocks[new_succ].terminator(), Update::Incr); - - // Replace the `current -> succ` edge by `current -> new_succ` in all the following - // TOs. This is necessary to avoid trying to thread through a non-existing edge. We - // use `involving_tos` here to avoid traversing the full set of TOs on each iteration. - let mut new_involved = Vec::new(); - for &(to_index, in_to_index) in &self.involving_tos[current] { - // That TO has already been applied, do nothing. - if to_index <= index { - continue; - } - - let other_to = &mut self.opportunities[to_index]; - if other_to.chain.get(in_to_index) != Some(¤t) { - continue; - } - let s = other_to.chain.get_mut(in_to_index + 1).unwrap_or(&mut other_to.target); - if *s == succ { - // `other_to` references the `current -> succ` edge, so replace `succ`. - *s = new_succ; - new_involved.push((to_index, in_to_index + 1)); - } - } - - // The TOs that we just updated now reference `new_succ`. Update `involving_tos` - // in case we need to duplicate an edge starting at `new_succ` later. - let _new_succ = self.involving_tos.push(new_involved); - debug_assert_eq!(new_succ, _new_succ); - - current = new_succ; - } - - let current = &mut basic_blocks[current]; - self.update_predecessor_count(current.terminator(), Update::Decr); - current.terminator_mut().kind = TerminatorKind::Goto { target: op_target }; - self.predecessors[op_target] += 1; - } - - fn update_predecessor_count(&mut self, terminator: &Terminator<'_>, incr: Update) { - match incr { - Update::Incr => { - for s in terminator.successors() { - self.predecessors[s] += 1; - } - } - Update::Decr => { - for s in terminator.successors() { - self.predecessors[s] -= 1; - } - } + // `apply_once` may have modified the terminator of `bb`. + // Only visit actual successors. + worklist.extend(self.basic_blocks[bb].terminator().successors()); } } -} -fn predecessor_count(body: &Body<'_>) -> IndexVec { - let mut predecessors: IndexVec<_, _> = - body.basic_blocks.predecessors().iter().map(|ps| ps.len()).collect(); - predecessors[START_BLOCK] += 1; // Account for the implicit entry edge. - predecessors -} + /// Apply the opportunities on `bb`. + #[instrument(level = "debug", skip(self))] + fn apply_once(&mut self, bb: BasicBlock) { + let state = &mut self.entry_states[bb]; + trace!(?state); -enum Update { - Incr, - Decr, + // We are modifying the `bb` in-place. Once a `EdgeEffect` has been applied, + // it does not need to be applied again. + let mut targets: Vec<_> = state + .fulfilled + .iter() + .flat_map(|&index| std::mem::take(&mut state.targets[index])) + .collect(); + targets.sort(); + targets.dedup(); + trace!(?targets); + + // Use a while-pop to allow modifying `targets` from inside the loop. + targets.reverse(); + while let Some(target) = targets.pop() { + debug!(?target); + trace!(term = ?self.basic_blocks[bb].terminator().kind); + + // By construction, `target.block()` is a successor of `bb`. + // When applying targets, we may change the set of successors. + // The match below updates the set of targets for consistency. + debug_assert!( + self.basic_blocks[bb].terminator().successors().contains(&target.block()), + "missing {target:?} in successors for {bb:?}, term={:?}", + self.basic_blocks[bb].terminator(), + ); + + match target { + EdgeEffect::Goto { target } => { + self.apply_goto(bb, target); + + // We now have `target` as single successor. Drop all other target blocks. + targets.retain(|t| t.block() == target); + // Also do this on targets that may be applied by a duplicate of `bb`. + for ts in self.entry_states[bb].targets.iter_mut() { + ts.retain(|t| t.block() == target); + } + } + EdgeEffect::Chain { succ_block, succ_condition } => { + let new_succ_block = self.apply_chain(bb, succ_block, succ_condition); + + // We have a new name for `target`, ensure it is correctly applied. + if let Some(new_succ_block) = new_succ_block { + for t in targets.iter_mut() { + t.replace_block(succ_block, new_succ_block) + } + // Also do this on targets that may be applied by a duplicate of `bb`. + for t in + self.entry_states[bb].targets.iter_mut().flat_map(|ts| ts.iter_mut()) + { + t.replace_block(succ_block, new_succ_block) + } + } + } + } + + trace!(post_term = ?self.basic_blocks[bb].terminator().kind); + } + } + + #[instrument(level = "debug", skip(self))] + fn apply_goto(&mut self, bb: BasicBlock, target: BasicBlock) { + self.basic_blocks[bb].terminator_mut().kind = TerminatorKind::Goto { target }; + } + + #[instrument(level = "debug", skip(self), ret)] + fn apply_chain( + &mut self, + bb: BasicBlock, + target: BasicBlock, + condition: ConditionIndex, + ) -> Option { + if self.entry_states[target].fulfilled.contains(&condition) { + // `target` already fulfills `condition`, so we do not need to thread anything. + trace!("fulfilled"); + return None; + } + + // We may be tempted to modify `target` in-place to avoid a clone. This is wrong. + // We may still have edges from other blocks to `target` that have not been created yet. + // For instance because we may be threading an edge coming from `bb`, + // or `target` may be a block duplicate for which we may still create predecessors. + + let new_target = *self.duplicates.entry((target, condition)).or_insert_with(|| { + // If we already have a duplicate of `target` which fulfills `condition`, reuse it. + // Otherwise, we clone a new bb to such ends. + let new_target = self.basic_blocks.push(self.basic_blocks[target].clone()); + trace!(?target, ?new_target, ?condition, "clone"); + + // By definition, `new_target` fulfills the same condition as `target`, with + // `condition` added. + let mut condition_set = self.entry_states[target].clone(); + condition_set.fulfilled.push(condition); + let _new_target = self.entry_states.push(condition_set); + debug_assert_eq!(new_target, _new_target); + + new_target + }); + trace!(?target, ?new_target, ?condition, "reuse"); + + // Replace `target` by `new_target` where it appears. + // This changes exactly `direct_count` edges. + self.basic_blocks[bb].terminator_mut().successors_mut(|s| { + if *s == target { + *s = new_target; + } + }); + + Some(new_target) + } } diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff new file mode 100644 index 000000000000..4c1f25ada076 --- /dev/null +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff @@ -0,0 +1,335 @@ +- // MIR for `chained_conditions` before JumpThreading ++ // MIR for `chained_conditions` after JumpThreading + + fn chained_conditions() -> u8 { + let mut _0: u8; + let _1: chained_conditions::BacktraceStyle; + let mut _2: std::option::Option; + let mut _3: &std::option::Option; + let mut _4: isize; + let _5: std::string::String; + let _6: &std::string::String; + let mut _7: bool; + let mut _8: &&std::string::String; + let _9: &std::string::String; + let mut _10: &&str; + let _11: &str; + let _12: std::string::String; + let _13: &std::string::String; + let mut _14: bool; + let mut _15: &&std::string::String; + let _16: &std::string::String; + let mut _17: &&str; + let _18: &str; + let mut _19: isize; + let mut _20: &&str; + let mut _21: &&str; + let mut _22: bool; + let mut _23: bool; + let mut _24: isize; + let mut _25: isize; + let mut _26: isize; + scope 1 { + debug format => _1; + } + scope 2 { + debug x => _5; + debug x => _6; + } + scope 3 { + debug x => _12; + debug x => _13; + } + scope 4 (inlined std::cmp::impls:: for &String>::eq) { + let mut _27: &std::string::String; + let mut _28: &str; + } + scope 5 (inlined std::cmp::impls:: for &String>::eq) { + let mut _29: &std::string::String; + let mut _30: &str; + } + + bb0: { + _22 = const false; + _23 = const false; + StorageLive(_1); + StorageLive(_2); + _2 = env_var() -> [return: bb1, unwind unreachable]; + } + + bb1: { + _22 = const true; + _23 = const true; + _4 = discriminant(_2); +- switchInt(move _4) -> [0: bb3, 1: bb4, otherwise: bb2]; ++ switchInt(move _4) -> [0: bb21, 1: bb4, otherwise: bb2]; + } + + bb2: { + unreachable; + } + + bb3: { + _1 = chained_conditions::BacktraceStyle::Off; + goto -> bb18; + } + + bb4: { + StorageLive(_6); + _6 = &((_2 as Some).0: std::string::String); + StorageLive(_7); + StorageLive(_8); + StorageLive(_9); + _9 = &(*_6); + _8 = &_9; + StorageLive(_10); + _21 = const chained_conditions::promoted[1]; + _10 = &(*_21); + StorageLive(_27); + StorageLive(_28); + _27 = copy (*_8); + _28 = copy (*_10); + _7 = >::eq(move _27, move _28) -> [return: bb19, unwind unreachable]; + } + + bb5: { + StorageDead(_10); + StorageDead(_9); + StorageDead(_8); + StorageDead(_7); + StorageLive(_5); + _23 = const false; + _5 = move ((_2 as Some).0: std::string::String); + _1 = chained_conditions::BacktraceStyle::Full; +- drop(_5) -> [return: bb7, unwind unreachable]; ++ drop(_5) -> [return: bb23, unwind unreachable]; + } + + bb6: { + StorageDead(_10); + StorageDead(_9); + StorageDead(_8); + StorageDead(_7); + StorageDead(_6); + StorageLive(_13); + _13 = &((_2 as Some).0: std::string::String); + StorageLive(_14); + StorageLive(_15); + StorageLive(_16); + _16 = &(*_13); + _15 = &_16; + StorageLive(_17); + _20 = const chained_conditions::promoted[0]; + _17 = &(*_20); + StorageLive(_29); + StorageLive(_30); + _29 = copy (*_15); + _30 = copy (*_17); + _14 = >::eq(move _29, move _30) -> [return: bb20, unwind unreachable]; + } + + bb7: { + StorageDead(_5); + StorageDead(_6); + goto -> bb18; + } + + bb8: { + StorageDead(_17); + StorageDead(_16); + StorageDead(_15); + StorageDead(_14); + StorageLive(_12); + _23 = const false; + _12 = move ((_2 as Some).0: std::string::String); + _1 = chained_conditions::BacktraceStyle::Off; +- drop(_12) -> [return: bb10, unwind unreachable]; ++ drop(_12) -> [return: bb30, unwind unreachable]; + } + + bb9: { + StorageDead(_17); + StorageDead(_16); + StorageDead(_15); + StorageDead(_14); + StorageDead(_13); + _1 = chained_conditions::BacktraceStyle::Short; +- goto -> bb18; ++ goto -> bb36; + } + + bb10: { + StorageDead(_12); + StorageDead(_13); + goto -> bb18; + } + + bb11: { + _0 = const 3_u8; + goto -> bb14; + } + + bb12: { + _0 = const 2_u8; + goto -> bb14; + } + + bb13: { + _0 = const 1_u8; + goto -> bb14; + } + + bb14: { + StorageDead(_1); + return; + } + + bb15: { + _22 = const false; + _23 = const false; + StorageDead(_2); + _19 = discriminant(_1); + switchInt(move _19) -> [0: bb13, 1: bb12, 2: bb11, otherwise: bb2]; + } + + bb16: { + switchInt(copy _23) -> [0: bb15, otherwise: bb17]; + } + + bb17: { + drop(((_2 as Some).0: std::string::String)) -> [return: bb15, unwind unreachable]; + } + + bb18: { + _24 = discriminant(_2); + switchInt(move _24) -> [1: bb16, otherwise: bb15]; + } + + bb19: { + StorageDead(_28); + StorageDead(_27); + switchInt(move _7) -> [0: bb6, otherwise: bb5]; + } + + bb20: { + StorageDead(_30); + StorageDead(_29); + switchInt(move _14) -> [0: bb9, otherwise: bb8]; ++ } ++ ++ bb21: { ++ _1 = chained_conditions::BacktraceStyle::Off; ++ goto -> bb40; ++ } ++ ++ bb22: { ++ StorageDead(_5); ++ StorageDead(_6); ++ goto -> bb18; ++ } ++ ++ bb23: { ++ StorageDead(_5); ++ StorageDead(_6); ++ goto -> bb25; ++ } ++ ++ bb24: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb16, otherwise: bb15]; ++ } ++ ++ bb25: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb28, otherwise: bb26]; ++ } ++ ++ bb26: { ++ _22 = const false; ++ _23 = const false; ++ StorageDead(_2); ++ _19 = discriminant(_1); ++ goto -> bb11; ++ } ++ ++ bb27: { ++ switchInt(copy _23) -> [0: bb15, otherwise: bb17]; ++ } ++ ++ bb28: { ++ goto -> bb26; ++ } ++ ++ bb29: { ++ StorageDead(_12); ++ StorageDead(_13); ++ goto -> bb18; ++ } ++ ++ bb30: { ++ StorageDead(_12); ++ StorageDead(_13); ++ goto -> bb32; ++ } ++ ++ bb31: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb16, otherwise: bb15]; ++ } ++ ++ bb32: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb35, otherwise: bb33]; ++ } ++ ++ bb33: { ++ _22 = const false; ++ _23 = const false; ++ StorageDead(_2); ++ _19 = discriminant(_1); ++ goto -> bb13; ++ } ++ ++ bb34: { ++ switchInt(copy _23) -> [0: bb15, otherwise: bb17]; ++ } ++ ++ bb35: { ++ goto -> bb33; ++ } ++ ++ bb36: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb38, otherwise: bb37]; ++ } ++ ++ bb37: { ++ _22 = const false; ++ _23 = const false; ++ StorageDead(_2); ++ _19 = discriminant(_1); ++ goto -> bb12; ++ } ++ ++ bb38: { ++ switchInt(copy _23) -> [0: bb37, otherwise: bb39]; ++ } ++ ++ bb39: { ++ drop(((_2 as Some).0: std::string::String)) -> [return: bb37, unwind unreachable]; ++ } ++ ++ bb40: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb41, otherwise: bb33]; ++ } ++ ++ bb41: { ++ goto -> bb42; ++ } ++ ++ bb42: { ++ drop(((_2 as Some).0: std::string::String)) -> [return: bb33, unwind unreachable]; + } + } + diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff new file mode 100644 index 000000000000..e45cb1714a99 --- /dev/null +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff @@ -0,0 +1,349 @@ +- // MIR for `chained_conditions` before JumpThreading ++ // MIR for `chained_conditions` after JumpThreading + + fn chained_conditions() -> u8 { + let mut _0: u8; + let _1: chained_conditions::BacktraceStyle; + let mut _2: std::option::Option; + let mut _3: &std::option::Option; + let mut _4: isize; + let _5: std::string::String; + let _6: &std::string::String; + let mut _7: bool; + let mut _8: &&std::string::String; + let _9: &std::string::String; + let mut _10: &&str; + let _11: &str; + let _12: std::string::String; + let _13: &std::string::String; + let mut _14: bool; + let mut _15: &&std::string::String; + let _16: &std::string::String; + let mut _17: &&str; + let _18: &str; + let mut _19: isize; + let mut _20: &&str; + let mut _21: &&str; + let mut _22: bool; + let mut _23: bool; + let mut _24: isize; + let mut _25: isize; + let mut _26: isize; + scope 1 { + debug format => _1; + } + scope 2 { + debug x => _5; + debug x => _6; + } + scope 3 { + debug x => _12; + debug x => _13; + } + scope 4 (inlined std::cmp::impls:: for &String>::eq) { + let mut _27: &std::string::String; + let mut _28: &str; + } + scope 5 (inlined std::cmp::impls:: for &String>::eq) { + let mut _29: &std::string::String; + let mut _30: &str; + } + + bb0: { + _22 = const false; + _23 = const false; + StorageLive(_1); + StorageLive(_2); + _22 = const true; + _23 = const true; +- _2 = env_var() -> [return: bb1, unwind continue]; ++ _2 = env_var() -> [return: bb25, unwind continue]; + } + + bb1: { + _4 = discriminant(_2); + switchInt(move _4) -> [0: bb3, 1: bb4, otherwise: bb2]; + } + + bb2: { + unreachable; + } + + bb3: { + _1 = chained_conditions::BacktraceStyle::Off; + goto -> bb19; + } + + bb4: { + StorageLive(_6); + _6 = &((_2 as Some).0: std::string::String); + StorageLive(_7); + StorageLive(_8); + StorageLive(_9); + _9 = &(*_6); + _8 = &_9; + StorageLive(_10); + _21 = const chained_conditions::promoted[1]; + _10 = &(*_21); + StorageLive(_27); + StorageLive(_28); + _27 = copy (*_8); + _28 = copy (*_10); + _7 = >::eq(move _27, move _28) -> [return: bb23, unwind: bb22]; + } + + bb5: { + StorageDead(_10); + StorageDead(_9); + StorageDead(_8); + StorageDead(_7); + StorageLive(_5); + _23 = const false; + _5 = move ((_2 as Some).0: std::string::String); + _1 = chained_conditions::BacktraceStyle::Full; +- drop(_5) -> [return: bb7, unwind: bb22]; ++ drop(_5) -> [return: bb28, unwind: bb22]; + } + + bb6: { + StorageDead(_10); + StorageDead(_9); + StorageDead(_8); + StorageDead(_7); + StorageDead(_6); + StorageLive(_13); + _13 = &((_2 as Some).0: std::string::String); + StorageLive(_14); + StorageLive(_15); + StorageLive(_16); + _16 = &(*_13); + _15 = &_16; + StorageLive(_17); + _20 = const chained_conditions::promoted[0]; + _17 = &(*_20); + StorageLive(_29); + StorageLive(_30); + _29 = copy (*_15); + _30 = copy (*_17); + _14 = >::eq(move _29, move _30) -> [return: bb24, unwind: bb22]; + } + + bb7: { + StorageDead(_5); + StorageDead(_6); + goto -> bb19; + } + + bb8: { + StorageDead(_17); + StorageDead(_16); + StorageDead(_15); + StorageDead(_14); + StorageLive(_12); + _23 = const false; + _12 = move ((_2 as Some).0: std::string::String); + _1 = chained_conditions::BacktraceStyle::Off; +- drop(_12) -> [return: bb10, unwind: bb22]; ++ drop(_12) -> [return: bb35, unwind: bb22]; + } + + bb9: { + StorageDead(_17); + StorageDead(_16); + StorageDead(_15); + StorageDead(_14); + StorageDead(_13); + _1 = chained_conditions::BacktraceStyle::Short; +- goto -> bb19; ++ goto -> bb41; + } + + bb10: { + StorageDead(_12); + StorageDead(_13); + goto -> bb19; + } + + bb11: { + _0 = const 3_u8; + goto -> bb14; + } + + bb12: { + _0 = const 2_u8; + goto -> bb14; + } + + bb13: { + _0 = const 1_u8; + goto -> bb14; + } + + bb14: { + StorageDead(_1); + return; + } + + bb15 (cleanup): { + resume; + } + + bb16: { + _22 = const false; + _23 = const false; + StorageDead(_2); + _19 = discriminant(_1); + switchInt(move _19) -> [0: bb13, 1: bb12, 2: bb11, otherwise: bb2]; + } + + bb17: { + switchInt(copy _23) -> [0: bb16, otherwise: bb18]; + } + + bb18: { + drop(((_2 as Some).0: std::string::String)) -> [return: bb16, unwind: bb15]; + } + + bb19: { + _24 = discriminant(_2); + switchInt(move _24) -> [1: bb17, otherwise: bb16]; + } + + bb20 (cleanup): { + switchInt(copy _23) -> [0: bb15, otherwise: bb21]; + } + + bb21 (cleanup): { + drop(((_2 as Some).0: std::string::String)) -> [return: bb15, unwind terminate(cleanup)]; + } + + bb22 (cleanup): { + _26 = discriminant(_2); + switchInt(move _26) -> [1: bb20, otherwise: bb15]; + } + + bb23: { + StorageDead(_28); + StorageDead(_27); + switchInt(move _7) -> [0: bb6, otherwise: bb5]; + } + + bb24: { + StorageDead(_30); + StorageDead(_29); + switchInt(move _14) -> [0: bb9, otherwise: bb8]; ++ } ++ ++ bb25: { ++ _4 = discriminant(_2); ++ switchInt(move _4) -> [0: bb26, 1: bb4, otherwise: bb2]; ++ } ++ ++ bb26: { ++ _1 = chained_conditions::BacktraceStyle::Off; ++ goto -> bb44; ++ } ++ ++ bb27: { ++ StorageDead(_5); ++ StorageDead(_6); ++ goto -> bb19; ++ } ++ ++ bb28: { ++ StorageDead(_5); ++ StorageDead(_6); ++ goto -> bb30; ++ } ++ ++ bb29: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb17, otherwise: bb16]; ++ } ++ ++ bb30: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb33, otherwise: bb31]; ++ } ++ ++ bb31: { ++ _22 = const false; ++ _23 = const false; ++ StorageDead(_2); ++ _19 = discriminant(_1); ++ goto -> bb11; ++ } ++ ++ bb32: { ++ switchInt(copy _23) -> [0: bb16, otherwise: bb18]; ++ } ++ ++ bb33: { ++ goto -> bb31; ++ } ++ ++ bb34: { ++ StorageDead(_12); ++ StorageDead(_13); ++ goto -> bb19; ++ } ++ ++ bb35: { ++ StorageDead(_12); ++ StorageDead(_13); ++ goto -> bb37; ++ } ++ ++ bb36: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb17, otherwise: bb16]; ++ } ++ ++ bb37: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb40, otherwise: bb38]; ++ } ++ ++ bb38: { ++ _22 = const false; ++ _23 = const false; ++ StorageDead(_2); ++ _19 = discriminant(_1); ++ goto -> bb13; ++ } ++ ++ bb39: { ++ switchInt(copy _23) -> [0: bb16, otherwise: bb18]; ++ } ++ ++ bb40: { ++ goto -> bb38; ++ } ++ ++ bb41: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb43, otherwise: bb42]; ++ } ++ ++ bb42: { ++ _22 = const false; ++ _23 = const false; ++ StorageDead(_2); ++ _19 = discriminant(_1); ++ goto -> bb12; ++ } ++ ++ bb43: { ++ switchInt(copy _23) -> [0: bb42, otherwise: bb18]; ++ } ++ ++ bb44: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb45, otherwise: bb38]; ++ } ++ ++ bb45: { ++ goto -> bb18; + } + } + diff --git a/tests/mir-opt/jump_threading.custom_discr.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.custom_discr.JumpThreading.panic-abort.diff index a86371794ebe..0b11a0d188fb 100644 --- a/tests/mir-opt/jump_threading.custom_discr.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.custom_discr.JumpThreading.panic-abort.diff @@ -23,14 +23,14 @@ bb2: { _2 = CustomDiscr::B; - goto -> bb3; +- goto -> bb3; ++ goto -> bb8; } bb3: { StorageDead(_3); _4 = discriminant(_2); -- switchInt(move _4) -> [35: bb5, otherwise: bb4]; -+ goto -> bb4; + switchInt(move _4) -> [35: bb5, otherwise: bb4]; } bb4: { @@ -52,6 +52,12 @@ + StorageDead(_3); + _4 = discriminant(_2); + goto -> bb5; ++ } ++ ++ bb8: { ++ StorageDead(_3); ++ _4 = discriminant(_2); ++ goto -> bb4; } } diff --git a/tests/mir-opt/jump_threading.custom_discr.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.custom_discr.JumpThreading.panic-unwind.diff index a86371794ebe..0b11a0d188fb 100644 --- a/tests/mir-opt/jump_threading.custom_discr.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.custom_discr.JumpThreading.panic-unwind.diff @@ -23,14 +23,14 @@ bb2: { _2 = CustomDiscr::B; - goto -> bb3; +- goto -> bb3; ++ goto -> bb8; } bb3: { StorageDead(_3); _4 = discriminant(_2); -- switchInt(move _4) -> [35: bb5, otherwise: bb4]; -+ goto -> bb4; + switchInt(move _4) -> [35: bb5, otherwise: bb4]; } bb4: { @@ -52,6 +52,12 @@ + StorageDead(_3); + _4 = discriminant(_2); + goto -> bb5; ++ } ++ ++ bb8: { ++ StorageDead(_3); ++ _4 = discriminant(_2); ++ goto -> bb4; } } diff --git a/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-abort.diff index d17f2752f58e..4933e42d0f40 100644 --- a/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-abort.diff @@ -9,13 +9,13 @@ bb0: { _2 = const true; _3 = const true; - switchInt(copy _1) -> [0: bb3, 1: bb3, 2: bb1, otherwise: bb2]; +- switchInt(copy _1) -> [0: bb3, 1: bb3, 2: bb1, otherwise: bb2]; ++ switchInt(copy _1) -> [0: bb10, 1: bb10, 2: bb9, otherwise: bb2]; } bb1: { _3 = const false; -- goto -> bb4; -+ goto -> bb9; + goto -> bb4; } bb2: { @@ -40,8 +40,7 @@ } bb7: { -- goto -> bb5; -+ goto -> bb10; + goto -> bb5; } bb8: { @@ -49,10 +48,40 @@ + } + + bb9: { -+ goto -> bb5; ++ _3 = const false; ++ goto -> bb12; + } + + bb10: { ++ _2 = const false; ++ goto -> bb15; ++ } ++ ++ bb11: { ++ switchInt(copy _3) -> [0: bb5, otherwise: bb7]; ++ } ++ ++ bb12: { ++ goto -> bb13; ++ } ++ ++ bb13: { ++ goto -> bb8; ++ } ++ ++ bb14: { ++ switchInt(copy _3) -> [0: bb5, otherwise: bb7]; ++ } ++ ++ bb15: { ++ goto -> bb16; ++ } ++ ++ bb16: { ++ goto -> bb17; ++ } ++ ++ bb17: { goto -> bb6; } } diff --git a/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-unwind.diff index d17f2752f58e..4933e42d0f40 100644 --- a/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-unwind.diff @@ -9,13 +9,13 @@ bb0: { _2 = const true; _3 = const true; - switchInt(copy _1) -> [0: bb3, 1: bb3, 2: bb1, otherwise: bb2]; +- switchInt(copy _1) -> [0: bb3, 1: bb3, 2: bb1, otherwise: bb2]; ++ switchInt(copy _1) -> [0: bb10, 1: bb10, 2: bb9, otherwise: bb2]; } bb1: { _3 = const false; -- goto -> bb4; -+ goto -> bb9; + goto -> bb4; } bb2: { @@ -40,8 +40,7 @@ } bb7: { -- goto -> bb5; -+ goto -> bb10; + goto -> bb5; } bb8: { @@ -49,10 +48,40 @@ + } + + bb9: { -+ goto -> bb5; ++ _3 = const false; ++ goto -> bb12; + } + + bb10: { ++ _2 = const false; ++ goto -> bb15; ++ } ++ ++ bb11: { ++ switchInt(copy _3) -> [0: bb5, otherwise: bb7]; ++ } ++ ++ bb12: { ++ goto -> bb13; ++ } ++ ++ bb13: { ++ goto -> bb8; ++ } ++ ++ bb14: { ++ switchInt(copy _3) -> [0: bb5, otherwise: bb7]; ++ } ++ ++ bb15: { ++ goto -> bb16; ++ } ++ ++ bb16: { ++ goto -> bb17; ++ } ++ ++ bb17: { goto -> bb6; } } diff --git a/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-abort.diff index 083a6e7487a0..d17e7d974443 100644 --- a/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-abort.diff @@ -13,12 +13,14 @@ bb1: { _2 = const 5_u8; - goto -> bb3; +- goto -> bb3; ++ goto -> bb7; } bb2: { _2 = const 5_u8; - goto -> bb3; +- goto -> bb3; ++ goto -> bb7; } bb3: { @@ -28,8 +30,7 @@ bb4: { _4 = const 15_i32; -- switchInt(copy _2) -> [5: bb5, otherwise: bb6]; -+ goto -> bb5; + switchInt(copy _2) -> [5: bb5, otherwise: bb6]; } bb5: { @@ -40,6 +41,16 @@ bb6: { _0 = const 9_u8; return; ++ } ++ ++ bb7: { ++ _3 = const 13_i32; ++ goto -> bb8; ++ } ++ ++ bb8: { ++ _4 = const 15_i32; ++ goto -> bb5; } } diff --git a/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-unwind.diff index 083a6e7487a0..d17e7d974443 100644 --- a/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-unwind.diff @@ -13,12 +13,14 @@ bb1: { _2 = const 5_u8; - goto -> bb3; +- goto -> bb3; ++ goto -> bb7; } bb2: { _2 = const 5_u8; - goto -> bb3; +- goto -> bb3; ++ goto -> bb7; } bb3: { @@ -28,8 +30,7 @@ bb4: { _4 = const 15_i32; -- switchInt(copy _2) -> [5: bb5, otherwise: bb6]; -+ goto -> bb5; + switchInt(copy _2) -> [5: bb5, otherwise: bb6]; } bb5: { @@ -40,6 +41,16 @@ bb6: { _0 = const 9_u8; return; ++ } ++ ++ bb7: { ++ _3 = const 13_i32; ++ goto -> bb8; ++ } ++ ++ bb8: { ++ _4 = const 15_i32; ++ goto -> bb5; } } diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff index 79599f856115..97b8d484194f 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff @@ -97,8 +97,7 @@ StorageDead(_10); StorageDead(_4); _5 = discriminant(_3); -- switchInt(move _5) -> [0: bb2, 1: bb3, otherwise: bb1]; -+ goto -> bb2; + switchInt(move _5) -> [0: bb2, 1: bb3, otherwise: bb1]; } bb6: { @@ -114,7 +113,8 @@ bb7: { _11 = move ((_4 as Ok).0: i32); _3 = ControlFlow::, i32>::Continue(copy _11); - goto -> bb5; +- goto -> bb5; ++ goto -> bb9; + } + + bb8: { @@ -124,6 +124,15 @@ + StorageDead(_4); + _5 = discriminant(_3); + goto -> bb3; ++ } ++ ++ bb9: { ++ StorageDead(_12); ++ StorageDead(_11); ++ StorageDead(_10); ++ StorageDead(_4); ++ _5 = discriminant(_3); ++ goto -> bb2; } } diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff index 79599f856115..97b8d484194f 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff @@ -97,8 +97,7 @@ StorageDead(_10); StorageDead(_4); _5 = discriminant(_3); -- switchInt(move _5) -> [0: bb2, 1: bb3, otherwise: bb1]; -+ goto -> bb2; + switchInt(move _5) -> [0: bb2, 1: bb3, otherwise: bb1]; } bb6: { @@ -114,7 +113,8 @@ bb7: { _11 = move ((_4 as Ok).0: i32); _3 = ControlFlow::, i32>::Continue(copy _11); - goto -> bb5; +- goto -> bb5; ++ goto -> bb9; + } + + bb8: { @@ -124,6 +124,15 @@ + StorageDead(_4); + _5 = discriminant(_3); + goto -> bb3; ++ } ++ ++ bb9: { ++ StorageDead(_12); ++ StorageDead(_11); ++ StorageDead(_10); ++ StorageDead(_4); ++ _5 = discriminant(_3); ++ goto -> bb2; } } diff --git a/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-abort.diff index 09c0ad6d4856..271b7f00078c 100644 --- a/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-abort.diff @@ -7,19 +7,18 @@ let mut _3: u8; bb0: { - switchInt(copy _1) -> [3: bb1, otherwise: bb2]; +- switchInt(copy _1) -> [3: bb1, otherwise: bb2]; ++ switchInt(copy _1) -> [3: bb9, otherwise: bb10]; } bb1: { _2 = copy _1; -- switchInt(copy _2) -> [3: bb3, otherwise: bb4]; -+ goto -> bb3; + switchInt(copy _2) -> [3: bb3, otherwise: bb4]; } bb2: { _3 = copy _1; -- switchInt(copy _3) -> [3: bb5, otherwise: bb6]; -+ goto -> bb6; + switchInt(copy _3) -> [3: bb5, otherwise: bb6]; } bb3: { @@ -49,6 +48,16 @@ bb8: { _0 = const 11_u8; return; ++ } ++ ++ bb9: { ++ _2 = copy _1; ++ goto -> bb3; ++ } ++ ++ bb10: { ++ _3 = copy _1; ++ goto -> bb6; } } diff --git a/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-unwind.diff index 09c0ad6d4856..271b7f00078c 100644 --- a/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-unwind.diff @@ -7,19 +7,18 @@ let mut _3: u8; bb0: { - switchInt(copy _1) -> [3: bb1, otherwise: bb2]; +- switchInt(copy _1) -> [3: bb1, otherwise: bb2]; ++ switchInt(copy _1) -> [3: bb9, otherwise: bb10]; } bb1: { _2 = copy _1; -- switchInt(copy _2) -> [3: bb3, otherwise: bb4]; -+ goto -> bb3; + switchInt(copy _2) -> [3: bb3, otherwise: bb4]; } bb2: { _3 = copy _1; -- switchInt(copy _3) -> [3: bb5, otherwise: bb6]; -+ goto -> bb6; + switchInt(copy _3) -> [3: bb5, otherwise: bb6]; } bb3: { @@ -49,6 +48,16 @@ bb8: { _0 = const 11_u8; return; ++ } ++ ++ bb9: { ++ _2 = copy _1; ++ goto -> bb3; ++ } ++ ++ bb10: { ++ _3 = copy _1; ++ goto -> bb6; } } diff --git a/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-abort.diff index 9a8bdc8f4d95..4f80acd07338 100644 --- a/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-abort.diff @@ -8,13 +8,13 @@ bb0: { _3 = const false; - switchInt(copy _1) -> [1: bb1, otherwise: bb2]; +- switchInt(copy _1) -> [1: bb1, otherwise: bb2]; ++ switchInt(copy _1) -> [1: bb8, otherwise: bb2]; } bb1: { _2 = const false; -- goto -> bb3; -+ goto -> bb8; + goto -> bb3; } bb2: { @@ -47,10 +47,19 @@ + } + + bb8: { -+ goto -> bb9; ++ _2 = const false; ++ goto -> bb10; + } + + bb9: { ++ switchInt(copy _2) -> [0: bb4, otherwise: bb5]; ++ } ++ ++ bb10: { ++ goto -> bb11; ++ } ++ ++ bb11: { + goto -> bb6; } } diff --git a/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-unwind.diff index 9a8bdc8f4d95..4f80acd07338 100644 --- a/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-unwind.diff @@ -8,13 +8,13 @@ bb0: { _3 = const false; - switchInt(copy _1) -> [1: bb1, otherwise: bb2]; +- switchInt(copy _1) -> [1: bb1, otherwise: bb2]; ++ switchInt(copy _1) -> [1: bb8, otherwise: bb2]; } bb1: { _2 = const false; -- goto -> bb3; -+ goto -> bb8; + goto -> bb3; } bb2: { @@ -47,10 +47,19 @@ + } + + bb8: { -+ goto -> bb9; ++ _2 = const false; ++ goto -> bb10; + } + + bb9: { ++ switchInt(copy _2) -> [0: bb4, otherwise: bb5]; ++ } ++ ++ bb10: { ++ goto -> bb11; ++ } ++ ++ bb11: { + goto -> bb6; } } diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index ad46a02b83f4..e841643e7ce5 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -19,9 +19,9 @@ fn too_complex(x: Result) -> Option { // CHECK: goto -> bb8; // CHECK: bb3: { // CHECK: [[controlflow]] = ControlFlow::::Continue( - // CHECK: goto -> bb4; + // CHECK: goto -> bb9; // CHECK: bb4: { - // CHECK: goto -> bb6; + // CHECK: switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb1]; // CHECK: bb5: { // CHECK: {{_.*}} = copy (([[controlflow]] as Break).0: usize); // CHECK: _0 = Option::::None; @@ -34,6 +34,8 @@ fn too_complex(x: Result) -> Option { // CHECK: return; // CHECK: bb8: { // CHECK: goto -> bb5; + // CHECK: bb9: { + // CHECK: goto -> bb6; match { match x { Ok(v) => ControlFlow::Continue(v), @@ -63,7 +65,7 @@ fn identity(x: Result) -> Result { // CHECK: bb4: { // CHECK: return; // CHECK: bb5: { - // CHECK: goto -> bb2; + // CHECK: switchInt(move _5) -> [0: bb2, 1: bb3, otherwise: bb1]; // CHECK: bb6: { // CHECK: {{_.*}} = move (([[x]] as Err).0: i32); // CHECK: [[controlflow]] = ControlFlow::, i32>::Break( @@ -71,9 +73,11 @@ fn identity(x: Result) -> Result { // CHECK: bb7: { // CHECK: {{_.*}} = move (([[x]] as Ok).0: i32); // CHECK: [[controlflow]] = ControlFlow::, i32>::Continue( - // CHECK: goto -> bb5; + // CHECK: goto -> bb9; // CHECK: bb8: { // CHECK: goto -> bb3; + // CHECK: bb9: { + // CHECK: goto -> bb2; Ok(x?) } @@ -160,9 +164,9 @@ fn custom_discr(x: bool) -> u8 { // CHECK: goto -> bb7; // CHECK: bb2: { // CHECK: {{_.*}} = CustomDiscr::B; - // CHECK: goto -> bb3; + // CHECK: goto -> bb8; // CHECK: bb3: { - // CHECK: goto -> bb4; + // CHECK: switchInt(move _4) -> [35: bb5, otherwise: bb4]; // CHECK: bb4: { // CHECK: _0 = const 13_u8; // CHECK: goto -> bb6; @@ -173,6 +177,8 @@ fn custom_discr(x: bool) -> u8 { // CHECK: return; // CHECK: bb7: { // CHECK: goto -> bb5; + // CHECK: bb8: { + // CHECK: goto -> bb4; match if x { CustomDiscr::A } else { CustomDiscr::B } { CustomDiscr::A => 5, _ => 13, @@ -185,22 +191,18 @@ fn multiple_match(x: u8) -> u8 { mir! { { // CHECK: bb0: { - // CHECK: switchInt(copy [[x:_.*]]) -> [3: bb1, otherwise: bb2]; + // CHECK: switchInt(copy [[x:_.*]]) -> [3: bb9, otherwise: bb10]; match x { 3 => bb1, _ => bb2 } } bb1 = { // We know `x == 3`, so we can take `bb3`. // CHECK: bb1: { - // CHECK: {{_.*}} = copy [[x]]; - // CHECK: goto -> bb3; let y = x; match y { 3 => bb3, _ => bb4 } } bb2 = { // We know `x != 3`, so we can take `bb6`. // CHECK: bb2: { - // CHECK: [[z:_.*]] = copy [[x]]; - // CHECK: goto -> bb6; let z = x; match z { 3 => bb5, _ => bb6 } } @@ -228,7 +230,7 @@ fn multiple_match(x: u8) -> u8 { bb6 = { // We know `z != 3`, so we CANNOT take `bb7`. // CHECK: bb6: { - // CHECK: switchInt(copy [[z]]) -> [1: bb7, otherwise: bb8]; + // CHECK: switchInt(copy [[z:_.*]]) -> [1: bb7, otherwise: bb8]; match z { 1 => bb7, _ => bb8 } } bb7 = { @@ -245,6 +247,14 @@ fn multiple_match(x: u8) -> u8 { RET = 11; Return() } + // We know `x == 3`, so we can take `bb3`. + // CHECK: bb9: { + // CHECK: {{_.*}} = copy [[x]]; + // CHECK: goto -> bb3; + // We know `x != 3`, so we can take `bb6`. + // CHECK: bb10: { + // CHECK: [[z]] = copy [[x]]; + // CHECK: goto -> bb6; } } @@ -263,14 +273,14 @@ fn duplicate_chain(x: bool) -> u8 { bb1 = { // CHECK: bb1: { // CHECK: [[a:_.*]] = const 5_u8; - // CHECK: goto -> bb3; + // CHECK: goto -> bb7; a = 5; Goto(bb3) } bb2 = { // CHECK: bb2: { // CHECK: [[a]] = const 5_u8; - // CHECK: goto -> bb3; + // CHECK: goto -> bb7; a = 5; Goto(bb3) } @@ -284,8 +294,7 @@ fn duplicate_chain(x: bool) -> u8 { bb4 = { // CHECK: bb4: { // CHECK: {{_.*}} = const 15_i32; - // CHECK-NOT: switchInt( - // CHECK: goto -> bb5; + // CHECK: switchInt(copy _2) -> [5: bb5, otherwise: bb6]; let c = 15; match a { 5 => bb5, _ => bb6 } } @@ -303,6 +312,12 @@ fn duplicate_chain(x: bool) -> u8 { RET = 9; Return() } + // CHECK: bb7: { + // CHECK-NEXT: {{_.*}} = const 13_i32; + // CHECK-NEXT: goto -> bb8; + // CHECK: bb8: { + // CHECK-NEXT: {{_.*}} = const 15_i32; + // CHECK-NEXT: goto -> bb5; } } @@ -368,13 +383,13 @@ fn renumbered_bb(x: bool) -> u8 { let b: bool; { // CHECK: bb0: { - // CHECK: switchInt({{.*}}) -> [1: bb1, otherwise: bb2]; + // CHECK: switchInt({{.*}}) -> [1: bb8, otherwise: bb2]; b = false; match x { true => bb1, _ => bb2 } } bb1 = { // CHECK: bb1: { - // CHECK: goto -> bb8; + // CHECK: goto -> bb3; a = false; Goto(bb3) } @@ -413,12 +428,18 @@ fn renumbered_bb(x: bool) -> u8 { RET = 11; Return() } - // Duplicate of bb3. + // Duplicate of bb1. // CHECK: bb8: { - // CHECK-NEXT: goto -> bb9; - // Duplicate of bb4. + // CHECK: goto -> bb10; + // Duplicate of bb3. // CHECK: bb9: { - // CHECK-NEXT: goto -> bb6; + // CHECK: switchInt(copy _2) -> [0: bb4, otherwise: bb5]; + // Duplicate of bb9. + // CHECK: bb10: { + // CHECK: goto -> bb11; + // Duplicate of bb4. + // CHECK: bb11: { + // CHECK: goto -> bb6; } } @@ -433,22 +454,26 @@ fn disappearing_bb(x: u8) -> u8 { let a: bool; let b: bool; { + // CHECK: bb0: { a = true; b = true; + // CHECK: switchInt({{.*}}) -> [0: bb10, 1: bb10, 2: bb9, otherwise: bb2]; match x { 0 => bb3, 1 => bb3, 2 => bb1, _ => bb2 } } bb1 = { // CHECK: bb1: { - // CHECK: goto -> bb9; + // CHECK: goto -> bb4; b = false; Goto(bb4) } bb2 = { + // CHECK: bb2: { + // CHECK: unreachable; Unreachable() } bb3 = { // CHECK: bb3: { - // CHECK: goto -> bb10; + // CHECK: goto -> bb4; a = false; Goto(bb4) } @@ -468,9 +493,23 @@ fn disappearing_bb(x: u8) -> u8 { Goto(bb6) } // CHECK: bb9: { - // CHECK: goto -> bb5; + // CHECK: goto -> bb12; // CHECK: bb10: { - // CHECK: goto -> bb6; + // CHECK: goto -> bb15; + // CHECK: bb11: { + // CHECK: switchInt(copy _3) -> [0: bb5, otherwise: bb7]; + // CHECK: bb12: { + // CHECK: goto -> bb13; + // CHECK: bb13: { + // CHECK: goto -> bb8; + // CHECK: bb14: { + // CHECK: switchInt(copy _3) -> [0: bb5, otherwise: bb7]; + // CHECK: bb15: { + // CHECK: goto -> bb16; + // CHECK: bb16: { + // CHECK: goto -> bb17; + // CHECK: bb17: { + // CHECK: goto -> bb6; } } @@ -604,6 +643,36 @@ pub fn logical_not() -> i32 { if !a == true { 1 } else { 0 } } +/// Verify that we correctly handle threading multiple conditions on the same bb. +/// One version of the implementation was buggy and mutated a bb that would be duplicated later. +fn chained_conditions() -> u8 { + // CHECK-LABEL: fn chained_conditions( + + #[inline(never)] + fn env_var() -> Option { + None + } + + enum BacktraceStyle { + Off, + Short, + Full, + }; + + let format = match env_var() { + Some(x) if &x == "full" => BacktraceStyle::Full, + Some(x) if &x == "0" => BacktraceStyle::Off, + Some(_) => BacktraceStyle::Short, + None => BacktraceStyle::Off, + }; + + match format { + BacktraceStyle::Off => 1, + BacktraceStyle::Short => 2, + BacktraceStyle::Full => 3, + } +} + fn main() { // CHECK-LABEL: fn main( too_complex(Ok(0)); @@ -640,3 +709,4 @@ fn main() { // EMIT_MIR jump_threading.floats.JumpThreading.diff // EMIT_MIR jump_threading.bitwise_not.JumpThreading.diff // EMIT_MIR jump_threading.logical_not.JumpThreading.diff +// EMIT_MIR jump_threading.chained_conditions.JumpThreading.diff diff --git a/tests/mir-opt/jump_threading.too_complex.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.too_complex.JumpThreading.panic-abort.diff index 7de359298922..6e0cf5ec41ab 100644 --- a/tests/mir-opt/jump_threading.too_complex.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.too_complex.JumpThreading.panic-abort.diff @@ -57,13 +57,13 @@ _2 = ControlFlow::::Continue(move _5); StorageDead(_5); StorageDead(_4); - goto -> bb4; +- goto -> bb4; ++ goto -> bb9; } bb4: { _8 = discriminant(_2); -- switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb1]; -+ goto -> bb6; + switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb1]; } bb5: { @@ -93,6 +93,11 @@ + bb8: { + _8 = discriminant(_2); + goto -> bb5; ++ } ++ ++ bb9: { ++ _8 = discriminant(_2); ++ goto -> bb6; } } diff --git a/tests/mir-opt/jump_threading.too_complex.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.too_complex.JumpThreading.panic-unwind.diff index 7de359298922..6e0cf5ec41ab 100644 --- a/tests/mir-opt/jump_threading.too_complex.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.too_complex.JumpThreading.panic-unwind.diff @@ -57,13 +57,13 @@ _2 = ControlFlow::::Continue(move _5); StorageDead(_5); StorageDead(_4); - goto -> bb4; +- goto -> bb4; ++ goto -> bb9; } bb4: { _8 = discriminant(_2); -- switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb1]; -+ goto -> bb6; + switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb1]; } bb5: { @@ -93,6 +93,11 @@ + bb8: { + _8 = discriminant(_2); + goto -> bb5; ++ } ++ ++ bb9: { ++ _8 = discriminant(_2); ++ goto -> bb6; } } diff --git a/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir index e235fa35c023..578aff4f7129 100644 --- a/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir @@ -7,12 +7,11 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool { scope 1 (inlined ::le) { let mut _6: std::option::Option; scope 2 (inlined Option::::is_some_and:: bool {std::cmp::Ordering::is_le}>) { - let mut _11: isize; - let _12: std::cmp::Ordering; + let _11: std::cmp::Ordering; scope 3 { scope 4 (inlined bool {std::cmp::Ordering::is_le} as FnOnce<(std::cmp::Ordering,)>>::call_once - shim(fn(std::cmp::Ordering) -> bool {std::cmp::Ordering::is_le})) { scope 5 (inlined std::cmp::Ordering::is_le) { - let mut _13: i8; + let mut _12: i8; scope 6 (inlined std::cmp::Ordering::as_raw) { } } @@ -37,7 +36,7 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool { } bb0: { - StorageLive(_12); + StorageLive(_11); StorageLive(_6); StorageLive(_5); StorageLive(_7); @@ -64,42 +63,19 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool { StorageDead(_8); _6 = Option::::Some(move _10); StorageDead(_10); - StorageDead(_7); - StorageDead(_5); - StorageLive(_11); - goto -> bb4; + goto -> bb2; } bb2: { StorageDead(_7); StorageDead(_5); - StorageLive(_11); - _11 = discriminant(_6); - switchInt(move _11) -> [0: bb3, 1: bb4, otherwise: bb6]; - } - - bb3: { - _0 = const false; - goto -> bb5; - } - - bb4: { - _12 = move ((_6 as Some).0: std::cmp::Ordering); - StorageLive(_13); - _13 = discriminant(_12); - _0 = Le(move _13, const 0_i8); - StorageDead(_13); - goto -> bb5; - } - - bb5: { - StorageDead(_11); - StorageDead(_6); + _11 = move ((_6 as Some).0: std::cmp::Ordering); + StorageLive(_12); + _12 = discriminant(_11); + _0 = Le(move _12, const 0_i8); StorageDead(_12); + StorageDead(_6); + StorageDead(_11); return; } - - bb6: { - unreachable; - } } diff --git a/tests/mir-opt/pre-codegen/derived_ord.rs b/tests/mir-opt/pre-codegen/derived_ord.rs index 823e0f6d09c2..a67756c22d46 100644 --- a/tests/mir-opt/pre-codegen/derived_ord.rs +++ b/tests/mir-opt/pre-codegen/derived_ord.rs @@ -13,22 +13,23 @@ pub fn demo_le(a: &MultiField, b: &MultiField) -> bool { // CHECK: inlined{{.+}}is_some_and // CHECK: inlined ::partial_cmp - // CHECK: [[A0:_[0-9]+]] = copy ((*_1).0: char); - // CHECK: [[B0:_[0-9]+]] = copy ((*_2).0: char); - // CHECK: Cmp(move [[A0]], move [[B0]]); + // CHECK: bb0: { + // CHECK: [[A0:_[0-9]+]] = copy ((*_1).0: char); + // CHECK: [[B0:_[0-9]+]] = copy ((*_2).0: char); + // CHECK: Cmp(move [[A0]], move [[B0]]); + // CHECK: [[D0:_[0-9]+]] = discriminant({{.+}}); + // CHECK: switchInt(move [[D0]]) -> [0: bb1, otherwise: bb2]; - // CHECK: [[D0:_[0-9]+]] = discriminant({{.+}}); - // CHECK: switchInt(move [[D0]]) -> [0: bb{{[0-9]+}}, otherwise: bb{{[0-9]+}}]; + // CHECK: bb1: { + // CHECK: [[A1:_[0-9]+]] = copy ((*_1).1: i16); + // CHECK: [[B1:_[0-9]+]] = copy ((*_2).1: i16); + // CHECK: Cmp(move [[A1]], move [[B1]]); + // CHECK: goto -> bb2; - // CHECK: [[A1:_[0-9]+]] = copy ((*_1).1: i16); - // CHECK: [[B1:_[0-9]+]] = copy ((*_2).1: i16); - // CHECK: Cmp(move [[A1]], move [[B1]]); - - // CHECK: [[D1:_[0-9]+]] = discriminant({{.+}}); - // CHECK: switchInt(move [[D1]]) -> [0: bb{{[0-9]+}}, 1: bb{{[0-9]+}}, otherwise: bb{{[0-9]+}}]; - - // CHECK: [[D2:_[0-9]+]] = discriminant({{.+}}); - // CHECK: _0 = Le(move [[D2]], const 0_i8); + // CHECK: bb2: { + // CHECK: [[D2:_[0-9]+]] = discriminant({{.+}}); + // CHECK: _0 = Le(move [[D2]], const 0_i8); + // CHECK: return; *a <= *b } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index 104987b0fdda..f72611b7cb8e 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -211,12 +211,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { bb7: { StorageDead(_16); - StorageDead(_22); - StorageDead(_13); - StorageDead(_20); - StorageDead(_19); - StorageDead(_12); - StorageDead(_11); goto -> bb10; } @@ -226,16 +220,16 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb9: { + goto -> bb10; + } + + bb10: { StorageDead(_22); StorageDead(_13); StorageDead(_20); StorageDead(_19); StorageDead(_12); StorageDead(_11); - goto -> bb10; - } - - bb10: { StorageDead(_23); StorageDead(_26); StorageDead(_25); diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index 4d0e3548e7d6..b210efb1f46c 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -173,12 +173,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb7: { StorageDead(_15); - StorageDead(_21); - StorageDead(_12); - StorageDead(_19); - StorageDead(_18); - StorageDead(_11); - StorageDead(_10); goto -> bb10; } @@ -188,16 +182,16 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb9: { + goto -> bb10; + } + + bb10: { StorageDead(_21); StorageDead(_12); StorageDead(_19); StorageDead(_18); StorageDead(_11); StorageDead(_10); - goto -> bb10; - } - - bb10: { StorageDead(_22); drop(_2) -> [return: bb11, unwind unreachable]; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index 2b5d8c27d710..ab6e2bf0b36b 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -173,12 +173,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb7: { StorageDead(_15); - StorageDead(_21); - StorageDead(_12); - StorageDead(_19); - StorageDead(_18); - StorageDead(_11); - StorageDead(_10); goto -> bb10; } @@ -188,16 +182,16 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb9: { + goto -> bb10; + } + + bb10: { StorageDead(_21); StorageDead(_12); StorageDead(_19); StorageDead(_18); StorageDead(_11); StorageDead(_10); - goto -> bb10; - } - - bb10: { StorageDead(_22); drop(_2) -> [return: bb11, unwind continue]; } diff --git a/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff b/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff index ce9d812701a8..34f451fc698c 100644 --- a/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff +++ b/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff @@ -69,8 +69,7 @@ StorageDead(_7); StorageDead(_6); _3 = discriminant(_2); -- switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; -+ goto -> bb2; + switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; } bb5: { @@ -86,7 +85,8 @@ bb6: { _7 = copy ((_1 as Ok).0: i32); _2 = ControlFlow::, i32>::Continue(copy _7); - goto -> bb4; +- goto -> bb4; ++ goto -> bb8; + } + + bb7: { @@ -95,6 +95,14 @@ + StorageDead(_6); + _3 = discriminant(_2); + goto -> bb3; ++ } ++ ++ bb8: { ++ StorageDead(_8); ++ StorageDead(_7); ++ StorageDead(_6); ++ _3 = discriminant(_2); ++ goto -> bb2; } } diff --git a/tests/mir-opt/separate_const_switch.too_complex.JumpThreading.diff b/tests/mir-opt/separate_const_switch.too_complex.JumpThreading.diff index c88c63e0c133..794c28ab46da 100644 --- a/tests/mir-opt/separate_const_switch.too_complex.JumpThreading.diff +++ b/tests/mir-opt/separate_const_switch.too_complex.JumpThreading.diff @@ -44,13 +44,13 @@ bb3: { _4 = copy ((_1 as Ok).0: i32); _2 = ControlFlow::::Continue(copy _4); - goto -> bb4; +- goto -> bb4; ++ goto -> bb9; } bb4: { _6 = discriminant(_2); -- switchInt(move _6) -> [0: bb6, 1: bb5, otherwise: bb1]; -+ goto -> bb6; + switchInt(move _6) -> [0: bb6, 1: bb5, otherwise: bb1]; } bb5: { @@ -75,6 +75,11 @@ + bb8: { + _6 = discriminant(_2); + goto -> bb5; ++ } ++ ++ bb9: { ++ _6 = discriminant(_2); ++ goto -> bb6; } } From 2a63fde0bcb1d6615dc245e8f6e6d7cad07857a7 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 14 Sep 2025 19:48:25 +0000 Subject: [PATCH 055/585] Simplify condition graph. --- .../rustc_mir_transform/src/jump_threading.rs | 90 +++++++++++++++- ..._conditions.JumpThreading.panic-abort.diff | 101 +++++++----------- ...conditions.JumpThreading.panic-unwind.diff | 96 ++++++----------- ...ppearing_bb.JumpThreading.panic-abort.diff | 41 +++---- ...pearing_bb.JumpThreading.panic-unwind.diff | 41 +++---- ...icate_chain.JumpThreading.panic-abort.diff | 19 +--- ...cate_chain.JumpThreading.panic-unwind.diff | 19 +--- ...tiple_match.JumpThreading.panic-abort.diff | 19 +--- ...iple_match.JumpThreading.panic-unwind.diff | 19 +--- ...numbered_bb.JumpThreading.panic-abort.diff | 17 ++- ...umbered_bb.JumpThreading.panic-unwind.diff | 17 ++- tests/mir-opt/jump_threading.rs | 69 +++++------- 12 files changed, 244 insertions(+), 304 deletions(-) diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index a99297bf2f9a..1b6a0203519c 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -134,7 +134,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { finder.entry_states[bb] = state; } - if let Some(opportunities) = OpportunitySet::new(body, finder.entry_states) { + let mut entry_states = finder.entry_states; + simplify_conditions(body, &mut entry_states); + + if let Some(opportunities) = OpportunitySet::new(body, entry_states) { opportunities.apply(); } } @@ -777,6 +780,91 @@ fn process_switch_int( } } +/// Propagate fulfilled conditions forward in the CFG to reduce the amount of duplication. +#[instrument(level = "debug", skip(body, entry_states))] +fn simplify_conditions(body: &Body<'_>, entry_states: &mut IndexVec) { + let basic_blocks = &body.basic_blocks; + let reverse_postorder = basic_blocks.reverse_postorder(); + + // Start by computing the number of *incoming edges* for each block. + // We do not use the cached `basic_blocks.predecessors` as we only want reachable predecessors. + let mut predecessors = IndexVec::from_elem(0, &entry_states); + predecessors[START_BLOCK] = 1; // Account for the implicit entry edge. + for &bb in reverse_postorder { + let term = basic_blocks[bb].terminator(); + for s in term.successors() { + predecessors[s] += 1; + } + } + + // Compute the number of edges into each block that carry each condition. + let mut fulfill_in_pred_count = IndexVec::from_fn_n( + |bb: BasicBlock| IndexVec::from_elem_n(0, entry_states[bb].targets.len()), + entry_states.len(), + ); + + // By traversing in RPO, we increase the likelihood to visit predecessors before successors. + for &bb in reverse_postorder { + let preds = predecessors[bb]; + trace!(?bb, ?preds); + + // We have removed all the input edges towards this block. Just skip visiting it. + if preds == 0 { + continue; + } + + let state = &mut entry_states[bb]; + trace!(?state); + + // Conditions that are fulfilled in all the predecessors, are fulfilled in `bb`. + trace!(fulfilled_count = ?fulfill_in_pred_count[bb]); + for (condition, &cond_preds) in fulfill_in_pred_count[bb].iter_enumerated() { + if cond_preds == preds { + trace!(?condition); + state.fulfilled.push(condition); + } + } + + // We want to count how many times each condition is fulfilled, + // so ensure we are not counting the same edge twice. + let mut targets: Vec<_> = state + .fulfilled + .iter() + .flat_map(|&index| state.targets[index].iter().copied()) + .collect(); + targets.sort(); + targets.dedup(); + trace!(?targets); + + // We may modify the set of successors by applying edges, so track them here. + let mut successors = basic_blocks[bb].terminator().successors().collect::>(); + + targets.reverse(); + while let Some(target) = targets.pop() { + match target { + EdgeEffect::Goto { target } => { + // We update the count of predecessors. If target or any successor has not been + // processed yet, this increases the likelihood we find something relevant. + predecessors[target] += 1; + for &s in successors.iter() { + predecessors[s] -= 1; + } + // Only process edges that still exist. + targets.retain(|t| t.block() == target); + successors.clear(); + successors.push(target); + } + EdgeEffect::Chain { succ_block, succ_condition } => { + // `predecessors` is the number of incoming *edges* in each block. + // Count the number of edges that apply `succ_condition` into `succ_block`. + let count = successors.iter().filter(|&&s| s == succ_block).count(); + fulfill_in_pred_count[succ_block][succ_condition] += count; + } + } + } + } +} + struct OpportunitySet<'a, 'tcx> { basic_blocks: &'a mut IndexVec>, entry_states: IndexVec, diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff index 4c1f25ada076..bbe9ba806dc7 100644 --- a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff @@ -61,8 +61,7 @@ _22 = const true; _23 = const true; _4 = discriminant(_2); -- switchInt(move _4) -> [0: bb3, 1: bb4, otherwise: bb2]; -+ switchInt(move _4) -> [0: bb21, 1: bb4, otherwise: bb2]; + switchInt(move _4) -> [0: bb3, 1: bb4, otherwise: bb2]; } bb2: { @@ -71,7 +70,8 @@ bb3: { _1 = chained_conditions::BacktraceStyle::Off; - goto -> bb18; +- goto -> bb18; ++ goto -> bb35; } bb4: { @@ -101,8 +101,7 @@ _23 = const false; _5 = move ((_2 as Some).0: std::string::String); _1 = chained_conditions::BacktraceStyle::Full; -- drop(_5) -> [return: bb7, unwind unreachable]; -+ drop(_5) -> [return: bb23, unwind unreachable]; + drop(_5) -> [return: bb7, unwind unreachable]; } bb6: { @@ -131,7 +130,8 @@ bb7: { StorageDead(_5); StorageDead(_6); - goto -> bb18; +- goto -> bb18; ++ goto -> bb22; } bb8: { @@ -143,8 +143,7 @@ _23 = const false; _12 = move ((_2 as Some).0: std::string::String); _1 = chained_conditions::BacktraceStyle::Off; -- drop(_12) -> [return: bb10, unwind unreachable]; -+ drop(_12) -> [return: bb30, unwind unreachable]; + drop(_12) -> [return: bb10, unwind unreachable]; } bb9: { @@ -155,13 +154,14 @@ StorageDead(_13); _1 = chained_conditions::BacktraceStyle::Short; - goto -> bb18; -+ goto -> bb36; ++ goto -> bb31; } bb10: { StorageDead(_12); StorageDead(_13); - goto -> bb18; +- goto -> bb18; ++ goto -> bb27; } bb11: { @@ -218,33 +218,16 @@ + } + + bb21: { -+ _1 = chained_conditions::BacktraceStyle::Off; -+ goto -> bb40; -+ } -+ -+ bb22: { -+ StorageDead(_5); -+ StorageDead(_6); -+ goto -> bb18; -+ } -+ -+ bb23: { -+ StorageDead(_5); -+ StorageDead(_6); -+ goto -> bb25; -+ } -+ -+ bb24: { + _24 = discriminant(_2); + switchInt(move _24) -> [1: bb16, otherwise: bb15]; + } + -+ bb25: { ++ bb22: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb28, otherwise: bb26]; ++ switchInt(move _24) -> [1: bb25, otherwise: bb23]; + } + -+ bb26: { ++ bb23: { + _22 = const false; + _23 = const false; + StorageDead(_2); @@ -252,37 +235,25 @@ + goto -> bb11; + } + -+ bb27: { ++ bb24: { + switchInt(copy _23) -> [0: bb15, otherwise: bb17]; + } + -+ bb28: { -+ goto -> bb26; ++ bb25: { ++ goto -> bb23; + } + -+ bb29: { -+ StorageDead(_12); -+ StorageDead(_13); -+ goto -> bb18; -+ } -+ -+ bb30: { -+ StorageDead(_12); -+ StorageDead(_13); -+ goto -> bb32; -+ } -+ -+ bb31: { ++ bb26: { + _24 = discriminant(_2); + switchInt(move _24) -> [1: bb16, otherwise: bb15]; + } + -+ bb32: { ++ bb27: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb35, otherwise: bb33]; ++ switchInt(move _24) -> [1: bb30, otherwise: bb28]; + } + -+ bb33: { ++ bb28: { + _22 = const false; + _23 = const false; + StorageDead(_2); @@ -290,20 +261,20 @@ + goto -> bb13; + } + -+ bb34: { ++ bb29: { + switchInt(copy _23) -> [0: bb15, otherwise: bb17]; + } + -+ bb35: { -+ goto -> bb33; ++ bb30: { ++ goto -> bb28; + } + -+ bb36: { ++ bb31: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb38, otherwise: bb37]; ++ switchInt(move _24) -> [1: bb33, otherwise: bb32]; + } + -+ bb37: { ++ bb32: { + _22 = const false; + _23 = const false; + StorageDead(_2); @@ -311,25 +282,25 @@ + goto -> bb12; + } + -+ bb38: { -+ switchInt(copy _23) -> [0: bb37, otherwise: bb39]; ++ bb33: { ++ switchInt(copy _23) -> [0: bb32, otherwise: bb34]; + } + -+ bb39: { -+ drop(((_2 as Some).0: std::string::String)) -> [return: bb37, unwind unreachable]; ++ bb34: { ++ drop(((_2 as Some).0: std::string::String)) -> [return: bb32, unwind unreachable]; + } + -+ bb40: { ++ bb35: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb41, otherwise: bb33]; ++ switchInt(move _24) -> [1: bb36, otherwise: bb28]; + } + -+ bb41: { -+ goto -> bb42; ++ bb36: { ++ goto -> bb37; + } + -+ bb42: { -+ drop(((_2 as Some).0: std::string::String)) -> [return: bb33, unwind unreachable]; ++ bb37: { ++ drop(((_2 as Some).0: std::string::String)) -> [return: bb28, unwind unreachable]; } } diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff index e45cb1714a99..a40e4446aef1 100644 --- a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff @@ -56,8 +56,7 @@ StorageLive(_2); _22 = const true; _23 = const true; -- _2 = env_var() -> [return: bb1, unwind continue]; -+ _2 = env_var() -> [return: bb25, unwind continue]; + _2 = env_var() -> [return: bb1, unwind continue]; } bb1: { @@ -71,7 +70,8 @@ bb3: { _1 = chained_conditions::BacktraceStyle::Off; - goto -> bb19; +- goto -> bb19; ++ goto -> bb38; } bb4: { @@ -101,8 +101,7 @@ _23 = const false; _5 = move ((_2 as Some).0: std::string::String); _1 = chained_conditions::BacktraceStyle::Full; -- drop(_5) -> [return: bb7, unwind: bb22]; -+ drop(_5) -> [return: bb28, unwind: bb22]; + drop(_5) -> [return: bb7, unwind: bb22]; } bb6: { @@ -131,7 +130,8 @@ bb7: { StorageDead(_5); StorageDead(_6); - goto -> bb19; +- goto -> bb19; ++ goto -> bb26; } bb8: { @@ -143,8 +143,7 @@ _23 = const false; _12 = move ((_2 as Some).0: std::string::String); _1 = chained_conditions::BacktraceStyle::Off; -- drop(_12) -> [return: bb10, unwind: bb22]; -+ drop(_12) -> [return: bb35, unwind: bb22]; + drop(_12) -> [return: bb10, unwind: bb22]; } bb9: { @@ -155,13 +154,14 @@ StorageDead(_13); _1 = chained_conditions::BacktraceStyle::Short; - goto -> bb19; -+ goto -> bb41; ++ goto -> bb35; } bb10: { StorageDead(_12); StorageDead(_13); - goto -> bb19; +- goto -> bb19; ++ goto -> bb31; } bb11: { @@ -235,38 +235,16 @@ + } + + bb25: { -+ _4 = discriminant(_2); -+ switchInt(move _4) -> [0: bb26, 1: bb4, otherwise: bb2]; -+ } -+ -+ bb26: { -+ _1 = chained_conditions::BacktraceStyle::Off; -+ goto -> bb44; -+ } -+ -+ bb27: { -+ StorageDead(_5); -+ StorageDead(_6); -+ goto -> bb19; -+ } -+ -+ bb28: { -+ StorageDead(_5); -+ StorageDead(_6); -+ goto -> bb30; -+ } -+ -+ bb29: { + _24 = discriminant(_2); + switchInt(move _24) -> [1: bb17, otherwise: bb16]; + } + -+ bb30: { ++ bb26: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb33, otherwise: bb31]; ++ switchInt(move _24) -> [1: bb29, otherwise: bb27]; + } + -+ bb31: { ++ bb27: { + _22 = const false; + _23 = const false; + StorageDead(_2); @@ -274,37 +252,25 @@ + goto -> bb11; + } + -+ bb32: { ++ bb28: { + switchInt(copy _23) -> [0: bb16, otherwise: bb18]; + } + -+ bb33: { -+ goto -> bb31; ++ bb29: { ++ goto -> bb27; + } + -+ bb34: { -+ StorageDead(_12); -+ StorageDead(_13); -+ goto -> bb19; -+ } -+ -+ bb35: { -+ StorageDead(_12); -+ StorageDead(_13); -+ goto -> bb37; -+ } -+ -+ bb36: { ++ bb30: { + _24 = discriminant(_2); + switchInt(move _24) -> [1: bb17, otherwise: bb16]; + } + -+ bb37: { ++ bb31: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb40, otherwise: bb38]; ++ switchInt(move _24) -> [1: bb34, otherwise: bb32]; + } + -+ bb38: { ++ bb32: { + _22 = const false; + _23 = const false; + StorageDead(_2); @@ -312,20 +278,20 @@ + goto -> bb13; + } + -+ bb39: { ++ bb33: { + switchInt(copy _23) -> [0: bb16, otherwise: bb18]; + } + -+ bb40: { -+ goto -> bb38; ++ bb34: { ++ goto -> bb32; + } + -+ bb41: { ++ bb35: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb43, otherwise: bb42]; ++ switchInt(move _24) -> [1: bb37, otherwise: bb36]; + } + -+ bb42: { ++ bb36: { + _22 = const false; + _23 = const false; + StorageDead(_2); @@ -333,16 +299,16 @@ + goto -> bb12; + } + -+ bb43: { -+ switchInt(copy _23) -> [0: bb42, otherwise: bb18]; ++ bb37: { ++ switchInt(copy _23) -> [0: bb36, otherwise: bb18]; + } + -+ bb44: { ++ bb38: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb45, otherwise: bb38]; ++ switchInt(move _24) -> [1: bb39, otherwise: bb32]; + } + -+ bb45: { ++ bb39: { + goto -> bb18; } } diff --git a/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-abort.diff index 4933e42d0f40..4955d05214ff 100644 --- a/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-abort.diff @@ -9,13 +9,13 @@ bb0: { _2 = const true; _3 = const true; -- switchInt(copy _1) -> [0: bb3, 1: bb3, 2: bb1, otherwise: bb2]; -+ switchInt(copy _1) -> [0: bb10, 1: bb10, 2: bb9, otherwise: bb2]; + switchInt(copy _1) -> [0: bb3, 1: bb3, 2: bb1, otherwise: bb2]; } bb1: { _3 = const false; - goto -> bb4; +- goto -> bb4; ++ goto -> bb10; } bb2: { @@ -24,7 +24,8 @@ bb3: { _2 = const false; - goto -> bb4; +- goto -> bb4; ++ goto -> bb13; } bb4: { @@ -48,40 +49,30 @@ + } + + bb9: { -+ _3 = const false; -+ goto -> bb12; ++ switchInt(copy _3) -> [0: bb5, otherwise: bb7]; + } + + bb10: { -+ _2 = const false; -+ goto -> bb15; ++ goto -> bb11; + } + + bb11: { -+ switchInt(copy _3) -> [0: bb5, otherwise: bb7]; -+ } -+ -+ bb12: { -+ goto -> bb13; -+ } -+ -+ bb13: { + goto -> bb8; + } + -+ bb14: { ++ bb12: { + switchInt(copy _3) -> [0: bb5, otherwise: bb7]; + } + ++ bb13: { ++ goto -> bb14; ++ } ++ ++ bb14: { ++ goto -> bb15; ++ } ++ + bb15: { -+ goto -> bb16; -+ } -+ -+ bb16: { -+ goto -> bb17; -+ } -+ -+ bb17: { goto -> bb6; } } diff --git a/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-unwind.diff index 4933e42d0f40..4955d05214ff 100644 --- a/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.disappearing_bb.JumpThreading.panic-unwind.diff @@ -9,13 +9,13 @@ bb0: { _2 = const true; _3 = const true; -- switchInt(copy _1) -> [0: bb3, 1: bb3, 2: bb1, otherwise: bb2]; -+ switchInt(copy _1) -> [0: bb10, 1: bb10, 2: bb9, otherwise: bb2]; + switchInt(copy _1) -> [0: bb3, 1: bb3, 2: bb1, otherwise: bb2]; } bb1: { _3 = const false; - goto -> bb4; +- goto -> bb4; ++ goto -> bb10; } bb2: { @@ -24,7 +24,8 @@ bb3: { _2 = const false; - goto -> bb4; +- goto -> bb4; ++ goto -> bb13; } bb4: { @@ -48,40 +49,30 @@ + } + + bb9: { -+ _3 = const false; -+ goto -> bb12; ++ switchInt(copy _3) -> [0: bb5, otherwise: bb7]; + } + + bb10: { -+ _2 = const false; -+ goto -> bb15; ++ goto -> bb11; + } + + bb11: { -+ switchInt(copy _3) -> [0: bb5, otherwise: bb7]; -+ } -+ -+ bb12: { -+ goto -> bb13; -+ } -+ -+ bb13: { + goto -> bb8; + } + -+ bb14: { ++ bb12: { + switchInt(copy _3) -> [0: bb5, otherwise: bb7]; + } + ++ bb13: { ++ goto -> bb14; ++ } ++ ++ bb14: { ++ goto -> bb15; ++ } ++ + bb15: { -+ goto -> bb16; -+ } -+ -+ bb16: { -+ goto -> bb17; -+ } -+ -+ bb17: { goto -> bb6; } } diff --git a/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-abort.diff index d17e7d974443..083a6e7487a0 100644 --- a/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-abort.diff @@ -13,14 +13,12 @@ bb1: { _2 = const 5_u8; -- goto -> bb3; -+ goto -> bb7; + goto -> bb3; } bb2: { _2 = const 5_u8; -- goto -> bb3; -+ goto -> bb7; + goto -> bb3; } bb3: { @@ -30,7 +28,8 @@ bb4: { _4 = const 15_i32; - switchInt(copy _2) -> [5: bb5, otherwise: bb6]; +- switchInt(copy _2) -> [5: bb5, otherwise: bb6]; ++ goto -> bb5; } bb5: { @@ -41,16 +40,6 @@ bb6: { _0 = const 9_u8; return; -+ } -+ -+ bb7: { -+ _3 = const 13_i32; -+ goto -> bb8; -+ } -+ -+ bb8: { -+ _4 = const 15_i32; -+ goto -> bb5; } } diff --git a/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-unwind.diff index d17e7d974443..083a6e7487a0 100644 --- a/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.duplicate_chain.JumpThreading.panic-unwind.diff @@ -13,14 +13,12 @@ bb1: { _2 = const 5_u8; -- goto -> bb3; -+ goto -> bb7; + goto -> bb3; } bb2: { _2 = const 5_u8; -- goto -> bb3; -+ goto -> bb7; + goto -> bb3; } bb3: { @@ -30,7 +28,8 @@ bb4: { _4 = const 15_i32; - switchInt(copy _2) -> [5: bb5, otherwise: bb6]; +- switchInt(copy _2) -> [5: bb5, otherwise: bb6]; ++ goto -> bb5; } bb5: { @@ -41,16 +40,6 @@ bb6: { _0 = const 9_u8; return; -+ } -+ -+ bb7: { -+ _3 = const 13_i32; -+ goto -> bb8; -+ } -+ -+ bb8: { -+ _4 = const 15_i32; -+ goto -> bb5; } } diff --git a/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-abort.diff index 271b7f00078c..09c0ad6d4856 100644 --- a/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-abort.diff @@ -7,18 +7,19 @@ let mut _3: u8; bb0: { -- switchInt(copy _1) -> [3: bb1, otherwise: bb2]; -+ switchInt(copy _1) -> [3: bb9, otherwise: bb10]; + switchInt(copy _1) -> [3: bb1, otherwise: bb2]; } bb1: { _2 = copy _1; - switchInt(copy _2) -> [3: bb3, otherwise: bb4]; +- switchInt(copy _2) -> [3: bb3, otherwise: bb4]; ++ goto -> bb3; } bb2: { _3 = copy _1; - switchInt(copy _3) -> [3: bb5, otherwise: bb6]; +- switchInt(copy _3) -> [3: bb5, otherwise: bb6]; ++ goto -> bb6; } bb3: { @@ -48,16 +49,6 @@ bb8: { _0 = const 11_u8; return; -+ } -+ -+ bb9: { -+ _2 = copy _1; -+ goto -> bb3; -+ } -+ -+ bb10: { -+ _3 = copy _1; -+ goto -> bb6; } } diff --git a/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-unwind.diff index 271b7f00078c..09c0ad6d4856 100644 --- a/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.multiple_match.JumpThreading.panic-unwind.diff @@ -7,18 +7,19 @@ let mut _3: u8; bb0: { -- switchInt(copy _1) -> [3: bb1, otherwise: bb2]; -+ switchInt(copy _1) -> [3: bb9, otherwise: bb10]; + switchInt(copy _1) -> [3: bb1, otherwise: bb2]; } bb1: { _2 = copy _1; - switchInt(copy _2) -> [3: bb3, otherwise: bb4]; +- switchInt(copy _2) -> [3: bb3, otherwise: bb4]; ++ goto -> bb3; } bb2: { _3 = copy _1; - switchInt(copy _3) -> [3: bb5, otherwise: bb6]; +- switchInt(copy _3) -> [3: bb5, otherwise: bb6]; ++ goto -> bb6; } bb3: { @@ -48,16 +49,6 @@ bb8: { _0 = const 11_u8; return; -+ } -+ -+ bb9: { -+ _2 = copy _1; -+ goto -> bb3; -+ } -+ -+ bb10: { -+ _3 = copy _1; -+ goto -> bb6; } } diff --git a/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-abort.diff index 4f80acd07338..c8edd704ff9b 100644 --- a/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-abort.diff @@ -8,13 +8,13 @@ bb0: { _3 = const false; -- switchInt(copy _1) -> [1: bb1, otherwise: bb2]; -+ switchInt(copy _1) -> [1: bb8, otherwise: bb2]; + switchInt(copy _1) -> [1: bb1, otherwise: bb2]; } bb1: { _2 = const false; - goto -> bb3; +- goto -> bb3; ++ goto -> bb9; } bb2: { @@ -47,19 +47,14 @@ + } + + bb8: { -+ _2 = const false; -+ goto -> bb10; -+ } -+ -+ bb9: { + switchInt(copy _2) -> [0: bb4, otherwise: bb5]; + } + -+ bb10: { -+ goto -> bb11; ++ bb9: { ++ goto -> bb10; + } + -+ bb11: { ++ bb10: { + goto -> bb6; } } diff --git a/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-unwind.diff index 4f80acd07338..c8edd704ff9b 100644 --- a/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.renumbered_bb.JumpThreading.panic-unwind.diff @@ -8,13 +8,13 @@ bb0: { _3 = const false; -- switchInt(copy _1) -> [1: bb1, otherwise: bb2]; -+ switchInt(copy _1) -> [1: bb8, otherwise: bb2]; + switchInt(copy _1) -> [1: bb1, otherwise: bb2]; } bb1: { _2 = const false; - goto -> bb3; +- goto -> bb3; ++ goto -> bb9; } bb2: { @@ -47,19 +47,14 @@ + } + + bb8: { -+ _2 = const false; -+ goto -> bb10; -+ } -+ -+ bb9: { + switchInt(copy _2) -> [0: bb4, otherwise: bb5]; + } + -+ bb10: { -+ goto -> bb11; ++ bb9: { ++ goto -> bb10; + } + -+ bb11: { ++ bb10: { + goto -> bb6; } } diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index e841643e7ce5..39a2f16c5ad6 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -191,18 +191,22 @@ fn multiple_match(x: u8) -> u8 { mir! { { // CHECK: bb0: { - // CHECK: switchInt(copy [[x:_.*]]) -> [3: bb9, otherwise: bb10]; + // CHECK: switchInt(copy [[x:_.*]]) -> [3: bb1, otherwise: bb2]; match x { 3 => bb1, _ => bb2 } } bb1 = { // We know `x == 3`, so we can take `bb3`. // CHECK: bb1: { + // CHECK: {{_.*}} = copy [[x]]; + // CHECK: goto -> bb3; let y = x; match y { 3 => bb3, _ => bb4 } } bb2 = { // We know `x != 3`, so we can take `bb6`. // CHECK: bb2: { + // CHECK: [[z:_.*]] = copy [[x]]; + // CHECK: goto -> bb6; let z = x; match z { 3 => bb5, _ => bb6 } } @@ -230,7 +234,7 @@ fn multiple_match(x: u8) -> u8 { bb6 = { // We know `z != 3`, so we CANNOT take `bb7`. // CHECK: bb6: { - // CHECK: switchInt(copy [[z:_.*]]) -> [1: bb7, otherwise: bb8]; + // CHECK: switchInt(copy [[z]]) -> [1: bb7, otherwise: bb8]; match z { 1 => bb7, _ => bb8 } } bb7 = { @@ -247,14 +251,6 @@ fn multiple_match(x: u8) -> u8 { RET = 11; Return() } - // We know `x == 3`, so we can take `bb3`. - // CHECK: bb9: { - // CHECK: {{_.*}} = copy [[x]]; - // CHECK: goto -> bb3; - // We know `x != 3`, so we can take `bb6`. - // CHECK: bb10: { - // CHECK: [[z]] = copy [[x]]; - // CHECK: goto -> bb6; } } @@ -273,14 +269,14 @@ fn duplicate_chain(x: bool) -> u8 { bb1 = { // CHECK: bb1: { // CHECK: [[a:_.*]] = const 5_u8; - // CHECK: goto -> bb7; + // CHECK: goto -> bb3; a = 5; Goto(bb3) } bb2 = { // CHECK: bb2: { // CHECK: [[a]] = const 5_u8; - // CHECK: goto -> bb7; + // CHECK: goto -> bb3; a = 5; Goto(bb3) } @@ -294,7 +290,7 @@ fn duplicate_chain(x: bool) -> u8 { bb4 = { // CHECK: bb4: { // CHECK: {{_.*}} = const 15_i32; - // CHECK: switchInt(copy _2) -> [5: bb5, otherwise: bb6]; + // CHECK: goto -> bb5; let c = 15; match a { 5 => bb5, _ => bb6 } } @@ -312,12 +308,6 @@ fn duplicate_chain(x: bool) -> u8 { RET = 9; Return() } - // CHECK: bb7: { - // CHECK-NEXT: {{_.*}} = const 13_i32; - // CHECK-NEXT: goto -> bb8; - // CHECK: bb8: { - // CHECK-NEXT: {{_.*}} = const 15_i32; - // CHECK-NEXT: goto -> bb5; } } @@ -383,13 +373,13 @@ fn renumbered_bb(x: bool) -> u8 { let b: bool; { // CHECK: bb0: { - // CHECK: switchInt({{.*}}) -> [1: bb8, otherwise: bb2]; + // CHECK: switchInt({{.*}}) -> [1: bb1, otherwise: bb2]; b = false; match x { true => bb1, _ => bb2 } } bb1 = { // CHECK: bb1: { - // CHECK: goto -> bb3; + // CHECK: goto -> bb9; a = false; Goto(bb3) } @@ -428,17 +418,14 @@ fn renumbered_bb(x: bool) -> u8 { RET = 11; Return() } - // Duplicate of bb1. - // CHECK: bb8: { - // CHECK: goto -> bb10; // Duplicate of bb3. - // CHECK: bb9: { + // CHECK: bb8: { // CHECK: switchInt(copy _2) -> [0: bb4, otherwise: bb5]; - // Duplicate of bb9. - // CHECK: bb10: { - // CHECK: goto -> bb11; + // Duplicate of bb8. + // CHECK: bb9: { + // CHECK: goto -> bb10; // Duplicate of bb4. - // CHECK: bb11: { + // CHECK: bb10: { // CHECK: goto -> bb6; } } @@ -457,12 +444,12 @@ fn disappearing_bb(x: u8) -> u8 { // CHECK: bb0: { a = true; b = true; - // CHECK: switchInt({{.*}}) -> [0: bb10, 1: bb10, 2: bb9, otherwise: bb2]; + // CHECK: switchInt({{.*}}) -> [0: bb3, 1: bb3, 2: bb1, otherwise: bb2]; match x { 0 => bb3, 1 => bb3, 2 => bb1, _ => bb2 } } bb1 = { // CHECK: bb1: { - // CHECK: goto -> bb4; + // CHECK: goto -> bb10; b = false; Goto(bb4) } @@ -473,7 +460,7 @@ fn disappearing_bb(x: u8) -> u8 { } bb3 = { // CHECK: bb3: { - // CHECK: goto -> bb4; + // CHECK: goto -> bb13; a = false; Goto(bb4) } @@ -493,22 +480,18 @@ fn disappearing_bb(x: u8) -> u8 { Goto(bb6) } // CHECK: bb9: { - // CHECK: goto -> bb12; + // CHECK: switchInt(copy _3) -> [0: bb5, otherwise: bb7]; // CHECK: bb10: { - // CHECK: goto -> bb15; + // CHECK: goto -> bb11; // CHECK: bb11: { - // CHECK: switchInt(copy _3) -> [0: bb5, otherwise: bb7]; - // CHECK: bb12: { - // CHECK: goto -> bb13; - // CHECK: bb13: { // CHECK: goto -> bb8; - // CHECK: bb14: { + // CHECK: bb12: { // CHECK: switchInt(copy _3) -> [0: bb5, otherwise: bb7]; + // CHECK: bb13: { + // CHECK: goto -> bb14; + // CHECK: bb14: { + // CHECK: goto -> bb15; // CHECK: bb15: { - // CHECK: goto -> bb16; - // CHECK: bb16: { - // CHECK: goto -> bb17; - // CHECK: bb17: { // CHECK: goto -> bb6; } } From 223620f3c6e3e276bde157c13ae20da93f1199a1 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sat, 20 Sep 2025 13:40:38 +0000 Subject: [PATCH 056/585] Filter costly chains after simplification. --- .../rustc_mir_transform/src/jump_threading.rs | 111 +++++++++++++----- ..._conditions.JumpThreading.panic-abort.diff | 86 ++------------ ...conditions.JumpThreading.panic-unwind.diff | 76 ++---------- 3 files changed, 96 insertions(+), 177 deletions(-) diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 1b6a0203519c..c021e7d4c3ae 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -51,8 +51,6 @@ //! //! [libfirm]: -use std::cell::OnceCell; - use itertools::Itertools as _; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable}; @@ -100,7 +98,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { map: Map::new(tcx, body, Some(MAX_PLACES)), maybe_loop_headers: loops::maybe_loop_headers(body), entry_states: IndexVec::from_elem(ConditionSet::default(), &body.basic_blocks), - costs: IndexVec::from_elem(OnceCell::new(), &body.basic_blocks), }; for (bb, bbdata) in traversal::postorder(body) { @@ -136,6 +133,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let mut entry_states = finder.entry_states; simplify_conditions(body, &mut entry_states); + remove_costly_conditions(tcx, typing_env, body, &mut entry_states); if let Some(opportunities) = OpportunitySet::new(body, entry_states) { opportunities.apply(); @@ -159,8 +157,6 @@ struct TOFinder<'a, 'tcx> { // Invariant: for each `bb`, each condition in `entry_states[bb]` has a `chain` that // starts with `bb`. entry_states: IndexVec, - /// Pre-computed cost of duplicating each block. - costs: IndexVec>, } rustc_index::newtype_index! { @@ -222,7 +218,6 @@ struct ConditionSet { active: Vec<(ConditionIndex, Condition)>, fulfilled: Vec, targets: IndexVec>, - costs: IndexVec, } impl ConditionSet { @@ -233,7 +228,6 @@ fn is_empty(&self) -> bool { #[tracing::instrument(level = "trace", skip(self))] fn push_condition(&mut self, c: Condition, target: BasicBlock) { let index = self.targets.push(vec![EdgeEffect::Goto { target }]); - self.costs.push(0); self.active.push((index, c)); } @@ -293,21 +287,18 @@ fn populate_from_outgoing_edges(&mut self, bb: BasicBlock) -> ConditionSet { active: Vec::with_capacity(state_len), targets: IndexVec::with_capacity(state_len), fulfilled: Vec::new(), - costs: IndexVec::with_capacity(state_len), }; // Use an index-set to deduplicate conditions coming from different successor blocks. let mut known_conditions = FxIndexSet::with_capacity_and_hasher(state_len, Default::default()); - let mut insert = |condition, succ_block, succ_condition, cost| { + let mut insert = |condition, succ_block, succ_condition| { let (index, new) = known_conditions.insert_full(condition); let index = ConditionIndex::from_usize(index); if new { state.active.push((index, condition)); let _index = state.targets.push(Vec::new()); debug_assert_eq!(_index, index); - let _index = state.costs.push(u8::MAX); - debug_assert_eq!(_index, index); } let target = EdgeEffect::Chain { succ_block, succ_condition }; debug_assert!( @@ -316,7 +307,6 @@ fn populate_from_outgoing_edges(&mut self, bb: BasicBlock) -> ConditionSet { &state.targets[index], ); state.targets[index].push(target); - state.costs[index] = std::cmp::min(state.costs[index], cost); }; // A given block may have several times the same successor. @@ -331,35 +321,19 @@ fn populate_from_outgoing_edges(&mut self, bb: BasicBlock) -> ConditionSet { continue; } - let succ_cost = self.cost(succ); for &(succ_index, cond) in self.entry_states[succ].active.iter() { - let cost = self.entry_states[succ].costs[succ_index]; - if let Ok(cost) = ((cost as usize) + succ_cost).try_into() - && cost < MAX_COST - { - insert(cond, succ, succ_index, cost); - } + insert(cond, succ, succ_index); } } let num_conditions = known_conditions.len(); debug_assert_eq!(num_conditions, state.active.len()); debug_assert_eq!(num_conditions, state.targets.len()); - debug_assert_eq!(num_conditions, state.costs.len()); state.fulfilled.reserve(num_conditions); state } - fn cost(&self, bb: BasicBlock) -> usize { - *self.costs[bb].get_or_init(|| { - let bbdata = &self.body[bb]; - let mut cost = CostChecker::new(self.tcx, self.typing_env, None, self.body); - cost.visit_basic_block_data(bb, bbdata); - cost.cost() - }) - } - /// Remove all conditions in the state that alias given place. fn flood_state( &self, @@ -751,8 +725,6 @@ fn process_switch_int( // Fulfilling `index` may thread conditions that we do not want, // so create a brand new index to immediately mark fulfilled. let index = state.targets.push(new_edges); - let _index = state.costs.push(0); - debug_assert_eq!(_index, index); state.fulfilled.push(index); } } @@ -865,6 +837,82 @@ fn simplify_conditions(body: &Body<'_>, entry_states: &mut IndexVec( + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + body: &Body<'tcx>, + entry_states: &mut IndexVec, +) { + let basic_blocks = &body.basic_blocks; + + let mut costs = IndexVec::from_elem(None, basic_blocks); + let mut cost = |bb: BasicBlock| -> u8 { + let c = *costs[bb].get_or_insert_with(|| { + let bbdata = &basic_blocks[bb]; + let mut cost = CostChecker::new(tcx, typing_env, None, body); + cost.visit_basic_block_data(bb, bbdata); + cost.cost().try_into().unwrap_or(MAX_COST) + }); + trace!("cost[{bb:?}] = {c}"); + c + }; + + // Initialize costs with `MAX_COST`: if we have a cycle, the cyclic `bb` has infinite costs. + let mut condition_cost = IndexVec::from_fn_n( + |bb: BasicBlock| IndexVec::from_elem_n(MAX_COST, entry_states[bb].targets.len()), + entry_states.len(), + ); + + let reverse_postorder = basic_blocks.reverse_postorder(); + + for &bb in reverse_postorder.iter().rev() { + let state = &entry_states[bb]; + trace!(?bb, ?state); + + let mut current_costs = IndexVec::from_elem(0u8, &state.targets); + + for (condition, targets) in state.targets.iter_enumerated() { + for &target in targets { + match target { + // A `Goto` has cost 0. + EdgeEffect::Goto { .. } => {} + // Chaining into an already-fulfilled condition is nop. + EdgeEffect::Chain { succ_block, succ_condition } + if entry_states[succ_block].fulfilled.contains(&succ_condition) => {} + // When chaining, use `cost[succ_block][succ_condition] + cost(succ_block)`. + EdgeEffect::Chain { succ_block, succ_condition } => { + // Cost associated with duplicating `succ_block`. + let duplication_cost = cost(succ_block); + // Cost associated with the rest of the chain. + let target_cost = + *condition_cost[succ_block].get(succ_condition).unwrap_or(&MAX_COST); + let cost = current_costs[condition] + .saturating_add(duplication_cost) + .saturating_add(target_cost); + trace!(?condition, ?succ_block, ?duplication_cost, ?target_cost); + current_costs[condition] = cost; + } + } + } + } + + trace!("condition_cost[{bb:?}] = {:?}", current_costs); + condition_cost[bb] = current_costs; + } + + trace!(?condition_cost); + + for &bb in reverse_postorder { + for (index, targets) in entry_states[bb].targets.iter_enumerated_mut() { + if condition_cost[bb][index] >= MAX_COST { + trace!(?bb, ?index, ?targets, c = ?condition_cost[bb][index], "remove"); + targets.clear() + } + } + } +} + struct OpportunitySet<'a, 'tcx> { basic_blocks: &'a mut IndexVec>, entry_states: IndexVec, @@ -887,7 +935,6 @@ fn new( // Free some memory, because we will need to clone condition sets. for state in entry_states.iter_mut() { state.active = Default::default(); - state.costs = Default::default(); } let duplicates = Default::default(); let basic_blocks = body.basic_blocks.as_mut(); diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff index bbe9ba806dc7..f09a187bfaf8 100644 --- a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff @@ -71,7 +71,7 @@ bb3: { _1 = chained_conditions::BacktraceStyle::Off; - goto -> bb18; -+ goto -> bb35; ++ goto -> bb23; } bb4: { @@ -131,7 +131,7 @@ StorageDead(_5); StorageDead(_6); - goto -> bb18; -+ goto -> bb22; ++ goto -> bb21; } bb8: { @@ -154,14 +154,14 @@ StorageDead(_13); _1 = chained_conditions::BacktraceStyle::Short; - goto -> bb18; -+ goto -> bb31; ++ goto -> bb23; } bb10: { StorageDead(_12); StorageDead(_13); - goto -> bb18; -+ goto -> bb27; ++ goto -> bb21; } bb11: { @@ -219,88 +219,20 @@ + + bb21: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb16, otherwise: bb15]; ++ switchInt(move _24) -> [1: bb22, otherwise: bb15]; + } + + bb22: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb25, otherwise: bb23]; ++ goto -> bb15; + } + + bb23: { -+ _22 = const false; -+ _23 = const false; -+ StorageDead(_2); -+ _19 = discriminant(_1); -+ goto -> bb11; ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb24, otherwise: bb15]; + } + + bb24: { -+ switchInt(copy _23) -> [0: bb15, otherwise: bb17]; -+ } -+ -+ bb25: { -+ goto -> bb23; -+ } -+ -+ bb26: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb16, otherwise: bb15]; -+ } -+ -+ bb27: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb30, otherwise: bb28]; -+ } -+ -+ bb28: { -+ _22 = const false; -+ _23 = const false; -+ StorageDead(_2); -+ _19 = discriminant(_1); -+ goto -> bb13; -+ } -+ -+ bb29: { -+ switchInt(copy _23) -> [0: bb15, otherwise: bb17]; -+ } -+ -+ bb30: { -+ goto -> bb28; -+ } -+ -+ bb31: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb33, otherwise: bb32]; -+ } -+ -+ bb32: { -+ _22 = const false; -+ _23 = const false; -+ StorageDead(_2); -+ _19 = discriminant(_1); -+ goto -> bb12; -+ } -+ -+ bb33: { -+ switchInt(copy _23) -> [0: bb32, otherwise: bb34]; -+ } -+ -+ bb34: { -+ drop(((_2 as Some).0: std::string::String)) -> [return: bb32, unwind unreachable]; -+ } -+ -+ bb35: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb36, otherwise: bb28]; -+ } -+ -+ bb36: { -+ goto -> bb37; -+ } -+ -+ bb37: { -+ drop(((_2 as Some).0: std::string::String)) -> [return: bb28, unwind unreachable]; ++ goto -> bb17; } } diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff index a40e4446aef1..afd40c1862c3 100644 --- a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff @@ -71,7 +71,7 @@ bb3: { _1 = chained_conditions::BacktraceStyle::Off; - goto -> bb19; -+ goto -> bb38; ++ goto -> bb27; } bb4: { @@ -131,7 +131,7 @@ StorageDead(_5); StorageDead(_6); - goto -> bb19; -+ goto -> bb26; ++ goto -> bb25; } bb8: { @@ -154,14 +154,14 @@ StorageDead(_13); _1 = chained_conditions::BacktraceStyle::Short; - goto -> bb19; -+ goto -> bb35; ++ goto -> bb27; } bb10: { StorageDead(_12); StorageDead(_13); - goto -> bb19; -+ goto -> bb31; ++ goto -> bb25; } bb11: { @@ -236,79 +236,19 @@ + + bb25: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb17, otherwise: bb16]; ++ switchInt(move _24) -> [1: bb26, otherwise: bb16]; + } + + bb26: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb29, otherwise: bb27]; ++ goto -> bb16; + } + + bb27: { -+ _22 = const false; -+ _23 = const false; -+ StorageDead(_2); -+ _19 = discriminant(_1); -+ goto -> bb11; ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb28, otherwise: bb16]; + } + + bb28: { -+ switchInt(copy _23) -> [0: bb16, otherwise: bb18]; -+ } -+ -+ bb29: { -+ goto -> bb27; -+ } -+ -+ bb30: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb17, otherwise: bb16]; -+ } -+ -+ bb31: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb34, otherwise: bb32]; -+ } -+ -+ bb32: { -+ _22 = const false; -+ _23 = const false; -+ StorageDead(_2); -+ _19 = discriminant(_1); -+ goto -> bb13; -+ } -+ -+ bb33: { -+ switchInt(copy _23) -> [0: bb16, otherwise: bb18]; -+ } -+ -+ bb34: { -+ goto -> bb32; -+ } -+ -+ bb35: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb37, otherwise: bb36]; -+ } -+ -+ bb36: { -+ _22 = const false; -+ _23 = const false; -+ StorageDead(_2); -+ _19 = discriminant(_1); -+ goto -> bb12; -+ } -+ -+ bb37: { -+ switchInt(copy _23) -> [0: bb36, otherwise: bb18]; -+ } -+ -+ bb38: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb39, otherwise: bb32]; -+ } -+ -+ bb39: { + goto -> bb18; } } From 485b53c85b7b1cf56d54697e371800670d912d2b Mon Sep 17 00:00:00 2001 From: dvermd <315743+dvermd@users.noreply.github.com> Date: Tue, 5 Aug 2025 08:30:49 +0200 Subject: [PATCH 057/585] fix 128bit ctlz intrinsic UB --- src/intrinsic/mod.rs | 116 ++++++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 46 deletions(-) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index db9f32bad5a7..b5e15b3a3599 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -405,7 +405,9 @@ fn codegen_intrinsic_call( | sym::saturating_sub => { match int_type_width_signed(args[0].layout.ty, self) { Some((width, signed)) => match name { - sym::ctlz | sym::cttz => { + sym::ctlz => self.count_leading_zeroes(width, args[0].immediate()), + + sym::cttz => { let func = self.current_func(); let then_block = func.new_block("then"); let else_block = func.new_block("else"); @@ -426,11 +428,7 @@ fn codegen_intrinsic_call( // in the state need to be updated. self.switch_to_block(else_block); - let zeros = match name { - sym::ctlz => self.count_leading_zeroes(width, arg), - sym::cttz => self.count_trailing_zeroes(width, arg), - _ => unreachable!(), - }; + let zeros = self.count_trailing_zeroes(width, arg); self.llbb().add_assignment(None, result, zeros); self.llbb().end_with_jump(None, after_block); @@ -440,7 +438,9 @@ fn codegen_intrinsic_call( result.to_rvalue() } - sym::ctlz_nonzero => self.count_leading_zeroes(width, args[0].immediate()), + sym::ctlz_nonzero => { + self.count_leading_zeroes_nonzero(width, args[0].immediate()) + } sym::cttz_nonzero => self.count_trailing_zeroes(width, args[0].immediate()), sym::ctpop => self.pop_count(args[0].immediate()), sym::bswap => { @@ -877,16 +877,46 @@ fn bit_reverse(&mut self, width: u64, value: RValue<'gcc>) -> RValue<'gcc> { } fn count_leading_zeroes(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + // if arg is 0, early return 0, else call count_leading_zeroes_nonzero to compute leading zeros + let func = self.current_func(); + let then_block = func.new_block("then"); + let else_block = func.new_block("else"); + let after_block = func.new_block("after"); + + let result = func.new_local(None, self.u32_type, "zeros"); + let zero = self.cx.gcc_zero(arg.get_type()); + let cond = self.gcc_icmp(IntPredicate::IntEQ, arg, zero); + self.llbb().end_with_conditional(None, cond, then_block, else_block); + + let zero_result = self.cx.gcc_uint(self.u32_type, width); + then_block.add_assignment(None, result, zero_result); + then_block.end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place count_leading_zeroes_nonzero() does not expect, + // the current block in the state need to be updated. + self.switch_to_block(else_block); + + let zeros = self.count_leading_zeroes_nonzero(width, arg); + self.llbb().add_assignment(None, result, zeros); + self.llbb().end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place rustc does not + // expect, the current block in the state need to be updated. + self.switch_to_block(after_block); + + result.to_rvalue() + } + + fn count_leading_zeroes_nonzero(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { // TODO(antoyo): use width? - let arg_type = arg.get_type(); let result_type = self.u32_type; + let mut arg_type = arg.get_type(); let arg = if arg_type.is_signed(self.cx) { - let new_type = arg_type.to_unsigned(self.cx); - self.gcc_int_cast(arg, new_type) + arg_type = arg_type.to_unsigned(self.cx); + self.gcc_int_cast(arg, arg_type) } else { arg }; - let arg_type = arg.get_type(); let count_leading_zeroes = // TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here // instead of using is_uint(). @@ -900,51 +930,45 @@ fn count_leading_zeroes(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc "__builtin_clzll" } else if width == 128 { - // Algorithm from: https://stackoverflow.com/a/28433850/389119 - let array_type = self.context.new_array_type(None, arg_type, 3); - let result = self.current_func() - .new_local(None, array_type, "count_loading_zeroes_results"); + // arg is guaranteed to not be 0, so either its 64 high or 64 low bits are not 0 + // __buildin_clzll is UB when called with 0, so call it on the 64 high bits if they are not 0, + // else call it on the 64 low bits and add 64. In the else case, 64 low bits can't be 0 + // because arg is not 0. + let result = self.current_func() + .new_local(None, result_type, "count_leading_zeroes_results"); + + let ctlz_then_block = self.current_func().new_block("ctlz_then"); + let ctlz_else_block = self.current_func().new_block("ctlz_else"); + let ctlz_after_block = self.current_func().new_block("ctlz_after") + ; let sixty_four = self.const_uint(arg_type, 64); let shift = self.lshr(arg, sixty_four); let high = self.gcc_int_cast(shift, self.u64_type); - let low = self.gcc_int_cast(arg, self.u64_type); - - let zero = self.context.new_rvalue_zero(self.usize_type); - let one = self.context.new_rvalue_one(self.usize_type); - let two = self.context.new_rvalue_from_long(self.usize_type, 2); let clzll = self.context.get_builtin_function("__builtin_clzll"); - let first_elem = self.context.new_array_access(None, result, zero); - let first_value = self.gcc_int_cast(self.context.new_call(None, clzll, &[high]), arg_type); - self.llbb() - .add_assignment(self.location, first_elem, first_value); + let zero_hi = self.const_uint(high.get_type(), 0); + let cond = self.gcc_icmp(IntPredicate::IntNE, high, zero_hi); + self.llbb().end_with_conditional(self.location, cond, ctlz_then_block, ctlz_else_block); + self.switch_to_block(ctlz_then_block); - let second_elem = self.context.new_array_access(self.location, result, one); - let cast = self.gcc_int_cast(self.context.new_call(self.location, clzll, &[low]), arg_type); - let second_value = self.add(cast, sixty_four); - self.llbb() - .add_assignment(self.location, second_elem, second_value); + let result_128 = + self.gcc_int_cast(self.context.new_call(None, clzll, &[high]), result_type); - let third_elem = self.context.new_array_access(self.location, result, two); - let third_value = self.const_uint(arg_type, 128); - self.llbb() - .add_assignment(self.location, third_elem, third_value); + ctlz_then_block.add_assignment(self.location, result, result_128); + ctlz_then_block.end_with_jump(self.location, ctlz_after_block); - let not_high = self.context.new_unary_op(self.location, UnaryOp::LogicalNegate, self.u64_type, high); - let not_low = self.context.new_unary_op(self.location, UnaryOp::LogicalNegate, self.u64_type, low); - let not_low_and_not_high = not_low & not_high; - let index = not_high + not_low_and_not_high; - // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in - // gcc. - // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the - // compilation stage. - let index = self.context.new_cast(self.location, index, self.i32_type); - - let res = self.context.new_array_access(self.location, result, index); - - return self.gcc_int_cast(res.to_rvalue(), result_type); + self.switch_to_block(ctlz_else_block); + let low = self.gcc_int_cast(arg, self.u64_type); + let low_leading_zeroes = + self.gcc_int_cast(self.context.new_call(None, clzll, &[low]), result_type); + let sixty_four_result_type = self.const_uint(result_type, 64); + let result_128 = self.add(low_leading_zeroes, sixty_four_result_type); + ctlz_else_block.add_assignment(self.location, result, result_128); + ctlz_else_block.end_with_jump(self.location, ctlz_after_block); + self.switch_to_block(ctlz_after_block); + return result.to_rvalue(); } else { let count_leading_zeroes = self.context.get_builtin_function("__builtin_clzll"); From e4fd312a1674559b440ef3fb840dd04ba4f28e65 Mon Sep 17 00:00:00 2001 From: dvermd <315743+dvermd@users.noreply.github.com> Date: Thu, 7 Aug 2025 10:08:23 +0200 Subject: [PATCH 058/585] fix 128bit cttz intrinsic UB --- src/intrinsic/mod.rs | 142 +++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 73 deletions(-) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index b5e15b3a3599..b1ce33da3a7b 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -407,41 +407,13 @@ fn codegen_intrinsic_call( Some((width, signed)) => match name { sym::ctlz => self.count_leading_zeroes(width, args[0].immediate()), - sym::cttz => { - let func = self.current_func(); - let then_block = func.new_block("then"); - let else_block = func.new_block("else"); - let after_block = func.new_block("after"); - - let arg = args[0].immediate(); - let result = func.new_local(None, self.u32_type, "zeros"); - let zero = self.cx.gcc_zero(arg.get_type()); - let cond = self.gcc_icmp(IntPredicate::IntEQ, arg, zero); - self.llbb().end_with_conditional(None, cond, then_block, else_block); - - let zero_result = self.cx.gcc_uint(self.u32_type, width); - then_block.add_assignment(None, result, zero_result); - then_block.end_with_jump(None, after_block); - - // NOTE: since jumps were added in a place - // count_leading_zeroes() does not expect, the current block - // in the state need to be updated. - self.switch_to_block(else_block); - - let zeros = self.count_trailing_zeroes(width, arg); - self.llbb().add_assignment(None, result, zeros); - self.llbb().end_with_jump(None, after_block); - - // NOTE: since jumps were added in a place rustc does not - // expect, the current block in the state need to be updated. - self.switch_to_block(after_block); - - result.to_rvalue() - } sym::ctlz_nonzero => { self.count_leading_zeroes_nonzero(width, args[0].immediate()) } - sym::cttz_nonzero => self.count_trailing_zeroes(width, args[0].immediate()), + sym::cttz => self.count_trailing_zeroes(width, args[0].immediate()), + sym::cttz_nonzero => { + self.count_trailing_zeroes_nonzero(width, args[0].immediate()) + } sym::ctpop => self.pop_count(args[0].immediate()), sym::bswap => { if width == 8 { @@ -983,16 +955,46 @@ fn count_leading_zeroes_nonzero(&mut self, width: u64, arg: RValue<'gcc>) -> RVa self.context.new_cast(self.location, res, result_type) } - fn count_trailing_zeroes(&mut self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { - let arg_type = arg.get_type(); + fn count_trailing_zeroes(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + // if arg is 0, early return width, else call count_trailing_zeroes_nonzero to compute trailing zeros + let func = self.current_func(); + let then_block = func.new_block("then"); + let else_block = func.new_block("else"); + let after_block = func.new_block("after"); + + let result = func.new_local(None, self.u32_type, "zeros"); + let zero = self.cx.gcc_zero(arg.get_type()); + let cond = self.gcc_icmp(IntPredicate::IntEQ, arg, zero); + self.llbb().end_with_conditional(None, cond, then_block, else_block); + + let zero_result = self.cx.gcc_uint(self.u32_type, width); + then_block.add_assignment(None, result, zero_result); + then_block.end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place count_trailing_zeroes_nonzero() does not expect, + // the current block in the state need to be updated. + self.switch_to_block(else_block); + + let zeros = self.count_trailing_zeroes_nonzero(width, arg); + self.llbb().add_assignment(None, result, zeros); + self.llbb().end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place rustc does not + // expect, the current block in the state need to be updated. + self.switch_to_block(after_block); + + result.to_rvalue() + } + + fn count_trailing_zeroes_nonzero(&mut self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { let result_type = self.u32_type; + let mut arg_type = arg.get_type(); let arg = if arg_type.is_signed(self.cx) { - let new_type = arg_type.to_unsigned(self.cx); - self.gcc_int_cast(arg, new_type) + arg_type = arg_type.to_unsigned(self.cx); + self.gcc_int_cast(arg, arg_type) } else { arg }; - let arg_type = arg.get_type(); let (count_trailing_zeroes, expected_type) = // TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here // instead of using is_uint(). @@ -1007,50 +1009,44 @@ fn count_trailing_zeroes(&mut self, _width: u64, arg: RValue<'gcc>) -> RValue<'g ("__builtin_ctzll", self.cx.ulonglong_type) } else if arg_type.is_u128(self.cx) { - // Adapted from the algorithm to count leading zeroes from: https://stackoverflow.com/a/28433850/389119 - let array_type = self.context.new_array_type(None, arg_type, 3); + // arg is guaranteed to no be 0, so either its 64 high or 64 low bits are not 0 + // __buildin_ctzll is UB when called with 0, so call it on the 64 low bits if they are not 0, + // else call it on the 64 high bits and add 64. In the else case, 64 high bits can't be 0 + // because arg is not 0. + let result = self.current_func() - .new_local(None, array_type, "count_loading_zeroes_results"); - - let sixty_four = self.gcc_int(arg_type, 64); - let shift = self.gcc_lshr(arg, sixty_four); - let high = self.gcc_int_cast(shift, self.u64_type); - let low = self.gcc_int_cast(arg, self.u64_type); - - let zero = self.context.new_rvalue_zero(self.usize_type); - let one = self.context.new_rvalue_one(self.usize_type); - let two = self.context.new_rvalue_from_long(self.usize_type, 2); + .new_local(None, result_type, "count_trailing_zeroes_results"); + let ctlz_then_block = self.current_func().new_block("cttz_then"); + let ctlz_else_block = self.current_func().new_block("cttz_else"); + let ctlz_after_block = self.current_func().new_block("cttz_after"); let ctzll = self.context.get_builtin_function("__builtin_ctzll"); - let first_elem = self.context.new_array_access(self.location, result, zero); - let first_value = self.gcc_int_cast(self.context.new_call(self.location, ctzll, &[low]), arg_type); - self.llbb() - .add_assignment(self.location, first_elem, first_value); + let low = self.gcc_int_cast(arg, self.u64_type); + let sixty_four = self.const_uint(arg_type, 64); + let shift = self.lshr(arg, sixty_four); + let high = self.gcc_int_cast(shift, self.u64_type); + let zero_low = self.const_uint(low.get_type(), 0); + let cond = self.gcc_icmp(IntPredicate::IntNE, low, zero_low); + self.llbb().end_with_conditional(self.location, cond, ctlz_then_block, ctlz_else_block); + self.switch_to_block(ctlz_then_block); - let second_elem = self.context.new_array_access(self.location, result, one); - let second_value = self.gcc_add(self.gcc_int_cast(self.context.new_call(self.location, ctzll, &[high]), arg_type), sixty_four); - self.llbb() - .add_assignment(self.location, second_elem, second_value); + let result_128 = + self.gcc_int_cast(self.context.new_call(None, ctzll, &[low]), result_type); - let third_elem = self.context.new_array_access(self.location, result, two); - let third_value = self.gcc_int(arg_type, 128); - self.llbb() - .add_assignment(self.location, third_elem, third_value); + ctlz_then_block.add_assignment(self.location, result, result_128); + ctlz_then_block.end_with_jump(self.location, ctlz_after_block); - let not_low = self.context.new_unary_op(self.location, UnaryOp::LogicalNegate, self.u64_type, low); - let not_high = self.context.new_unary_op(self.location, UnaryOp::LogicalNegate, self.u64_type, high); - let not_low_and_not_high = not_low & not_high; - let index = not_low + not_low_and_not_high; - // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in - // gcc. - // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the - // compilation stage. - let index = self.context.new_cast(self.location, index, self.i32_type); + self.switch_to_block(ctlz_else_block); + let high_trailing_zeroes = + self.gcc_int_cast(self.context.new_call(None, ctzll, &[high]), result_type); - let res = self.context.new_array_access(self.location, result, index); - - return self.gcc_int_cast(res.to_rvalue(), result_type); + let sixty_four_result_type = self.const_uint(result_type, 64); + let result_128 = self.add(high_trailing_zeroes, sixty_four_result_type); + ctlz_else_block.add_assignment(self.location, result, result_128); + ctlz_else_block.end_with_jump(self.location, ctlz_after_block); + self.switch_to_block(ctlz_after_block); + return result.to_rvalue(); } else { let count_trailing_zeroes = self.context.get_builtin_function("__builtin_ctzll"); From f4496bf9b653faff16f271c09105ed620792b920 Mon Sep 17 00:00:00 2001 From: Sergio Giro Date: Sun, 16 Nov 2025 17:49:10 +0000 Subject: [PATCH 059/585] Fix suggestions in while_let_on_iterator for non-sized traits --- .../src/loops/while_let_on_iterator.rs | 29 +++++++++++++---- tests/ui/while_let_on_iterator.fixed | 31 +++++++++++++++++++ tests/ui/while_let_on_iterator.rs | 31 +++++++++++++++++++ tests/ui/while_let_on_iterator.stderr | 16 ++++++++-- 4 files changed, 99 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 2545f81f1afa..c063e9263ba0 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -12,6 +12,7 @@ use rustc_hir::{Closure, Expr, ExprKind, HirId, LetStmt, Mutability, UnOp}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter::OnlyBodies; +use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; use rustc_span::Symbol; use rustc_span::symbol::sym; @@ -43,26 +44,26 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { }; // If the iterator is a field or the iterator is accessed after the loop is complete it needs to be - // borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used + // passed by reference. TODO: If the struct can be partially moved from and the struct isn't used // afterwards a mutable borrow of a field isn't necessary. - let by_ref = if cx.typeck_results().expr_ty(iter_expr).ref_mutability() == Some(Mutability::Mut) + let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability); + let iterator_by_ref = if cx.typeck_results().expr_ty(iter_expr).ref_mutability() == Some(Mutability::Mut) || !iter_expr_struct.can_move || !iter_expr_struct.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr_struct, expr) { - ".by_ref()" + make_iterator_snippet(cx, iter_expr, iterator) } else { - "" + iterator.to_string() }; - let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability); span_lint_and_sugg( cx, WHILE_LET_ON_ITERATOR, expr.span.with_hi(let_expr.span.hi()), "this loop could be written as a `for` loop", "try", - format!("{loop_label}for {loop_var} in {iterator}{by_ref}"), + format!("{loop_label}for {loop_var} in {iterator_by_ref}"), applicability, ); } @@ -355,3 +356,19 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) { .is_break() } } + +/// Constructs the transformed iterator expression for the suggestion. +/// Returns `iterator.by_ref()` unless the iterator type is a reference to an unsized type, +/// in which case it returns `&mut *iterator`. +fn make_iterator_snippet<'tcx>(cx: &LateContext<'tcx>, iter_expr: &Expr<'tcx>, iterator: impl Into) -> String { + let iterator = iterator.into(); + let ty = cx.typeck_results().expr_ty(iter_expr); + + if let ty::Ref(_, inner_ty, _) = ty.kind() + && !inner_ty.is_sized(cx.tcx, cx.typing_env()) + { + return format!("&mut *{iterator}"); + } + + format!("{iterator}.by_ref()") +} diff --git a/tests/ui/while_let_on_iterator.fixed b/tests/ui/while_let_on_iterator.fixed index f9ccefab5898..4e03e954108e 100644 --- a/tests/ui/while_let_on_iterator.fixed +++ b/tests/ui/while_let_on_iterator.fixed @@ -492,6 +492,37 @@ fn issue13123() { } } +fn issue16089() { + trait CertainTrait: Iterator { + fn iter_over_self(&mut self) { + let mut a = 0; + for r in &mut *self { + //~^ while_let_on_iterator + a = r; + } + self.use_after_iter() + } + + fn use_after_iter(&mut self) {} + } +} + +fn issue16089_sized_trait_not_reborrowed() { + trait CertainTrait: Iterator + Sized { + fn iter_over_self(&mut self) { + let mut a = 0; + // Check that the suggestion is just "self", since the trait is sized. + for r in self.by_ref() { + //~^ while_let_on_iterator + a = r; + } + self.use_after_iter() + } + + fn use_after_iter(&mut self) {} + } +} + fn main() { let mut it = 0..20; for _ in it { diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs index f957f2e5a523..cc65fda6d18f 100644 --- a/tests/ui/while_let_on_iterator.rs +++ b/tests/ui/while_let_on_iterator.rs @@ -492,6 +492,37 @@ fn issue13123() { } } +fn issue16089() { + trait CertainTrait: Iterator { + fn iter_over_self(&mut self) { + let mut a = 0; + while let Some(r) = self.next() { + //~^ while_let_on_iterator + a = r; + } + self.use_after_iter() + } + + fn use_after_iter(&mut self) {} + } +} + +fn issue16089_sized_trait_not_reborrowed() { + trait CertainTrait: Iterator + Sized { + fn iter_over_self(&mut self) { + let mut a = 0; + // Check that the suggestion is just "self", since the trait is sized. + while let Some(r) = self.next() { + //~^ while_let_on_iterator + a = r; + } + self.use_after_iter() + } + + fn use_after_iter(&mut self) {} + } +} + fn main() { let mut it = 0..20; while let Some(..) = it.next() { diff --git a/tests/ui/while_let_on_iterator.stderr b/tests/ui/while_let_on_iterator.stderr index 50f20227b90f..21ebc22f699d 100644 --- a/tests/ui/while_let_on_iterator.stderr +++ b/tests/ui/while_let_on_iterator.stderr @@ -164,10 +164,22 @@ LL | 'label: while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'label: for n in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:497:5 + --> tests/ui/while_let_on_iterator.rs:499:13 + | +LL | while let Some(r) = self.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for r in &mut *self` + +error: this loop could be written as a `for` loop + --> tests/ui/while_let_on_iterator.rs:515:13 + | +LL | while let Some(r) = self.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for r in self.by_ref()` + +error: this loop could be written as a `for` loop + --> tests/ui/while_let_on_iterator.rs:528:5 | LL | while let Some(..) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` -error: aborting due to 28 previous errors +error: aborting due to 30 previous errors From 726b7360cf771cabbdbe44feac96b59aafd1fa32 Mon Sep 17 00:00:00 2001 From: srosefield-riverside Date: Mon, 17 Nov 2025 09:31:02 -0500 Subject: [PATCH 060/585] Only allocate the minimal alignment requested for a type when possible. (#1604) * Only allocate the minimal alignment requested for a type when possible. * Code review: make an assertion a debug assert. Adjust an out-of-date comment. --- src/common.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/common.rs b/src/common.rs index 38676eaac3d5..758d89c92b75 100644 --- a/src/common.rs +++ b/src/common.rs @@ -377,26 +377,26 @@ pub(crate) fn create_stack_slot(&mut self, size: u32, align: u32) -> Pointer { size.is_multiple_of(align), "size must be a multiple of alignment (size={size}, align={align})" ); + debug_assert!(align.is_power_of_two(), "alignment must be a power of two (align={align})"); let abi_align = if self.tcx.sess.target.arch == Arch::S390x { 8 } else { 16 }; + // Cranelift can only guarantee alignment up to the ABI alignment provided by the target. + // If the requested alignment is less than the abi_align it can be used directly. if align <= abi_align { let stack_slot = self.bcx.create_sized_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, - // FIXME Don't force the size to a multiple of bytes once Cranelift gets - // a way to specify stack slot alignment. - size: size.div_ceil(abi_align) * abi_align, - align_shift: 4, + size, + // The maximum value of ilog2 is 31 which will always fit in a u8. + align_shift: align.ilog2().try_into().unwrap(), }); Pointer::stack_slot(stack_slot) } else { - // Alignment is too big to handle using the above hack. Dynamically realign a stack slot + // Alignment is larger than the ABI alignment guaranteed. Dynamically realign a stack slot // instead. This wastes some space for the realignment. let stack_slot = self.bcx.create_sized_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, - // FIXME Don't force the size to a multiple of bytes once Cranelift gets - // a way to specify stack slot alignment. - size: (size + align) / abi_align * abi_align, - align_shift: 4, + size: size + align, + align_shift: abi_align.ilog2().try_into().unwrap(), }); let base_ptr = self.bcx.ins().stack_addr(self.pointer_type, stack_slot, 0); let misalign_offset = self.bcx.ins().band_imm(base_ptr, i64::from(align - 1)); From 5a8cf3362c29cbc503d9ea1ec8c119578da38fc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=C3=A1n=20de=20B=C3=BArca?= Date: Fri, 7 Nov 2025 09:47:55 -0800 Subject: [PATCH 061/585] alloc: Document panics when allocations will exceed max --- library/alloc/src/string.rs | 21 +++++++++++++++++---- library/alloc/src/vec/mod.rs | 9 +++++++-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 4a2689e01ff1..f5ba71c28833 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -454,6 +454,10 @@ pub const fn new() -> String { /// /// [`new`]: String::new /// + /// # Panics + /// + /// Panics if the capacity exceeds `isize::MAX` _bytes_. + /// /// # Examples /// /// ``` @@ -1079,6 +1083,10 @@ pub const fn as_mut_str(&mut self) -> &mut str { /// Appends a given string slice onto the end of this `String`. /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// /// # Examples /// /// ``` @@ -1101,8 +1109,9 @@ pub fn push_str(&mut self, string: &str) { /// /// # Panics /// - /// Panics if the range has `start_bound > end_bound`, or, if the range is - /// bounded on either end and does not lie on a [`char`] boundary. + /// Panics if the range has `start_bound > end_bound`, if the range is + /// bounded on either end and does not lie on a [`char`] boundary, or if the + /// new capacity exceeds `isize::MAX` bytes. /// /// # Examples /// @@ -1158,7 +1167,7 @@ pub const fn capacity(&self) -> usize { /// /// # Panics /// - /// Panics if the new capacity overflows [`usize`]. + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. /// /// # Examples /// @@ -1208,7 +1217,7 @@ pub fn reserve(&mut self, additional: usize) { /// /// # Panics /// - /// Panics if the new capacity overflows [`usize`]. + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. /// /// # Examples /// @@ -1372,6 +1381,10 @@ pub fn shrink_to(&mut self, min_capacity: usize) { /// Appends the given [`char`] to the end of this `String`. /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// /// # Examples /// /// ``` diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 13d38d3c9609..0c485ed31912 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3338,6 +3338,10 @@ pub fn resize(&mut self, new_len: usize, value: T) { /// except that it also works with slice elements that are Clone but not Copy. /// If Rust gets specialization this function may be deprecated. /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// /// # Examples /// /// ``` @@ -3359,8 +3363,9 @@ pub fn extend_from_slice(&mut self, other: &[T]) { /// /// # Panics /// - /// Panics if starting index is greater than the end index - /// or if the index is greater than the length of the vector. + /// Panics if starting index is greater than the end index, if the index is + /// greater than the length of the vector, or if the new capacity exceeds + /// `isize::MAX` _bytes_. /// /// # Examples /// From 201734496e4d76a77ef6ba8ae28017c232096550 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 17 Nov 2025 19:00:14 +0000 Subject: [PATCH 062/585] Remove usage of function const promotion in the build system --- build_system/abi_cafe.rs | 2 +- build_system/build_backend.rs | 2 +- build_system/build_sysroot.rs | 2 +- build_system/tests.rs | 8 ++++---- build_system/utils.rs | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build_system/abi_cafe.rs b/build_system/abi_cafe.rs index 5a393a217c27..762b2be8f440 100644 --- a/build_system/abi_cafe.rs +++ b/build_system/abi_cafe.rs @@ -11,7 +11,7 @@ "abi-cafe", ); -static ABI_CAFE: CargoProject = CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe_target"); +static ABI_CAFE: CargoProject = CargoProject::new(ABI_CAFE_REPO.source_dir(), "abi_cafe_target"); pub(crate) fn run( sysroot_kind: SysrootKind, diff --git a/build_system/build_backend.rs b/build_system/build_backend.rs index b9fa0ff2d94c..ad6743a6d659 100644 --- a/build_system/build_backend.rs +++ b/build_system/build_backend.rs @@ -6,7 +6,7 @@ use crate::shared_utils::{rustflags_from_env, rustflags_to_cmd_env}; use crate::utils::{CargoProject, Compiler, LogGroup}; -static CG_CLIF: CargoProject = CargoProject::new(&RelPath::source("."), "cg_clif"); +static CG_CLIF: CargoProject = CargoProject::new(RelPath::source("."), "cg_clif"); pub(crate) fn build_backend( dirs: &Dirs, diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 70504ee8007d..804d50e25d0d 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -140,7 +140,7 @@ fn install_into_sysroot(&self, sysroot: &Path) { static STDLIB_SRC: RelPath = RelPath::build("stdlib"); static STANDARD_LIBRARY: CargoProject = - CargoProject::new(&RelPath::build("stdlib/library/sysroot"), "stdlib_target"); + CargoProject::new(RelPath::build("stdlib/library/sysroot"), "stdlib_target"); fn build_sysroot_for_triple( dirs: &Dirs, diff --git a/build_system/tests.rs b/build_system/tests.rs index dd8cf929bc2f..3b6a2e7a055c 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -129,7 +129,7 @@ const fn jit_bin(config: &'static str, source: &'static str, args: &'static str) "rand", ); -static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand_target"); +static RAND: CargoProject = CargoProject::new(RAND_REPO.source_dir(), "rand_target"); pub(crate) static REGEX_REPO: GitRepo = GitRepo::github( "rust-lang", @@ -139,15 +139,15 @@ const fn jit_bin(config: &'static str, source: &'static str, args: &'static str) "regex", ); -static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex_target"); +static REGEX: CargoProject = CargoProject::new(REGEX_REPO.source_dir(), "regex_target"); static PORTABLE_SIMD_SRC: RelPath = RelPath::build("portable-simd"); -static PORTABLE_SIMD: CargoProject = CargoProject::new(&PORTABLE_SIMD_SRC, "portable-simd_target"); +static PORTABLE_SIMD: CargoProject = CargoProject::new(PORTABLE_SIMD_SRC, "portable-simd_target"); static SYSROOT_TESTS_SRC: RelPath = RelPath::build("sysroot_tests"); -static SYSROOT_TESTS: CargoProject = CargoProject::new(&SYSROOT_TESTS_SRC, "sysroot_tests_target"); +static SYSROOT_TESTS: CargoProject = CargoProject::new(SYSROOT_TESTS_SRC, "sysroot_tests_target"); const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ TestCase::custom("test.rust-random/rand", &|runner| { diff --git a/build_system/utils.rs b/build_system/utils.rs index 3266aa0ce8b6..5c7cefa120a7 100644 --- a/build_system/utils.rs +++ b/build_system/utils.rs @@ -75,12 +75,12 @@ pub(crate) fn run_with_runner(&self, program: impl AsRef) -> Command { } pub(crate) struct CargoProject { - source: &'static RelPath, + source: RelPath, target: &'static str, } impl CargoProject { - pub(crate) const fn new(path: &'static RelPath, target: &'static str) -> CargoProject { + pub(crate) const fn new(path: RelPath, target: &'static str) -> CargoProject { CargoProject { source: path, target } } From 94ff1de61ea096eab6f7937c8850deb59201d3cd Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sat, 25 Oct 2025 04:15:43 +0000 Subject: [PATCH 063/585] Replace OffsetOf by an actual sum. --- src/base.rs | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/src/base.rs b/src/base.rs index 3bd2e4ea7343..e445f9457477 100644 --- a/src/base.rs +++ b/src/base.rs @@ -853,31 +853,14 @@ fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { fx.bcx.ins().nop(); } } - Rvalue::NullaryOp(ref null_op, ty) => { + Rvalue::NullaryOp(ref null_op) => { assert!(lval.layout().ty.is_sized(fx.tcx, fx.typing_env())); - let layout = fx.layout_of(fx.monomorphize(ty)); let val = match null_op { - NullOp::OffsetOf(fields) => fx - .tcx - .offset_of_subfield( - ty::TypingEnv::fully_monomorphized(), - layout, - fields.iter(), - ) - .bytes(), - NullOp::RuntimeChecks(kind) => { - let val = kind.value(fx.tcx.sess); - let val = CValue::by_val( - fx.bcx.ins().iconst(types::I8, i64::from(val)), - fx.layout_of(fx.tcx.types.bool), - ); - lval.write_cvalue(fx, val); - return; - } + NullOp::RuntimeChecks(kind) => kind.value(fx.tcx.sess), }; let val = CValue::by_val( - fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(val).unwrap()), - fx.layout_of(fx.tcx.types.usize), + fx.bcx.ins().iconst(types::I8, i64::from(val)), + fx.layout_of(fx.tcx.types.bool), ); lval.write_cvalue(fx, val); } From 0087253015d1191b97b5e312c2409e008db87ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 18 Nov 2025 14:31:06 +0100 Subject: [PATCH 064/585] early return on duplicate span lowerings --- compiler/rustc_ast_lowering/src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9cb17ea67a37..4172d079abac 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -220,6 +220,13 @@ struct SpanLowerer { impl SpanLowerer { fn lower(&self, span: Span) -> Span { if self.is_incremental { + // early return: span lowering takes some time since it accesses the query dependency graph + // to make sure we rerun the right code paths when spans change. When we've already lowered a span, + // or don't have to, bail out ASAP. + if span.is_dummy() || span.parent().is_some_and(|i| i == self.def_id) { + return span; + } + span.with_parent(Some(self.def_id)) } else { // Do not make spans relative when not using incremental compilation. From 98bf9c48574c9863f236939157c7006013175bb2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 19 Nov 2025 14:49:43 +0000 Subject: [PATCH 065/585] Rustup to rustc 1.93.0-nightly (3d461af2a 2025-11-18) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 3aeb07e469a3..5eba4411d78b 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-11-15" +channel = "nightly-2025-11-19" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 8ad6e38384241d3766b7a09dc898be00dff6d051 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 19 Nov 2025 15:02:42 +0000 Subject: [PATCH 066/585] Remove no longer necessary portable-simd patch --- ...-simd-Disable-broken-reduce_sum-test.patch | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch diff --git a/patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch b/patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch deleted file mode 100644 index b1fd6224632b..000000000000 --- a/patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 5489384bc265e9e6fc2efaa63d93a4d51ebec2f5 Mon Sep 17 00:00:00 2001 -From: bjorn3 <17426603+bjorn3@users.noreply.github.com> -Date: Thu, 22 Aug 2024 19:22:58 +0000 -Subject: [PATCH] Disable broken reduce_sum test - -It was broken by an upstream change to the .sum() implementation on -float iterators. ---- - crates/core_simd/tests/ops_macros.rs | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs -index aa565a1..5e6ac41 100644 ---- a/crates/core_simd/tests/ops_macros.rs -+++ b/crates/core_simd/tests/ops_macros.rs -@@ -646,6 +646,7 @@ macro_rules! impl_float_tests { - } - - fn reduce_sum() { -+ return; - test_helpers::test_1(&|x| { - test_helpers::prop_assert_biteq! ( - Vector::::from_array(x).reduce_sum(), --- -2.34.1 - From 0670b60de378951a518fbd67dd24849629534585 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 19 Nov 2025 15:16:18 +0000 Subject: [PATCH 067/585] Use the rust-std manifest file in build_llvm_sysroot_for_triple This is far more accurate than filtering based on filename and as such allows building the sysroot a bit quicker. In addition the code is a bit simpler. --- build_system/build_sysroot.rs | 37 ++++++++++------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 804d50e25d0d..b3bf7f725db7 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -161,35 +161,18 @@ fn build_sysroot_for_triple( fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget { let default_sysroot = crate::rustc_info::get_default_sysroot(&compiler.rustc); - let mut target_libs = SysrootTarget { triple: compiler.triple, libs: vec![] }; + let std_manifest_path = default_sysroot + .join("lib") + .join("rustlib") + .join(format!("manifest-rust-std-{}", compiler.triple)); - for entry in fs::read_dir( - default_sysroot.join("lib").join("rustlib").join(&target_libs.triple).join("lib"), - ) - .unwrap() - { - let entry = entry.unwrap(); - if entry.file_type().unwrap().is_dir() { - continue; - } - let file = entry.path(); - let file_name_str = file.file_name().unwrap().to_str().unwrap(); - if (file_name_str.contains("rustc_") - && !file_name_str.contains("rustc_std_workspace_") - && !file_name_str.contains("rustc_demangle") - && !file_name_str.contains("rustc_literal_escaper")) - || file_name_str.contains("chalk") - || file_name_str.contains("tracing") - || file_name_str.contains("regex") - { - // These are large crates that are part of the rustc-dev component and are not - // necessary to run regular programs. - continue; - } - target_libs.libs.push(file); - } + let libs = fs::read_to_string(std_manifest_path) + .unwrap() + .lines() + .map(|entry| default_sysroot.join(entry.strip_prefix("file:").unwrap())) + .collect(); - target_libs + SysrootTarget { triple: compiler.triple, libs } } fn build_clif_sysroot_for_triple( From 4adcdbb58ba65d0af86c50d77ef42b344b9a5cb2 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Wed, 19 Nov 2025 22:49:44 -0600 Subject: [PATCH 068/585] In `BTreeMap::eq`, do not compare the elements if the sizes are different. Reverts 68a7c250788833305f73f816b284aafa9e62370a in library/ --- library/alloc/src/collections/btree/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 766f4589177a..e9d0ad72c1e4 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2416,7 +2416,7 @@ fn default() -> BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for BTreeMap { fn eq(&self, other: &BTreeMap) -> bool { - self.iter().eq(other) + self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b) } } From 907f5c118096eb2e2031f41a5a3337791c7a111e Mon Sep 17 00:00:00 2001 From: Zachary S Date: Thu, 20 Nov 2025 00:09:56 -0600 Subject: [PATCH 069/585] Add regression test for collections' PartialEq::eq impls not comparing elements if lengths are different. --- .../tests/collections/eq_diff_len.rs | 96 +++++++++++++++++++ library/alloctests/tests/collections/mod.rs | 1 + 2 files changed, 97 insertions(+) create mode 100644 library/alloctests/tests/collections/eq_diff_len.rs diff --git a/library/alloctests/tests/collections/eq_diff_len.rs b/library/alloctests/tests/collections/eq_diff_len.rs new file mode 100644 index 000000000000..ee1e294d37c6 --- /dev/null +++ b/library/alloctests/tests/collections/eq_diff_len.rs @@ -0,0 +1,96 @@ +//! Regression tests which fail if some collections' `PartialEq::eq` impls compare +//! elements when the collections have different sizes. +//! This behavior is not guaranteed either way, so regressing these tests is fine +//! if it is done on purpose. +use std::cmp::Ordering; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, LinkedList}; + +/// This intentionally has a panicking `PartialEq` impl, to test that various +/// collections' `PartialEq` impls don't actually compare elements if their sizes +/// are unequal. +/// +/// This is not advisable in normal code. +#[derive(Debug, Clone, Copy, Hash)] +struct Evil; + +impl PartialEq for Evil { + fn eq(&self, _: &Self) -> bool { + panic!("Evil::eq is evil"); + } +} +impl Eq for Evil {} + +impl PartialOrd for Evil { + fn partial_cmp(&self, _: &Self) -> Option { + Some(Ordering::Equal) + } +} + +impl Ord for Evil { + fn cmp(&self, _: &Self) -> Ordering { + // Constructing a `BTreeSet`/`BTreeMap` uses `cmp` on the elements, + // but comparing it with with `==` uses `eq` on the elements, + // so Evil::cmp doesn't need to be evil. + Ordering::Equal + } +} + +// check Evil works +#[test] +#[should_panic = "Evil::eq is evil"] +fn evil_eq_works() { + let v1 = vec![Evil]; + let v2 = vec![Evil]; + + _ = v1 == v2; +} + +// check various containers don't compare if their sizes are different + +#[test] +fn vec_evil_eq() { + let v1 = vec![Evil]; + let v2 = vec![Evil; 2]; + + assert_eq!(false, v1 == v2); +} + +#[test] +fn hashset_evil_eq() { + let s1 = HashSet::from([(0, Evil)]); + let s2 = HashSet::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, s1 == s2); +} + +#[test] +fn hashmap_evil_eq() { + let m1 = HashMap::from([(0, Evil)]); + let m2 = HashMap::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, m1 == m2); +} + +#[test] +fn btreeset_evil_eq() { + let s1 = BTreeSet::from([(0, Evil)]); + let s2 = BTreeSet::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, s1 == s2); +} + +#[test] +fn btreemap_evil_eq() { + let m1 = BTreeMap::from([(0, Evil)]); + let m2 = BTreeMap::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, m1 == m2); +} + +#[test] +fn linkedlist_evil_eq() { + let m1 = LinkedList::from([Evil]); + let m2 = LinkedList::from([Evil; 2]); + + assert_eq!(false, m1 == m2); +} diff --git a/library/alloctests/tests/collections/mod.rs b/library/alloctests/tests/collections/mod.rs index e73f3aaef8c8..2d387f0e77eb 100644 --- a/library/alloctests/tests/collections/mod.rs +++ b/library/alloctests/tests/collections/mod.rs @@ -1 +1,2 @@ mod binary_heap; +mod eq_diff_len; From 53f8a7bd0b9be3bddeaed2fef4994805fc4d5da5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 20 Nov 2025 12:01:48 +0100 Subject: [PATCH 070/585] Make it clearer what exactly is being benchmarked --- build_system/bench.rs | 42 +++++++++++++++++++++-------------- build_system/build_backend.rs | 5 +++++ build_system/build_sysroot.rs | 4 ++++ build_system/main.rs | 7 +----- 4 files changed, 35 insertions(+), 23 deletions(-) diff --git a/build_system/bench.rs b/build_system/bench.rs index 192cb499536f..80c7826d4e73 100644 --- a/build_system/bench.rs +++ b/build_system/bench.rs @@ -39,7 +39,26 @@ pub(crate) fn benchmark(dirs: &Dirs, compiler: &Compiler) { let rustc_clif = &compiler.rustc; let rustflags = &compiler.rustflags.join("\x1f"); let manifest_path = SIMPLE_RAYTRACER_REPO.source_dir().to_path(dirs).join("Cargo.toml"); - let target_dir = dirs.build_dir.join("simple_raytracer"); + let target_dir = dirs.build_dir.join("simple-raytracer_target"); + + let raytracer_cg_llvm = dirs + .build_dir + .join(get_file_name(&compiler.rustc, "raytracer_cg_llvm", "bin")) + .to_str() + .unwrap() + .to_owned(); + let raytracer_cg_clif = dirs + .build_dir + .join(get_file_name(&compiler.rustc, "raytracer_cg_clif", "bin")) + .to_str() + .unwrap() + .to_owned(); + let raytracer_cg_clif_opt = dirs + .build_dir + .join(get_file_name(&compiler.rustc, "raytracer_cg_clif_opt", "bin")) + .to_str() + .unwrap() + .to_owned(); let clean_cmd = format!( "RUSTC=rustc cargo clean --manifest-path {manifest_path} --target-dir {target_dir}", @@ -47,19 +66,19 @@ pub(crate) fn benchmark(dirs: &Dirs, compiler: &Compiler) { target_dir = target_dir.display(), ); let llvm_build_cmd = format!( - "RUSTC=rustc cargo build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_llvm || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_llvm", + "RUSTC=rustc cargo build --manifest-path {manifest_path} --target-dir {target_dir} && (rm {raytracer_cg_llvm} || true) && ln {target_dir}/debug/main {raytracer_cg_llvm}", manifest_path = manifest_path.display(), target_dir = target_dir.display(), ); let clif_build_cmd = format!( - "RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_clif || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_clif", + "RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} && (rm {raytracer_cg_clif} || true) && ln {target_dir}/debug/main {raytracer_cg_clif}", cargo_clif = cargo_clif.display(), rustc_clif = rustc_clif.display(), manifest_path = manifest_path.display(), target_dir = target_dir.display(), ); let clif_build_opt_cmd = format!( - "RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} --release && (rm build/raytracer_cg_clif_opt || true) && ln build/simple_raytracer/release/main build/raytracer_cg_clif_opt", + "RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" CARGO_BUILD_INCREMENTAL=true {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} --release && (rm {raytracer_cg_clif_opt} || true) && ln {target_dir}/release/main {raytracer_cg_clif_opt}", cargo_clif = cargo_clif.display(), rustc_clif = rustc_clif.display(), manifest_path = manifest_path.display(), @@ -92,24 +111,13 @@ pub(crate) fn benchmark(dirs: &Dirs, compiler: &Compiler) { let bench_run_markdown = dirs.build_dir.join("bench_run.md"); - let raytracer_cg_llvm = - Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_llvm", "bin")); - let raytracer_cg_clif = - Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_clif", "bin")); - let raytracer_cg_clif_opt = - Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_clif_opt", "bin")); - let mut bench_run = hyperfine_command( + let bench_run = hyperfine_command( 0, bench_runs, None, - &[ - ("", raytracer_cg_llvm.to_str().unwrap()), - ("", raytracer_cg_clif.to_str().unwrap()), - ("", raytracer_cg_clif_opt.to_str().unwrap()), - ], + &[("", &raytracer_cg_llvm), ("", &raytracer_cg_clif), ("", &raytracer_cg_clif_opt)], &bench_run_markdown, ); - bench_run.current_dir(&dirs.build_dir); spawn_and_wait(bench_run); if let Some(gha_step_summary) = gha_step_summary.as_mut() { diff --git a/build_system/build_backend.rs b/build_system/build_backend.rs index ad6743a6d659..c0a8cc95614f 100644 --- a/build_system/build_backend.rs +++ b/build_system/build_backend.rs @@ -22,6 +22,11 @@ pub(crate) fn build_backend( rustflags.push("-Zallow-features=rustc_private,f16,f128".to_owned()); rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &rustflags); + // Use incr comp despite release mode unless incremental builds are explicitly disabled + if env::var_os("CARGO_BUILD_INCREMENTAL").is_none() { + cmd.env("CARGO_BUILD_INCREMENTAL", "true"); + } + if env::var("CG_CLIF_EXPENSIVE_CHECKS").is_ok() { // Enabling debug assertions implicitly enables the clif ir verifier cmd.env("CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS", "true"); diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index b3bf7f725db7..e7363e37a45d 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -234,6 +234,10 @@ fn build_clif_sysroot_for_triple( if compiler.triple.contains("apple") { build_cmd.env("CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO", "packed"); } + // Use incr comp despite release mode unless incremental builds are explicitly disabled + if env::var_os("CARGO_BUILD_INCREMENTAL").is_none() { + build_cmd.env("CARGO_BUILD_INCREMENTAL", "true"); + } spawn_and_wait(build_cmd); for entry in fs::read_dir(build_dir.join("deps")).unwrap() { diff --git a/build_system/main.rs b/build_system/main.rs index fc0093128300..6251687babc6 100644 --- a/build_system/main.rs +++ b/build_system/main.rs @@ -59,11 +59,6 @@ fn main() { } env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1"); - // Force incr comp even in release mode unless in CI or incremental builds are explicitly disabled - if env::var_os("CARGO_BUILD_INCREMENTAL").is_none() { - env::set_var("CARGO_BUILD_INCREMENTAL", "true"); - } - let mut args = env::args().skip(1); let command = match args.next().as_deref() { Some("prepare") => Command::Prepare, @@ -79,7 +74,7 @@ fn main() { } }; - let mut out_dir = PathBuf::from("."); + let mut out_dir = std::env::current_dir().unwrap(); let mut download_dir = None; let mut sysroot_kind = SysrootKind::Clif; let mut use_unstable_features = true; From f943606503b142b24edb2b20f77f1eb737fb9ed2 Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 20 Nov 2025 20:53:51 +0800 Subject: [PATCH 071/585] Fix unused_assignments false positives from macros --- compiler/rustc_mir_transform/src/liveness.rs | 5 +++++ tests/ui/liveness/auxiliary/aux_issue_147648.rs | 7 +++++++ .../liveness/unused-assignments-from-macro-147648.rs | 10 ++++++++++ 3 files changed, 22 insertions(+) create mode 100644 tests/ui/liveness/auxiliary/aux_issue_147648.rs create mode 100644 tests/ui/liveness/unused-assignments-from-macro-147648.rs diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index f7dc70356024..d9dd7f9c5b19 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -72,6 +72,11 @@ pub(crate) fn check_liveness<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Den return DenseBitSet::new_empty(0); } + // Don't run unused pass for items generated by foreign macros + if tcx.def_span(parent).in_external_macro(tcx.sess.source_map()) { + return DenseBitSet::new_empty(0); + } + let mut body = &*tcx.mir_promoted(def_id).0.borrow(); let mut body_mem; diff --git a/tests/ui/liveness/auxiliary/aux_issue_147648.rs b/tests/ui/liveness/auxiliary/aux_issue_147648.rs new file mode 100644 index 000000000000..ccb5ad6b8fc0 --- /dev/null +++ b/tests/ui/liveness/auxiliary/aux_issue_147648.rs @@ -0,0 +1,7 @@ +#[macro_export] +macro_rules! unused_assign { + ($x:ident) => { + let mut $x = 1; + $x = 2; + }; +} diff --git a/tests/ui/liveness/unused-assignments-from-macro-147648.rs b/tests/ui/liveness/unused-assignments-from-macro-147648.rs new file mode 100644 index 000000000000..c32c281538b4 --- /dev/null +++ b/tests/ui/liveness/unused-assignments-from-macro-147648.rs @@ -0,0 +1,10 @@ +//@ check-pass +//@ aux-build:aux_issue_147648.rs + +#![deny(unused_assignments)] + +extern crate aux_issue_147648; + +fn main() { + aux_issue_147648::unused_assign!(y); +} From 06962948eb7bf5abbfce4169215c1b5602e8cea9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 20 Nov 2025 11:20:25 +0000 Subject: [PATCH 072/585] Update to Cranelift 0.126 --- Cargo.lock | 109 +++++++++++++++++++++++++++----------------------- Cargo.toml | 24 +++++------ src/common.rs | 2 + 3 files changed, 73 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 09b6c6b87c30..dc27d9c6b542 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,15 +10,15 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" [[package]] name = "bitflags" @@ -43,42 +43,42 @@ checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cranelift-assembler-x64" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f502c60b6af2025c312b37788c089943ef03156a2910da1aa046bb39eb8f61c7" +checksum = "bf7631e609c97f063f9777aae405e8492abf9bf92336d7aa3f875403dd4ffd7d" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b7e21a74bcf08443a4ef800a4a257063e5c51ee4d7a3bd58da5262d10340830" +checksum = "9c030edccdc4a5bbf28fbfe7701b5cd1f9854b4445184dd34af2a7e8f8db6f45" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f337d268865c292ad5df0669a9bbf6223ca41460292a20ad5b0a57b8e9f27f93" +checksum = "bb544c1242d0ca98baf01873ebba96c79d5df155d5108d9bb699aefc741f5e6d" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0e60319a8242c8d1c7b5a2444d140c416f903f75e0d84da3256fceb822bab85" +checksum = "f0325aecbafec053d3d3f082edfdca7937e2945e7f09c5ff9672e05198312282" [[package]] name = "cranelift-codegen" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78dee669e447a1c68760bf7acee33835e99d564f0137b067f74d4718dfc9970d" +checksum = "abb3236fd319ae897ba00c8a25105081de5c1348576def0e96c062ad259f87a7" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -102,9 +102,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601f629d172b7230f41dd0e78ee797efaf7ec1a5e113c8f395f4027dff6a92ca" +checksum = "7b8791c911a361c539130ace34fb726b16aca4216470ec75d75264b1495c8a3a" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -114,33 +114,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15755c2660902c7d59d96f6551a66ef629650dc3fd405f9dad841e8c58c1a4a2" +checksum = "12ead718c2a10990870c19b2497b5a04b8aae6024485e33da25b5d02e35819e0" [[package]] name = "cranelift-control" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727bfca18705101a294ab9077ad214a8b762ea2bc9844389d0db233d7c61ec3b" +checksum = "c0a57fc972b5651047efddccb99440d103d9d8c13393ccebde15ddd5b6a1181b" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15564c6f0c72750ca4374f40b044857cbc8087571e46d4c7ccdbdcc29b1dec8b" +checksum = "5aae980b4a1678b601eab2f52e372ed0b3c9565a31c17f380008cb97b3a699c5" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16c681f2731f1cf68eed9f3b6811571823a5ac498f59c52b73736b68599defb3" +checksum = "a78877016b607982ca1708c0dd4ce23bde04581a39854c9b43a1dca43625b54c" dependencies = [ "cranelift-codegen", "log", @@ -150,15 +150,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40cedc02f08307da019a3e06d3f20f772f829ff813aec975accb012f8930b688" +checksum = "5dc46a68b46d4f53f9f2f02ab8d3a34b00f03a21c124a7a965b8cbf5fdb6773b" [[package]] name = "cranelift-jit" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2864461448c72d15ae3311ea63df9c7e35f22f04683785f6715a0cf17e6577d" +checksum = "7df920009af919ad9df52eb7b47b1895145822e0c29da9b715a876fc8ecc6d82" dependencies = [ "anyhow", "cranelift-codegen", @@ -176,9 +176,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b31d249bbbccc4c1ae54701087d4d49d05951897691eef44f4a60e70252743b" +checksum = "ddcf313629071ce74de8e59f02092f5453d1a01047607fc4ad36886b8bd1486c" dependencies = [ "anyhow", "cranelift-codegen", @@ -187,9 +187,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db03ab51c60710eb83d0217725b77db4062aca83b35359f5e6aa99ed1c275977" +checksum = "03faa07ec8cf373250a8252eb773d098ff88259fa1c19ee1ecde8012839f4097" dependencies = [ "cranelift-codegen", "libc", @@ -198,9 +198,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7131e0eb45ee10b0bd6082d0c0114c2e9a670b034d46774b39d0fc5c0ed7cedf" +checksum = "7cca62c14f3c2e4f438192562bbf82d1a98a59543cc66ba04fb658ba99f515a6" dependencies = [ "anyhow", "cranelift-codegen", @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7a06c330b7994a891ad5b622ebc9aefcd17beae832dd25f577cf60c13426bf" +checksum = "0484cb32c527a742e1bba09ef174acac0afb1dcf623ef1adda42849200edcd2e" [[package]] name = "crc32fast" @@ -246,9 +246,9 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "gimli" -version = "0.32.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" dependencies = [ "fallible-iterator", "indexmap", @@ -282,9 +282,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.174" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libloading" @@ -304,9 +304,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "mach2" @@ -405,18 +405,27 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -460,9 +469,9 @@ checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "wasmtime-internal-jit-icache-coherence" -version = "38.0.1" +version = "39.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d0a76f1a6e887cc1b551b02dfd6e2ce5f6738e8cacd9ad7284f6ac1aac4698f" +checksum = "3f67986f5c499274ae5b2ba5b173bba0b95d1381f5ca70d8eec657f2392117d8" dependencies = [ "anyhow", "cfg-if", @@ -472,9 +481,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-math" -version = "38.0.1" +version = "39.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b900df4252ad86547e7f2b2c00201b006db4e864893bedfb3aca32b23d81868a" +checksum = "a681733e9b5d5d8804ee6cacd59f92c0d87ba2274f42ee1d4e5a943828d0075d" dependencies = [ "libm", ] diff --git a/Cargo.toml b/Cargo.toml index f2001123e579..02d0d2ab3c58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.125.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.125.0" } -cranelift-module = { version = "0.125.0" } -cranelift-native = { version = "0.125.0" } -cranelift-jit = { version = "0.125.0", optional = true } -cranelift-object = { version = "0.125.0" } +cranelift-codegen = { version = "0.126.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.126.0" } +cranelift-module = { version = "0.126.0" } +cranelift-native = { version = "0.126.0" } +cranelift-jit = { version = "0.126.0", optional = true } +cranelift-object = { version = "0.126.0" } target-lexicon = "0.13" gimli = { version = "0.32", default-features = false, features = ["write"] } object = { version = "0.37.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } diff --git a/src/common.rs b/src/common.rs index 758d89c92b75..b11f42408f58 100644 --- a/src/common.rs +++ b/src/common.rs @@ -388,6 +388,7 @@ pub(crate) fn create_stack_slot(&mut self, size: u32, align: u32) -> Pointer { size, // The maximum value of ilog2 is 31 which will always fit in a u8. align_shift: align.ilog2().try_into().unwrap(), + key: None, }); Pointer::stack_slot(stack_slot) } else { @@ -397,6 +398,7 @@ pub(crate) fn create_stack_slot(&mut self, size: u32, align: u32) -> Pointer { kind: StackSlotKind::ExplicitSlot, size: size + align, align_shift: abi_align.ilog2().try_into().unwrap(), + key: None, }); let base_ptr = self.bcx.ins().stack_addr(self.pointer_type, stack_slot, 0); let misalign_offset = self.bcx.ins().band_imm(base_ptr, i64::from(align - 1)); From fb32ac4a635dada245f892d5b56caad2182e56a3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 21 Nov 2025 10:31:02 +0000 Subject: [PATCH 073/585] Minor benchmarking improvements --- build_system/bench.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build_system/bench.rs b/build_system/bench.rs index 80c7826d4e73..91353ba8a874 100644 --- a/build_system/bench.rs +++ b/build_system/bench.rs @@ -111,13 +111,18 @@ pub(crate) fn benchmark(dirs: &Dirs, compiler: &Compiler) { let bench_run_markdown = dirs.build_dir.join("bench_run.md"); - let bench_run = hyperfine_command( + let mut bench_run = hyperfine_command( 0, bench_runs, None, - &[("", &raytracer_cg_llvm), ("", &raytracer_cg_clif), ("", &raytracer_cg_clif_opt)], + &[ + ("build/raytracer_cg_llvm", &raytracer_cg_llvm), + ("build/raytracer_cg_clif", &raytracer_cg_clif), + ("build/raytracer_cg_clif_opt", &raytracer_cg_clif_opt), + ], &bench_run_markdown, ); + bench_run.current_dir(&dirs.build_dir); spawn_and_wait(bench_run); if let Some(gha_step_summary) = gha_step_summary.as_mut() { From f5a5f0ff03be6c3feb25440c675ce6bcb787ec23 Mon Sep 17 00:00:00 2001 From: yukang Date: Fri, 21 Nov 2025 20:34:35 +0800 Subject: [PATCH 074/585] use verbose for associated functions suggestion --- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- tests/ui/issues/issue-4265.stderr | 10 ++-- tests/ui/methods/issue-3707.stderr | 10 ++-- tests/ui/suggestions/issue-102354.stderr | 10 ++-- tests/ui/suggestions/issue-103646.stderr | 10 ++-- .../suggest-assoc-fn-call-deref.stderr | 10 ++-- ...uggest-assoc-fn-call-for-impl-trait.stderr | 30 ++++++----- ...-fn-call-with-turbofish-placeholder.stderr | 10 ++-- ...n-call-with-turbofish-through-deref.stderr | 10 ++-- ...uggest-assoc-fn-call-with-turbofish.stderr | 50 +++++++++++-------- ...gest-assoc-fn-call-without-receiver.stderr | 40 +++++++++------ 11 files changed, 115 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index a0d9e9a72386..37661f93f021 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2339,7 +2339,7 @@ fn suggest_associated_call_syntax( applicability = Applicability::HasPlaceholders; "(...)".to_owned() }; - err.span_suggestion( + err.span_suggestion_verbose( sugg_span, "use associated function syntax instead", format!("{ty_str}::{item_name}{args}"), diff --git a/tests/ui/issues/issue-4265.stderr b/tests/ui/issues/issue-4265.stderr index 23d00aaa44b5..d4a44c129a89 100644 --- a/tests/ui/issues/issue-4265.stderr +++ b/tests/ui/issues/issue-4265.stderr @@ -14,10 +14,7 @@ LL | struct Foo { | ---------- method `bar` not found for this struct ... LL | Foo { baz: 0 }.bar(); - | ---------------^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `Foo::bar()` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `Foo` @@ -25,6 +22,11 @@ note: the candidate is defined in an impl for the type `Foo` | LL | fn bar() { | ^^^^^^^^ +help: use associated function syntax instead + | +LL - Foo { baz: 0 }.bar(); +LL + Foo::bar(); + | error: aborting due to 2 previous errors diff --git a/tests/ui/methods/issue-3707.stderr b/tests/ui/methods/issue-3707.stderr index b3d4dfe5aaa8..c163ccc81899 100644 --- a/tests/ui/methods/issue-3707.stderr +++ b/tests/ui/methods/issue-3707.stderr @@ -2,10 +2,7 @@ error[E0599]: no method named `boom` found for reference `&Obj` in the current s --> $DIR/issue-3707.rs:10:14 | LL | self.boom(); - | -----^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `Obj::boom()` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `Obj` @@ -13,6 +10,11 @@ note: the candidate is defined in an impl for the type `Obj` | LL | pub fn boom() -> bool { | ^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - self.boom(); +LL + Obj::boom(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/issue-102354.stderr b/tests/ui/suggestions/issue-102354.stderr index 8340d9340f9b..9354ce3efe57 100644 --- a/tests/ui/suggestions/issue-102354.stderr +++ b/tests/ui/suggestions/issue-102354.stderr @@ -2,10 +2,7 @@ error[E0599]: no method named `func` found for type `i32` in the current scope --> $DIR/issue-102354.rs:9:7 | LL | x.func(); - | --^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `i32::func()` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `Trait` @@ -13,6 +10,11 @@ note: the candidate is defined in the trait `Trait` | LL | fn func() {} | ^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.func(); +LL + i32::func(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/issue-103646.stderr b/tests/ui/suggestions/issue-103646.stderr index 8d0e8652392d..42505e13e7e6 100644 --- a/tests/ui/suggestions/issue-103646.stderr +++ b/tests/ui/suggestions/issue-103646.stderr @@ -4,10 +4,7 @@ error[E0599]: no method named `nya` found for type parameter `T` in the current LL | fn uwu(c: T) { | - method `nya` not found for this type parameter LL | c.nya(); - | --^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `T::nya()` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `Cat` @@ -15,6 +12,11 @@ note: the candidate is defined in the trait `Cat` | LL | fn nya() {} | ^^^^^^^^ +help: use associated function syntax instead + | +LL - c.nya(); +LL + T::nya(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-deref.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-deref.stderr index a30b78692146..2314ff378f64 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-deref.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-deref.stderr @@ -2,10 +2,7 @@ error[E0599]: no method named `test` found for struct `Box>` in the cur --> $DIR/suggest-assoc-fn-call-deref.rs:13:7 | LL | x.test(); - | --^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `Foo::::test()` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `Foo` @@ -13,6 +10,11 @@ note: the candidate is defined in an impl for the type `Foo` | LL | fn test() -> i32 { 1 } | ^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.test(); +LL + Foo::::test(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr index 0df2b08d3be8..4ff4c50f1790 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr @@ -5,10 +5,7 @@ LL | struct A { | -------- method `foo` not found for this struct ... LL | _a.foo(); - | ---^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::foo(_a)` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `M` @@ -16,6 +13,11 @@ note: the candidate is defined in the trait `M` | LL | fn foo(_a: Self); | ^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _a.foo(); +LL + A::foo(_a); + | error[E0599]: no method named `baz` found for struct `A` in the current scope --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:23:8 @@ -24,10 +26,7 @@ LL | struct A { | -------- method `baz` not found for this struct ... LL | _a.baz(0); - | ---^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::baz(0)` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `M` @@ -35,6 +34,11 @@ note: the candidate is defined in the trait `M` | LL | fn baz(_a: i32); | ^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _a.baz(0); +LL + A::baz(0); + | error[E0599]: no method named `bar` found for struct `A` in the current scope --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:27:8 @@ -43,10 +47,7 @@ LL | struct A { | -------- method `bar` not found for this struct ... LL | _b.bar(); - | ---^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::bar(_b)` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `M` @@ -54,6 +55,11 @@ note: the candidate is defined in the trait `M` | LL | fn bar(_a: Self); | ^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _b.bar(); +LL + A::bar(_b); + | error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr index 6e4c77deac50..df8d80c4babf 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr @@ -5,10 +5,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `default_hello` not found for this struct ... LL | x.default_hello(); - | --^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::<_>::default_hello()` + | ^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -16,6 +13,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn default_hello() {} | ^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.default_hello(); +LL + GenericAssocMethod::<_>::default_hello(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr index 1bc259294469..99d206764a17 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr @@ -2,10 +2,7 @@ error[E0599]: no method named `hello` found for struct `RefMut<'_, HasAssocMetho --> $DIR/suggest-assoc-fn-call-with-turbofish-through-deref.rs:11:11 | LL | state.hello(); - | ------^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `HasAssocMethod::hello()` + | ^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `HasAssocMethod` @@ -13,6 +10,11 @@ note: the candidate is defined in an impl for the type `HasAssocMethod` | LL | fn hello() {} | ^^^^^^^^^^ +help: use associated function syntax instead + | +LL - state.hello(); +LL + HasAssocMethod::hello(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr index 92b03fc77142..56d6b9fcd143 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr @@ -5,10 +5,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_ref_hello` not found for this struct ... LL | x.self_ty_ref_hello(); - | --^^^^^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_ref_hello(&x)` + | ^^^^^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -16,6 +13,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn self_ty_ref_hello(_: &Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.self_ty_ref_hello(); +LL + GenericAssocMethod::<_>::self_ty_ref_hello(&x); + | error[E0599]: no method named `self_ty_hello` found for struct `GenericAssocMethod<{integer}>` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:16:7 @@ -24,10 +26,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_hello` not found for this struct ... LL | x.self_ty_hello(); - | --^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_hello(x)` + | ^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -35,6 +34,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn self_ty_hello(_: Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.self_ty_hello(); +LL + GenericAssocMethod::<_>::self_ty_hello(x); + | error[E0599]: no method named `default_hello` found for struct `GenericAssocMethod` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:20:7 @@ -43,10 +47,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `default_hello` not found for this struct ... LL | y.default_hello(); - | --^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::::default_hello()` + | ^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -54,6 +55,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn default_hello() {} | ^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - y.default_hello(); +LL + GenericAssocMethod::::default_hello(); + | error[E0599]: no method named `self_ty_ref_hello` found for struct `GenericAssocMethod` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:22:7 @@ -62,10 +68,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_ref_hello` not found for this struct ... LL | y.self_ty_ref_hello(); - | --^^^^^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::::self_ty_ref_hello(&y)` + | ^^^^^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -73,6 +76,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn self_ty_ref_hello(_: &Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - y.self_ty_ref_hello(); +LL + GenericAssocMethod::::self_ty_ref_hello(&y); + | error[E0599]: no method named `self_ty_hello` found for struct `GenericAssocMethod` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:24:7 @@ -81,10 +89,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_hello` not found for this struct ... LL | y.self_ty_hello(); - | --^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::::self_ty_hello(y)` + | ^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -92,6 +97,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn self_ty_hello(_: Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - y.self_ty_hello(); +LL + GenericAssocMethod::::self_ty_hello(y); + | error: aborting due to 5 previous errors diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-without-receiver.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-without-receiver.stderr index 793595784d93..a09cf41488df 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-without-receiver.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-without-receiver.stderr @@ -5,10 +5,7 @@ LL | struct A {} | -------- method `hello` not found for this struct ... LL | _a.hello(1); - | ---^^^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::hello(1)` + | ^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `A` @@ -16,6 +13,11 @@ note: the candidate is defined in an impl for the type `A` | LL | fn hello(_a: i32) {} | ^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _a.hello(1); +LL + A::hello(1); + | error[E0599]: no method named `test` found for struct `A` in the current scope --> $DIR/suggest-assoc-fn-call-without-receiver.rs:22:8 @@ -24,10 +26,7 @@ LL | struct A {} | -------- method `test` not found for this struct ... LL | _a.test(1); - | ---^^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::test(_a, 1)` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `A` @@ -35,6 +34,11 @@ note: the candidate is defined in an impl for the type `A` | LL | fn test(_a: Self, _b: i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _a.test(1); +LL + A::test(_a, 1); + | error[E0599]: no method named `hello` found for struct `B<&str>` in the current scope --> $DIR/suggest-assoc-fn-call-without-receiver.rs:26:8 @@ -43,10 +47,7 @@ LL | struct B { | ----------- method `hello` not found for this struct ... LL | _b.hello(1); - | ---^^^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `B::<&str>::hello(1)` + | ^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `B` @@ -54,6 +55,11 @@ note: the candidate is defined in an impl for the type `B` | LL | fn hello(_a: i32) {} | ^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _b.hello(1); +LL + B::<&str>::hello(1); + | error[E0599]: no method named `test` found for struct `B<&str>` in the current scope --> $DIR/suggest-assoc-fn-call-without-receiver.rs:28:8 @@ -62,10 +68,7 @@ LL | struct B { | ----------- method `test` not found for this struct ... LL | _b.test(1); - | ---^^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `B::<&str>::test(_b, 1)` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `B` @@ -73,6 +76,11 @@ note: the candidate is defined in an impl for the type `B` | LL | fn test(_a: Self, _b: i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _b.test(1); +LL + B::<&str>::test(_b, 1); + | error: aborting due to 4 previous errors From e802180f416b1e30b70e605e4d950ea5e5564745 Mon Sep 17 00:00:00 2001 From: yukang Date: Fri, 21 Nov 2025 21:04:13 +0800 Subject: [PATCH 075/585] add suggestion for associated function --- compiler/rustc_hir_typeck/src/expr.rs | 34 +++++++++++++++ tests/ui/methods/assc-func-issue-149038.rs | 10 +++++ .../ui/methods/assc-func-issue-149038.stderr | 43 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 tests/ui/methods/assc-func-issue-149038.rs create mode 100644 tests/ui/methods/assc-func-issue-149038.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 658f9857e5e1..29eb1183953a 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3369,6 +3369,40 @@ fn no_such_field_err( err.span_label(within_macro_span, "due to this macro variable"); } + // Check if there is an associated function with the same name. + if let Some(def_id) = base_ty.peel_refs().ty_adt_def().map(|d| d.did()) { + for impl_def_id in self.tcx.inherent_impls(def_id) { + for item in self.tcx.associated_items(impl_def_id).in_definition_order() { + if let ExprKind::Field(base_expr, _) = expr.kind + && item.name() == field.name + && matches!(item.kind, ty::AssocKind::Fn { has_self: false, .. }) + { + err.span_label(field.span, "this is an associated function, not a method"); + err.note("found the following associated function; to be used as method, it must have a `self` parameter"); + let impl_ty = self.tcx.type_of(impl_def_id).instantiate_identity(); + err.span_note( + self.tcx.def_span(item.def_id), + format!("the candidate is defined in an impl for the type `{impl_ty}`"), + ); + + let ty_str = match base_ty.peel_refs().kind() { + ty::Adt(def, args) => self.tcx.def_path_str_with_args(def.did(), args), + _ => base_ty.peel_refs().to_string(), + }; + err.multipart_suggestion( + "use associated function syntax instead", + vec![ + (base_expr.span, ty_str), + (base_expr.span.between(field.span), "::".to_string()), + ], + Applicability::MaybeIncorrect, + ); + return err; + } + } + } + } + // try to add a suggestion in case the field is a nested field of a field of the Adt let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id(); let (ty, unwrap) = if let ty::Adt(def, args) = base_ty.kind() diff --git a/tests/ui/methods/assc-func-issue-149038.rs b/tests/ui/methods/assc-func-issue-149038.rs new file mode 100644 index 000000000000..4fb4bd72fcc3 --- /dev/null +++ b/tests/ui/methods/assc-func-issue-149038.rs @@ -0,0 +1,10 @@ +struct S; +impl S { + fn foo() {} + fn bar(&self) { + self.foo(); //~ ERROR no method named `foo` found for reference `&S` in the current scope + let f: fn() = self.foo; //~ ERROR no field `foo` on type `&S` + } +} + +fn main() {} diff --git a/tests/ui/methods/assc-func-issue-149038.stderr b/tests/ui/methods/assc-func-issue-149038.stderr new file mode 100644 index 000000000000..55b762bc0ee0 --- /dev/null +++ b/tests/ui/methods/assc-func-issue-149038.stderr @@ -0,0 +1,43 @@ +error[E0599]: no method named `foo` found for reference `&S` in the current scope + --> $DIR/assc-func-issue-149038.rs:5:14 + | +LL | self.foo(); + | ^^^ this is an associated function, not a method + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: the candidate is defined in an impl for the type `S` + --> $DIR/assc-func-issue-149038.rs:3:5 + | +LL | fn foo() {} + | ^^^^^^^^ +help: use associated function syntax instead + | +LL - self.foo(); +LL + S::foo(); + | + +error[E0609]: no field `foo` on type `&S` + --> $DIR/assc-func-issue-149038.rs:6:28 + | +LL | let f: fn() = self.foo; + | ^^^ + | | + | this is an associated function, not a method + | unknown field + | + = note: found the following associated function; to be used as method, it must have a `self` parameter +note: the candidate is defined in an impl for the type `S` + --> $DIR/assc-func-issue-149038.rs:3:5 + | +LL | fn foo() {} + | ^^^^^^^^ +help: use associated function syntax instead + | +LL - let f: fn() = self.foo; +LL + let f: fn() = S::foo; + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0599, E0609. +For more information about an error, try `rustc --explain E0599`. From adae6aa8520feb6abfcb7c0080a1d2845f701295 Mon Sep 17 00:00:00 2001 From: Greg Morenz Date: Fri, 21 Nov 2025 14:10:35 -0500 Subject: [PATCH 076/585] Add test for nfc-normalization of idents --- tests/ui/lexer/ident_normalization.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/ui/lexer/ident_normalization.rs diff --git a/tests/ui/lexer/ident_normalization.rs b/tests/ui/lexer/ident_normalization.rs new file mode 100644 index 000000000000..a16c52171106 --- /dev/null +++ b/tests/ui/lexer/ident_normalization.rs @@ -0,0 +1,20 @@ +//@check-pass +//@edition:2021 + +#![allow(non_snake_case)] + +// Tests that identifiers are NFC-normalized as per +// https://rust-lang.github.io/rfcs/2457-non-ascii-idents.html + +// Note that in the first argument of each function `K` is LATIN CAPITAL LETTER K +// and in the second it is K (KELVIN SIGN). + +fn ident_nfc(_p1: K, _p2: K) {} + +fn raw_ident_nfc(_p1: r#K, _p2: r#K) {} + +fn lifetime_nfc<'K>(_p1: &'K str, _p2: &'K str) {} + +fn raw_lifetime_nfc<'K>(_p1: &'r#K str, _p2: &'r#K str) {} + +fn main() {} From b1cde92016d139521ce6a437797574d413b4b6ce Mon Sep 17 00:00:00 2001 From: Greg Morenz Date: Fri, 21 Nov 2025 14:11:06 -0500 Subject: [PATCH 077/585] nfc normalize lifetime idents --- compiler/rustc_parse/src/lexer/mod.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 51019db7c00e..84596de12ae9 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -316,7 +316,7 @@ fn next_token_from_cursor(&mut self) -> (Token, bool) { // Include the leading `'` in the real identifier, for macro // expansion purposes. See #12512 for the gory details of why // this is necessary. - let lifetime_name = self.str_from(start); + let lifetime_name = nfc_normalize(self.str_from(start)); self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1))); if starts_with_number { let span = self.mk_sp(start, self.pos); @@ -325,8 +325,7 @@ fn next_token_from_cursor(&mut self) -> (Token, bool) { .with_span(span) .stash(span, StashKey::LifetimeIsChar); } - let ident = Symbol::intern(lifetime_name); - token::Lifetime(ident, IdentIsRaw::No) + token::Lifetime(lifetime_name, IdentIsRaw::No) } rustc_lexer::TokenKind::RawLifetime => { self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1))); @@ -373,7 +372,7 @@ fn next_token_from_cursor(&mut self) -> (Token, bool) { String::with_capacity(lifetime_name_without_tick.as_str().len() + 1); lifetime_name.push('\''); lifetime_name += lifetime_name_without_tick.as_str(); - let sym = Symbol::intern(&lifetime_name); + let sym = nfc_normalize(&lifetime_name); // Make sure we mark this as a raw identifier. self.psess.raw_identifier_spans.push(span); @@ -393,9 +392,8 @@ fn next_token_from_cursor(&mut self) -> (Token, bool) { self.pos = lt_start; self.cursor = Cursor::new(&str_before[2 as usize..], FrontmatterAllowed::No); - let lifetime_name = self.str_from(start); - let ident = Symbol::intern(lifetime_name); - token::Lifetime(ident, IdentIsRaw::No) + let lifetime_name = nfc_normalize(self.str_from(start)); + token::Lifetime(lifetime_name, IdentIsRaw::No) } } rustc_lexer::TokenKind::Semi => token::Semi, From 38987c0b9a922d7401cfd44e617003b1ea631367 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Wed, 29 Oct 2025 11:17:36 +0000 Subject: [PATCH 078/585] Remove +atomics-32 for armv4t-none-eabi and armv5te-none-eabi Also rationalise the settings, and copy in the thumb base defaults, rather than just import them, because these aren't M-profile microcontrollers and may not want to always have the same settings. --- .../src/spec/targets/armv4t_none_eabi.rs | 33 ++++++++------- .../src/spec/targets/armv5te_none_eabi.rs | 41 +++++++++++-------- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs index 129b639c5248..d6bea6efa6b6 100644 --- a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs @@ -25,15 +25,6 @@ pub(crate) fn target() -> Target { }, pointer_width: 32, arch: Arch::Arm, - /* Data layout args are '-' separated: - * little endian - * stack is 64-bit aligned (EABI) - * pointers are 32-bit - * i64 must be 64-bit aligned (EABI) - * mangle names with ELF style - * native integers are 32-bit - * All other elements are default - */ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), options: TargetOptions { abi: Abi::Eabi, @@ -43,15 +34,29 @@ pub(crate) fn target() -> Target { asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",], // Force-enable 32-bit atomics, which allows the use of atomic load/store only. // The resulting atomics are ABI incompatible with atomics backed by libatomic. - features: "+soft-float,+strict-align,+atomics-32".into(), - main_needs_argc_argv: false, + features: "+soft-float,+strict-align".into(), atomic_cas: false, has_thumb_interworking: true, - relocation_model: RelocModel::Static, + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + // Because these devices have very little resources having an unwinder is too onerous so we + // default to "abort" because the "unwind" strategy is very rare. panic_strategy: PanicStrategy::Abort, - // From thumb_base, rust-lang/rust#44993. + // Similarly, one almost always never wants to use relocatable code because of the extra + // costs it involves. + relocation_model: RelocModel::Static, + // When this section is added a volatile load to its start address is also generated. This + // volatile load is a footgun as it can end up loading an invalid memory address, depending + // on how the user set up their linker scripts. This section adds pretty printer for stuff + // like std::Vec, which is not that used in no-std context, so it's best to left it out + // until we figure a way to add the pretty printers without requiring a volatile load cf. + // rust-lang/rust#44993. emit_debug_gdb_scripts: false, - // From thumb_base, GCC gives enums a minimum of 8 bits on no-os targets. + // LLVM is eager to trash the link register when calling `noreturn` functions, which + // breaks debugging. Preserve LR by default to prevent that from happening. + frame_pointer: FramePointer::Always, + // ARM supports multiple ABIs for enums, the linux one matches the default of 32 here + // but any arm-none or thumb-none target will be defaulted to 8 on GCC. c_enum_min_bits: Some(8), ..Default::default() }, diff --git a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs index 7cd571b91479..b35b76865ee1 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs @@ -15,17 +15,7 @@ pub(crate) fn target() -> Target { }, pointer_width: 32, arch: Arch::Arm, - /* Data layout args are '-' separated: - * little endian - * stack is 64-bit aligned (EABI) - * pointers are 32-bit - * i64 must be 64-bit aligned (EABI) - * mangle names with ELF style - * native integers are 32-bit - * All other elements are default - */ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), - options: TargetOptions { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), @@ -35,16 +25,31 @@ pub(crate) fn target() -> Target { // * use little-endian asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",], // minimum extra features, these cannot be disabled via -C - // Also force-enable 32-bit atomics, which allows the use of atomic load/store only. - // The resulting atomics are ABI incompatible with atomics backed by libatomic. - features: "+soft-float,+strict-align,+atomics-32".into(), - frame_pointer: FramePointer::MayOmit, - main_needs_argc_argv: false, - // don't have atomic compare-and-swap + features: "+soft-float,+strict-align".into(), atomic_cas: false, has_thumb_interworking: true, - - ..base::thumb::opts() + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + // Because these devices have very little resources having an unwinder is too onerous so we + // default to "abort" because the "unwind" strategy is very rare. + panic_strategy: PanicStrategy::Abort, + // Similarly, one almost always never wants to use relocatable code because of the extra + // costs it involves. + relocation_model: RelocModel::Static, + // When this section is added a volatile load to its start address is also generated. This + // volatile load is a footgun as it can end up loading an invalid memory address, depending + // on how the user set up their linker scripts. This section adds pretty printer for stuff + // like std::Vec, which is not that used in no-std context, so it's best to left it out + // until we figure a way to add the pretty printers without requiring a volatile load cf. + // rust-lang/rust#44993. + emit_debug_gdb_scripts: false, + // LLVM is eager to trash the link register when calling `noreturn` functions, which + // breaks debugging. Preserve LR by default to prevent that from happening. + frame_pointer: FramePointer::Always, + // ARM supports multiple ABIs for enums, the linux one matches the default of 32 here + // but any arm-none or thumb-none target will be defaulted to 8 on GCC. + c_enum_min_bits: Some(8), + ..Default::default() }, } } From dbcb048e2854ab1ce451e98ee52f4b4f3d455335 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Sun, 16 Nov 2025 20:20:44 +0000 Subject: [PATCH 079/585] Unify the arm*-none-* and thumb*-none-* target descriptions. --- .../src/spec/base/{thumb.rs => arm_none.rs} | 29 +------------- compiler/rustc_target/src/spec/base/mod.rs | 2 +- .../src/spec/targets/armv4t_none_eabi.rs | 32 +--------------- .../src/spec/targets/armv5te_none_eabi.rs | 32 +--------------- .../src/spec/targets/thumbv4t_none_eabi.rs | 38 ++----------------- .../src/spec/targets/thumbv5te_none_eabi.rs | 29 ++------------ .../src/spec/targets/thumbv6m_none_eabi.rs | 2 +- .../src/spec/targets/thumbv6m_nuttx_eabi.rs | 2 +- .../src/spec/targets/thumbv7a_nuttx_eabi.rs | 2 +- .../src/spec/targets/thumbv7a_nuttx_eabihf.rs | 2 +- .../src/spec/targets/thumbv7em_none_eabi.rs | 2 +- .../src/spec/targets/thumbv7em_none_eabihf.rs | 2 +- .../src/spec/targets/thumbv7em_nuttx_eabi.rs | 2 +- .../spec/targets/thumbv7em_nuttx_eabihf.rs | 2 +- .../src/spec/targets/thumbv7m_none_eabi.rs | 2 +- .../src/spec/targets/thumbv7m_nuttx_eabi.rs | 2 +- .../spec/targets/thumbv8m_base_none_eabi.rs | 2 +- .../spec/targets/thumbv8m_base_nuttx_eabi.rs | 2 +- .../spec/targets/thumbv8m_main_none_eabi.rs | 2 +- .../spec/targets/thumbv8m_main_none_eabihf.rs | 2 +- .../spec/targets/thumbv8m_main_nuttx_eabi.rs | 2 +- .../targets/thumbv8m_main_nuttx_eabihf.rs | 2 +- src/doc/rustc/src/SUMMARY.md | 4 +- .../src/platform-support/armv4t-none-eabi.md | 3 +- .../src/platform-support/armv5te-none-eabi.md | 8 ++-- 25 files changed, 37 insertions(+), 172 deletions(-) rename compiler/rustc_target/src/spec/base/{thumb.rs => arm_none.rs} (54%) diff --git a/compiler/rustc_target/src/spec/base/thumb.rs b/compiler/rustc_target/src/spec/base/arm_none.rs similarity index 54% rename from compiler/rustc_target/src/spec/base/thumb.rs rename to compiler/rustc_target/src/spec/base/arm_none.rs index 03ec679038c0..feb69bdd26cd 100644 --- a/compiler/rustc_target/src/spec/base/thumb.rs +++ b/compiler/rustc_target/src/spec/base/arm_none.rs @@ -1,31 +1,4 @@ -// These `thumbv*` targets cover the ARM Cortex-M family of processors which are widely used in -// microcontrollers. Namely, all these processors: -// -// - Cortex-M0 -// - Cortex-M0+ -// - Cortex-M1 -// - Cortex-M3 -// - Cortex-M4(F) -// - Cortex-M7(F) -// - Cortex-M23 -// - Cortex-M33 -// -// We have opted for these instead of one target per processor (e.g., `cortex-m0`, `cortex-m3`, -// etc) because the differences between some processors like the cortex-m0 and cortex-m1 are almost -// nonexistent from the POV of codegen so it doesn't make sense to have separate targets for them. -// And if differences exist between two processors under the same target, rustc flags can be used to -// optimize for one processor or the other. -// -// Also, we have not chosen a single target (`arm-none-eabi`) like GCC does because this makes -// difficult to integrate Rust code and C code. Targeting the Cortex-M4 requires different gcc flags -// than the ones you would use for the Cortex-M0 and with a single target it'd be impossible to -// differentiate one processor from the other. -// -// About arm vs thumb in the name. The Cortex-M devices only support the Thumb instruction set, -// which is more compact (higher code density), and not the ARM instruction set. That's why LLVM -// triples use thumb instead of arm. We follow suit because having thumb in the name let us -// differentiate these targets from our other `arm(v7)-*-*-gnueabi(hf)` targets in the context of -// build scripts / gcc flags. +// These are the baseline settings for 32-bit bare-metal Arm targets using the EABI or EABIHF ABI. use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, PanicStrategy, RelocModel, TargetOptions}; diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs index ca1c9649ee4d..9e7ff620fea4 100644 --- a/compiler/rustc_target/src/spec/base/mod.rs +++ b/compiler/rustc_target/src/spec/base/mod.rs @@ -1,6 +1,7 @@ pub(crate) mod aix; pub(crate) mod android; pub mod apple; +pub(crate) mod arm_none; pub(crate) mod avr; pub(crate) mod bpf; pub(crate) mod cygwin; @@ -31,7 +32,6 @@ pub(crate) mod solaris; pub(crate) mod solid; pub(crate) mod teeos; -pub(crate) mod thumb; pub(crate) mod uefi_msvc; pub(crate) mod unikraft_linux_musl; pub(crate) mod vxworks; diff --git a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs index d6bea6efa6b6..a66c251c2902 100644 --- a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs @@ -9,10 +9,7 @@ //! The default link script is very likely wrong, so you should use //! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script. -use crate::spec::{ - Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, cvs, -}; +use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -29,36 +26,11 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), - linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), - linker: Some("rust-lld".into()), asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",], - // Force-enable 32-bit atomics, which allows the use of atomic load/store only. - // The resulting atomics are ABI incompatible with atomics backed by libatomic. features: "+soft-float,+strict-align".into(), atomic_cas: false, has_thumb_interworking: true, - linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), - linker: Some("rust-lld".into()), - // Because these devices have very little resources having an unwinder is too onerous so we - // default to "abort" because the "unwind" strategy is very rare. - panic_strategy: PanicStrategy::Abort, - // Similarly, one almost always never wants to use relocatable code because of the extra - // costs it involves. - relocation_model: RelocModel::Static, - // When this section is added a volatile load to its start address is also generated. This - // volatile load is a footgun as it can end up loading an invalid memory address, depending - // on how the user set up their linker scripts. This section adds pretty printer for stuff - // like std::Vec, which is not that used in no-std context, so it's best to left it out - // until we figure a way to add the pretty printers without requiring a volatile load cf. - // rust-lang/rust#44993. - emit_debug_gdb_scripts: false, - // LLVM is eager to trash the link register when calling `noreturn` functions, which - // breaks debugging. Preserve LR by default to prevent that from happening. - frame_pointer: FramePointer::Always, - // ARM supports multiple ABIs for enums, the linux one matches the default of 32 here - // but any arm-none or thumb-none target will be defaulted to 8 on GCC. - c_enum_min_bits: Some(8), - ..Default::default() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs index b35b76865ee1..a061b6d346bf 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs @@ -1,8 +1,6 @@ //! Targets the ARMv5TE, with code as `a32` code by default. -use crate::spec::{ - Abi, Arch, FloatAbi, FramePointer, Target, TargetMetadata, TargetOptions, base, cvs, -}; +use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -19,37 +17,11 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), - // extra args passed to the external assembler (assuming `arm-none-eabi-as`): - // * activate t32/a32 interworking - // * use arch ARMv5TE - // * use little-endian asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",], - // minimum extra features, these cannot be disabled via -C features: "+soft-float,+strict-align".into(), atomic_cas: false, has_thumb_interworking: true, - linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), - linker: Some("rust-lld".into()), - // Because these devices have very little resources having an unwinder is too onerous so we - // default to "abort" because the "unwind" strategy is very rare. - panic_strategy: PanicStrategy::Abort, - // Similarly, one almost always never wants to use relocatable code because of the extra - // costs it involves. - relocation_model: RelocModel::Static, - // When this section is added a volatile load to its start address is also generated. This - // volatile load is a footgun as it can end up loading an invalid memory address, depending - // on how the user set up their linker scripts. This section adds pretty printer for stuff - // like std::Vec, which is not that used in no-std context, so it's best to left it out - // until we figure a way to add the pretty printers without requiring a volatile load cf. - // rust-lang/rust#44993. - emit_debug_gdb_scripts: false, - // LLVM is eager to trash the link register when calling `noreturn` functions, which - // breaks debugging. Preserve LR by default to prevent that from happening. - frame_pointer: FramePointer::Always, - // ARM supports multiple ABIs for enums, the linux one matches the default of 32 here - // but any arm-none or thumb-none target will be defaulted to 8 on GCC. - c_enum_min_bits: Some(8), - ..Default::default() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs index 0498c55e9827..7a47417dd9cf 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs @@ -9,10 +9,7 @@ //! The default link script is very likely wrong, so you should use //! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script. -use crate::spec::{ - Abi, Arch, FloatAbi, FramePointer, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, base, cvs, -}; +use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -25,44 +22,15 @@ pub(crate) fn target() -> Target { }, pointer_width: 32, arch: Arch::Arm, - /* Data layout args are '-' separated: - * little endian - * stack is 64-bit aligned (EABI) - * pointers are 32-bit - * i64 must be 64-bit aligned (EABI) - * mangle names with ELF style - * native integers are 32-bit - * All other elements are default - */ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), options: TargetOptions { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), - - // extra args passed to the external assembler (assuming `arm-none-eabi-as`): - // * activate t32/a32 interworking - // * use arch ARMv4T - // * use little-endian asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",], - - // minimum extra features, these cannot be disabled via -C - // Also force-enable 32-bit atomics, which allows the use of atomic load/store only. - // The resulting atomics are ABI incompatible with atomics backed by libatomic. - features: "+soft-float,+strict-align,+atomics-32".into(), - - panic_strategy: PanicStrategy::Abort, - relocation_model: RelocModel::Static, - // suggested from thumb_base, rust-lang/rust#44993. - emit_debug_gdb_scripts: false, - frame_pointer: FramePointer::MayOmit, - - main_needs_argc_argv: false, - - // don't have atomic compare-and-swap + features: "+soft-float,+strict-align".into(), atomic_cas: false, has_thumb_interworking: true, - - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs index a07e9127a36e..771789518865 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs @@ -1,8 +1,6 @@ //! Targets the ARMv5TE, with code as `t32` code by default. -use crate::spec::{ - Abi, Arch, FloatAbi, FramePointer, Target, TargetMetadata, TargetOptions, base, cvs, -}; +use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -15,36 +13,15 @@ pub(crate) fn target() -> Target { }, pointer_width: 32, arch: Arch::Arm, - /* Data layout args are '-' separated: - * little endian - * stack is 64-bit aligned (EABI) - * pointers are 32-bit - * i64 must be 64-bit aligned (EABI) - * mangle names with ELF style - * native integers are 32-bit - * All other elements are default - */ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), - options: TargetOptions { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), - // extra args passed to the external assembler (assuming `arm-none-eabi-as`): - // * activate t32/a32 interworking - // * use arch ARMv5TE - // * use little-endian asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",], - // minimum extra features, these cannot be disabled via -C - // Also force-enable 32-bit atomics, which allows the use of atomic load/store only. - // The resulting atomics are ABI incompatible with atomics backed by libatomic. - features: "+soft-float,+strict-align,+atomics-32".into(), - frame_pointer: FramePointer::MayOmit, - main_needs_argc_argv: false, - // don't have atomic compare-and-swap + features: "+soft-float,+strict-align".into(), atomic_cas: false, has_thumb_interworking: true, - - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs index 836b2ff63a16..cc81cb92be6b 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs @@ -26,7 +26,7 @@ pub(crate) fn target() -> Target { // There are no atomic CAS instructions available in the instruction set of the ARMv6-M // architecture atomic_cas: false, - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs index fa0154d65d68..8b58d2e16eec 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs @@ -25,7 +25,7 @@ pub(crate) fn target() -> Target { // The ARMv6-M doesn't support hardware atomic operations, use atomic builtins instead. features: "+strict-align".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs index 7c1adc932626..17d25a67acbd 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs @@ -27,7 +27,7 @@ pub(crate) fn target() -> Target { // Cortex-A7/A8/A9 with software floating point features: "+soft-float,-neon".into(), max_atomic_width: Some(64), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs index 0e6d5b1f2ea9..a4e17004e7bf 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs @@ -31,7 +31,7 @@ pub(crate) fn target() -> Target { // and NEON SIMD instructions features: "+vfp3,+neon".into(), max_atomic_width: Some(64), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs index 9e0f09b45191..6e6975c01f81 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs @@ -28,7 +28,7 @@ pub(crate) fn target() -> Target { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs index acc31cc42d4a..6a7fe14a26df 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs @@ -36,7 +36,7 @@ pub(crate) fn target() -> Target { // ARMv7-M Architecture Reference Manual - A2.5 The optional floating-point extension features: "+vfp4d16sp".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs index 796206d4ffee..10173273b5d8 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs @@ -30,7 +30,7 @@ pub(crate) fn target() -> Target { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs index f85aef1ab5a6..1f24155a7dab 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs @@ -38,7 +38,7 @@ pub(crate) fn target() -> Target { // ARMv7-M Architecture Reference Manual - A2.5 The optional floating-point extension features: "+vfp4d16sp".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs index 8c5807b1a907..8851f7b63437 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs index 3d3d48748a9c..9f0261c69b3f 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs @@ -21,7 +21,7 @@ pub(crate) fn target() -> Target { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs index 298bad565e48..7426eb9bd5e2 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs @@ -22,7 +22,7 @@ pub(crate) fn target() -> Target { // with +strict-align. features: "+strict-align".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs index 18bafc72553d..a74719ba2f0c 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs @@ -24,7 +24,7 @@ pub(crate) fn target() -> Target { // with +strict-align. features: "+strict-align".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs index 90d7df75d44b..540d4bdee07c 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs @@ -20,7 +20,7 @@ pub(crate) fn target() -> Target { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs index debdb47d507b..2287cce395aa 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs @@ -25,7 +25,7 @@ pub(crate) fn target() -> Target { // and 16 D registers. features: "+fp-armv8d16sp".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs index f5039f13bc09..ec107292d529 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs @@ -22,7 +22,7 @@ pub(crate) fn target() -> Target { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs index 77d23a255278..9ff924b6386b 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs @@ -27,7 +27,7 @@ pub(crate) fn target() -> Target { // and 16 D registers. features: "+fp-armv8d16sp".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 4cf95a04465a..3da3571c2718 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -54,8 +54,8 @@ - [aarch64_be-unknown-linux-musl](platform-support/aarch64_be-unknown-linux-musl.md) - [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md) - [arm-none-eabi](platform-support/arm-none-eabi.md) - - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md) - - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md) + - [{arm,thumb}v4t-none-eabi](platform-support/armv4t-none-eabi.md) + - [{arm,thumb}v5te-none-eabi](platform-support/armv5te-none-eabi.md) - [armv7a-none-eabi{,hf}](platform-support/armv7a-none-eabi.md) - [armv7r-none-eabi{,hf}](platform-support/armv7r-none-eabi.md) - [armebv7r-none-eabi{,hf}](platform-support/armebv7r-none-eabi.md) diff --git a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md index c6d88762fb1b..e5840be66230 100644 --- a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md @@ -8,7 +8,8 @@ group, and all the information there applies. Both of these targets can be used on the Game Boy Advance (GBA), among other things. On the GBA, one should usually use the `thumb` target to get the best -overall performance. +overall performance. Note that this architecture only supports the old +Thumb-1 instruction set, not the later Thumb-2 instruction set. ## Target Maintainers diff --git a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md index e9f34d4ede8a..10a69143bff6 100644 --- a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md @@ -4,10 +4,12 @@ * **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for any cpu in the Armv5TE architecture family, supporting -ARM/Thumb code interworking (aka `A32`/`T32`), with `A32` code as the default code -generation. +ARM/Thumb code interworking (aka `Arm`/`Thumb`), with `Arm` code as the +default code generation. -The `thumbv5te-none-eabi` target is the same as this one, but the instruction set defaults to `T32`. +The `thumbv5te-none-eabi` target is the same as this one, but the instruction +set defaults to `Thumb`. Note that this architecture only supports the old +Thumb-1 instruction set, not the later Thumb-2 instruction set. See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all `arm-none-eabi` targets. From 99a393444cdae5fbf891008aed98f04d3f95b60c Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Sun, 23 Nov 2025 18:29:59 +0000 Subject: [PATCH 080/585] Set max-atomic-width for armv4 and armv5 to zero, to disable atomics --- compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs | 1 + compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs | 1 + compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs | 1 + compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs | 1 + 4 files changed, 4 insertions(+) diff --git a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs index a66c251c2902..fc66a2fa8f9e 100644 --- a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs @@ -29,6 +29,7 @@ pub(crate) fn target() -> Target { asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",], features: "+soft-float,+strict-align".into(), atomic_cas: false, + max_atomic_width: Some(0), has_thumb_interworking: true, ..base::arm_none::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs index a061b6d346bf..8089e9a7a064 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs @@ -20,6 +20,7 @@ pub(crate) fn target() -> Target { asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",], features: "+soft-float,+strict-align".into(), atomic_cas: false, + max_atomic_width: Some(0), has_thumb_interworking: true, ..base::arm_none::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs index 7a47417dd9cf..50eccbed3ac1 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs @@ -29,6 +29,7 @@ pub(crate) fn target() -> Target { asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",], features: "+soft-float,+strict-align".into(), atomic_cas: false, + max_atomic_width: Some(0), has_thumb_interworking: true, ..base::arm_none::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs index 771789518865..6acb03e3b296 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs @@ -20,6 +20,7 @@ pub(crate) fn target() -> Target { asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",], features: "+soft-float,+strict-align".into(), atomic_cas: false, + max_atomic_width: Some(0), has_thumb_interworking: true, ..base::arm_none::opts() }, From 120a464d260dabdb4d745858809f73380f309a52 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Sun, 23 Nov 2025 21:52:00 +0000 Subject: [PATCH 081/585] Revise the notes about atomics on Arm. --- library/core/src/sync/atomic.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 0c5552a0b81c..0601019abbd5 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -130,16 +130,18 @@ //! //! * PowerPC and MIPS platforms with 32-bit pointers do not have `AtomicU64` or //! `AtomicI64` types. -//! * ARM platforms like `armv5te` that aren't for Linux only provide `load` -//! and `store` operations, and do not support Compare and Swap (CAS) -//! operations, such as `swap`, `fetch_add`, etc. Additionally on Linux, -//! these CAS operations are implemented via [operating system support], which -//! may come with a performance penalty. -//! * ARM targets with `thumbv6m` only provide `load` and `store` operations, -//! and do not support Compare and Swap (CAS) operations, such as `swap`, -//! `fetch_add`, etc. +//! * Legacy ARM platforms like ARMv4T and ARMv5TE have very limited hardware +//! support for atomics. The bare-metal targets disable this module +//! entirely, but the Linux targets [use the kernel] to assist (which comes +//! with a performance penalty). It's not until ARMv6K onwards that ARM CPUs +//! have support for load/store and Compare and Swap (CAS) atomics in hardware. +//! * ARMv6-M and ARMv8-M baseline targets (`thumbv6m-*` and +//! `thumbv8m.base-*`) only provide `load` and `store` operations, and do +//! not support Compare and Swap (CAS) operations, such as `swap`, +//! `fetch_add`, etc. Full CAS support is available on ARMv7-M and ARMv8-M +//! Mainline (`thumbv7m-*`, `thumbv7em*` and `thumbv8m.main-*`). //! -//! [operating system support]: https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt +//! [use the kernel]: https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt //! //! Note that future platforms may be added that also do not have support for //! some atomic operations. Maximally portable code will want to be careful From d60e7cf94b514897c4185ebab08438af281a464b Mon Sep 17 00:00:00 2001 From: chenx97 Date: Thu, 30 Oct 2025 20:47:36 +0800 Subject: [PATCH 082/585] callconv: adapt mips padding logic to mips64 MIPS64 needs to put a padding argument before an aggregate argument when this argument is in an odd-number position, starting from 0, and has an alignment of 16 bytes or higher, e.g. `void foo(int a, max_align_t b);` is the same as `void foo(int a, long _padding, max_align_t b);` This fix uses an i32 padding, but it should work just fine because i32 is aligned like i64 for arguments. --- compiler/rustc_target/src/callconv/mips64.rs | 115 ++++++++++--------- 1 file changed, 62 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs index a4e94ce81605..4fafa7b3a5e2 100644 --- a/compiler/rustc_target/src/callconv/mips64.rs +++ b/compiler/rustc_target/src/callconv/mips64.rs @@ -34,7 +34,7 @@ fn float_reg<'a, Ty, C>(cx: &C, ret: &ArgAbi<'a, Ty>, i: usize) -> Option } } -fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>) +fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, offset: &mut Size) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, @@ -70,77 +70,82 @@ fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>) ret.cast_to(Uniform::new(Reg::i64(), size)); } else { ret.make_indirect(); + *offset += cx.data_layout().pointer_size(); } } -fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, offset: &mut Size) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { - if !arg.layout.is_aggregate() { - extend_integer_width_mips(arg, 64); - return; - } - if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { - arg.make_indirect(); - return; - } - let dl = cx.data_layout(); let size = arg.layout.size; let mut prefix = [None; 8]; let mut prefix_index = 0; - match arg.layout.fields { - FieldsShape::Primitive => unreachable!(), - FieldsShape::Array { .. } => { - // Arrays are passed indirectly - arg.make_indirect(); - return; - } - FieldsShape::Union(_) => { - // Unions and are always treated as a series of 64-bit integer chunks - } - FieldsShape::Arbitrary { .. } => { - // Structures are split up into a series of 64-bit integer chunks, but any aligned - // doubles not part of another aggregate are passed as floats. - let mut last_offset = Size::ZERO; + // Detect need for padding + let align = Ord::clamp(arg.layout.align.abi, dl.i64_align, dl.i128_align); + let pad_i32 = !offset.is_aligned(align); - for i in 0..arg.layout.fields.count() { - let field = arg.layout.field(cx, i); - let offset = arg.layout.fields.offset(i); + if !arg.layout.is_aggregate() { + extend_integer_width_mips(arg, 64); + } else if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + } else { + match arg.layout.fields { + FieldsShape::Primitive => unreachable!(), + FieldsShape::Array { .. } => { + // Arrays are passed indirectly + arg.make_indirect(); + } + FieldsShape::Union(_) => { + // Unions and are always treated as a series of 64-bit integer chunks + } + FieldsShape::Arbitrary { .. } => { + // Structures are split up into a series of 64-bit integer chunks, but any aligned + // doubles not part of another aggregate are passed as floats. + let mut last_offset = Size::ZERO; - // We only care about aligned doubles - if let BackendRepr::Scalar(scalar) = field.backend_repr { - if scalar.primitive() == Primitive::Float(Float::F64) { - if offset.is_aligned(dl.f64_align) { - // Insert enough integers to cover [last_offset, offset) - assert!(last_offset.is_aligned(dl.f64_align)); - for _ in 0..((offset - last_offset).bits() / 64) - .min((prefix.len() - prefix_index) as u64) - { - prefix[prefix_index] = Some(Reg::i64()); + for i in 0..arg.layout.fields.count() { + let field = arg.layout.field(cx, i); + let offset = arg.layout.fields.offset(i); + + // We only care about aligned doubles + if let BackendRepr::Scalar(scalar) = field.backend_repr { + if scalar.primitive() == Primitive::Float(Float::F64) { + if offset.is_aligned(dl.f64_align) { + // Insert enough integers to cover [last_offset, offset) + assert!(last_offset.is_aligned(dl.f64_align)); + for _ in 0..((offset - last_offset).bits() / 64) + .min((prefix.len() - prefix_index) as u64) + { + prefix[prefix_index] = Some(Reg::i64()); + prefix_index += 1; + } + + if prefix_index == prefix.len() { + break; + } + + prefix[prefix_index] = Some(Reg::f64()); prefix_index += 1; + last_offset = offset + Reg::f64().size; } - - if prefix_index == prefix.len() { - break; - } - - prefix[prefix_index] = Some(Reg::f64()); - prefix_index += 1; - last_offset = offset + Reg::f64().size; } } } } - } - }; + }; - // Extract first 8 chunks as the prefix - let rest_size = size - Size::from_bytes(8) * prefix_index as u64; - arg.cast_to(CastTarget::prefixed(prefix, Uniform::new(Reg::i64(), rest_size))); + // Extract first 8 chunks as the prefix + let rest_size = size - Size::from_bytes(8) * prefix_index as u64; + arg.cast_to_and_pad_i32( + CastTarget::prefixed(prefix, Uniform::new(Reg::i64(), rest_size)), + pad_i32, + ); + } + *offset = offset.align_to(align) + size.align_to(align); } pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) @@ -148,14 +153,18 @@ pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { + // mips64 argument passing is also affected by the alignment of aggregates. + // see mips.rs for how the offset is used + let mut offset = Size::ZERO; + if !fn_abi.ret.is_ignore() && fn_abi.ret.layout.is_sized() { - classify_ret(cx, &mut fn_abi.ret); + classify_ret(cx, &mut fn_abi.ret, &mut offset); } for arg in fn_abi.args.iter_mut() { if arg.is_ignore() || !arg.layout.is_sized() { continue; } - classify_arg(cx, arg); + classify_arg(cx, arg, &mut offset); } } From 5f623260818ba453bd969bf3f259e1e1e506dd45 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 24 Nov 2025 04:18:20 +0000 Subject: [PATCH 083/585] Prepare for merging from rust-lang/rust This updates the rust-version file to d3e1ccdf40ae7b7a6dc81edc073d80dad7b66f75. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 8c841aac8eb6..08324790e311 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -cc328c12382f05d8ddf6ffc8139deb7985270ad8 +d3e1ccdf40ae7b7a6dc81edc073d80dad7b66f75 From 06658ab84bbd4f835830808f78eb117d8f57efa0 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 24 Nov 2025 12:17:11 +0100 Subject: [PATCH 084/585] cmse: do not calculate the layout of a type with infer types --- .../src/hir_ty_lowering/cmse.rs | 10 ++++++ tests/crashes/130104.rs | 6 ---- .../cmse-nonsecure-call/infer.rs | 34 ++++++++++++++++++ .../cmse-nonsecure-call/infer.stderr | 27 ++++++++++++++ .../cmse-nonsecure-entry/infer.rs | 36 +++++++++++++++++++ .../cmse-nonsecure-entry/infer.stderr | 32 +++++++++++++++++ 6 files changed, 139 insertions(+), 6 deletions(-) delete mode 100644 tests/crashes/130104.rs create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.rs create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.stderr create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.rs create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index f8af6888923c..81bdfc1705a1 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -86,6 +86,11 @@ fn is_valid_cmse_inputs<'tcx>( let fn_sig = tcx.erase_and_anonymize_regions(fn_sig); for (ty, hir_ty) in fn_sig.inputs().iter().zip(fn_decl.inputs) { + if ty.has_infer_types() { + let err = LayoutError::Unknown(*ty); + return Err((hir_ty.span, tcx.arena.alloc(err))); + } + let layout = tcx .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty)) .map_err(|e| (hir_ty.span, e))?; @@ -138,6 +143,11 @@ fn is_valid_cmse_output<'tcx>( return Ok(()); } + if return_type.has_infer_types() { + let err = LayoutError::Unknown(return_type); + return Err(tcx.arena.alloc(err)); + } + let typing_env = ty::TypingEnv::fully_monomorphized(); let layout = tcx.layout_of(typing_env.as_query_input(return_type))?; diff --git a/tests/crashes/130104.rs b/tests/crashes/130104.rs deleted file mode 100644 index b961108c9233..000000000000 --- a/tests/crashes/130104.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: rust-lang/rust#130104 - -fn main() { - let non_secure_function = - core::mem::transmute:: _, extern "cmse-nonsecure-call" fn() -> _>; -} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.rs new file mode 100644 index 000000000000..3452dc268e59 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.rs @@ -0,0 +1,34 @@ +//@ add-minicore +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ needs-llvm-components: arm +#![feature(abi_cmse_nonsecure_call, no_core, lang_items)] +#![no_core] + +// Infer variables cause panics in layout generation, so the argument/return type is checked for +// whether it contains an infer var, and `LayoutError::Unknown` is emitted if so. +// +// See https://github.com/rust-lang/rust/issues/130104. + +extern crate minicore; +use minicore::*; + +fn infer_1() { + let _ = mem::transmute:: _, extern "cmse-nonsecure-call" fn() -> _>; + //~^ ERROR type annotations needed +} + +fn infer_2() { + let _ = mem::transmute:: (i32, _), extern "cmse-nonsecure-call" fn() -> (i32, _)>; + //~^ ERROR type annotations needed +} + +fn infer_3() { + let _ = mem::transmute:: (), extern "cmse-nonsecure-call" fn(_: _) -> ()>; + //~^ ERROR type annotations needed +} + +fn infer_4() { + let _ = + mem::transmute:: (), extern "cmse-nonsecure-call" fn(_: (i32, _)) -> ()>; + //~^ ERROR type annotations needed +} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.stderr new file mode 100644 index 000000000000..aab314c1ff25 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.stderr @@ -0,0 +1,27 @@ +error[E0282]: type annotations needed + --> $DIR/infer.rs:16:13 + | +LL | let _ = mem::transmute:: _, extern "cmse-nonsecure-call" fn() -> _>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error[E0282]: type annotations needed + --> $DIR/infer.rs:21:13 + | +LL | let _ = mem::transmute:: (i32, _), extern "cmse-nonsecure-call" fn() -> (i32, _)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error[E0282]: type annotations needed + --> $DIR/infer.rs:26:13 + | +LL | let _ = mem::transmute:: (), extern "cmse-nonsecure-call" fn(_: _) -> ()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error[E0282]: type annotations needed + --> $DIR/infer.rs:32:9 + | +LL | mem::transmute:: (), extern "cmse-nonsecure-call" fn(_: (i32, _)) -> ()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.rs new file mode 100644 index 000000000000..75a08ff40356 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.rs @@ -0,0 +1,36 @@ +//@ add-minicore +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ needs-llvm-components: arm +#![feature(cmse_nonsecure_entry, no_core, lang_items)] +#![no_core] + +// Infer variables cause panics in layout generation, so the argument/return type is checked for +// whether it contains an infer var, and `LayoutError::Unknown` is emitted if so. +// +// See https://github.com/rust-lang/rust/issues/130104. + +extern crate minicore; +use minicore::*; + +fn infer_1() { + let _ = mem::transmute:: _, extern "cmse-nonsecure-entry" fn() -> _>; + //~^ ERROR type annotations needed +} + +fn infer_2() { + let _ = mem::transmute:: (i32, _), extern "cmse-nonsecure-entry" fn() -> (i32, _)>; + //~^ ERROR type annotations needed +} + +fn infer_3() { + let _ = mem::transmute:: (), extern "cmse-nonsecure-entry" fn(_: _) -> ()>; + //~^ ERROR type annotations needed +} + +fn infer_4() { + let _ = mem::transmute::< + //~^ ERROR type annotations needed + fn(_: (i32, _)) -> (), + extern "cmse-nonsecure-entry" fn(_: (i32, _)) -> (), + >; +} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.stderr new file mode 100644 index 000000000000..4243771c3e67 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.stderr @@ -0,0 +1,32 @@ +error[E0282]: type annotations needed + --> $DIR/infer.rs:16:13 + | +LL | let _ = mem::transmute:: _, extern "cmse-nonsecure-entry" fn() -> _>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error[E0282]: type annotations needed + --> $DIR/infer.rs:21:13 + | +LL | let _ = mem::transmute:: (i32, _), extern "cmse-nonsecure-entry" fn() -> (i32, _)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error[E0282]: type annotations needed + --> $DIR/infer.rs:26:13 + | +LL | let _ = mem::transmute:: (), extern "cmse-nonsecure-entry" fn(_: _) -> ()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error[E0282]: type annotations needed + --> $DIR/infer.rs:31:13 + | +LL | let _ = mem::transmute::< + | _____________^ +LL | | +LL | | fn(_: (i32, _)) -> (), +LL | | extern "cmse-nonsecure-entry" fn(_: (i32, _)) -> (), +LL | | >; + | |_____^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0282`. From 6a11d0be8996ac56aa6b3d6905bbc99a1a0ecca5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:54:22 +0000 Subject: [PATCH 085/585] Don't leak sysroot crates through dependencies Previously if a dependency of the current crate depended on a sysroot crate, then extern crate would in the current crate would pick the first loaded version of said sysroot crate even in case of an ambiguity. This is surprising and brittle. For -Ldependency= we already blocked this, but the fix didn't account for sysroot crates. --- compiler/rustc_metadata/src/creader.rs | 29 ++++---------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 4e2e1e21ec6d..85fa8cda2229 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -519,7 +519,6 @@ fn existing_match( externs: &Externs, name: Symbol, hash: Option, - kind: PathKind, ) -> Option { for (cnum, data) in self.iter_crate_data() { if data.name() != name { @@ -561,27 +560,9 @@ fn existing_match( continue; } - // Alright, so we've gotten this far which means that `data` has the - // right name, we don't have a hash, and we don't have a --extern - // pointing for ourselves. We're still not quite yet done because we - // have to make sure that this crate was found in the crate lookup - // path (this is a top-level dependency) as we don't want to - // implicitly load anything inside the dependency lookup path. - let prev_kind = source - .dylib - .as_ref() - .or(source.rlib.as_ref()) - .or(source.rmeta.as_ref()) - .expect("No sources for crate") - .1; - if kind.matches(prev_kind) { - return Some(cnum); - } else { - debug!( - "failed to load existing crate {}; kind {:?} did not match prev_kind {:?}", - name, kind, prev_kind - ); - } + // While the crate name matched, no --extern crate_name=path matched. It is possible + // that we have already loaded the target crate, but if that happens CStore::load will + // indicate so and we gracefully handle this, just potentially wasting a bit of time. } None @@ -818,9 +799,7 @@ fn maybe_resolve_crate<'b, 'tcx>( let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate }; let private_dep = origin.private_dep(); - let result = if let Some(cnum) = - self.existing_match(&tcx.sess.opts.externs, name, hash, path_kind) - { + let result = if let Some(cnum) = self.existing_match(&tcx.sess.opts.externs, name, hash) { (LoadResult::Previous(cnum), None) } else { info!("falling back to a load"); From 7593f9d70612de27d8db97260ad247a8fa675a82 Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 25 Nov 2025 01:18:01 +0900 Subject: [PATCH 086/585] Fix link to README in ui test documentation Updated link from SUMMARY.md to README.md in ui.md --- src/doc/rustc-dev-guide/src/tests/ui.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 497e6109446e..759029e67132 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -12,7 +12,7 @@ the resulting program](#controlling-passfail-expectations) to verify its behavior. For a survey of each subdirectory's purpose under `tests/ui`, consult the -[SUMMARY.md](https://github.com/rust-lang/rust/tree/HEAD/tests/ui/SUMMARY.md). +[README.md](https://github.com/rust-lang/rust/tree/HEAD/tests/ui/README.md). This is useful if you write a new test, and are looking for a category to place it in. From 4aa5ee99c848e1da81ddac872d9c82dc3faa6943 Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 25 Nov 2025 13:42:45 +0900 Subject: [PATCH 087/585] Update contributing.md with Rust Book reference Added a reference to The Rust Book for more information on Rust's release channels. --- src/doc/rustc-dev-guide/src/contributing.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 8c764c31dbfa..4476ed842dae 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -52,6 +52,7 @@ the CI to build and test their PR (e.g. when developing on a slow machine). Rust has strong backwards-compatibility guarantees. Thus, new features can't just be implemented directly in stable Rust. Instead, we have 3 release channels: stable, beta, and nightly. +See [The Rust Book] for more details on Rust’s train release model. - **Stable**: this is the latest stable release for general usage. - **Beta**: this is the next release (will be stable within 6 weeks). @@ -62,6 +63,8 @@ Instead, we have 3 release channels: stable, beta, and nightly. See [this chapter on implementing new features](./implementing_new_features.md) for more information. +[The Rust Book]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html + ### Breaking changes Breaking changes have a [dedicated section][Breaking Changes] in the dev-guide. From 8f21e24bfeec2e43928e225b5b45575020599e36 Mon Sep 17 00:00:00 2001 From: dvermd <315743+dvermd@users.noreply.github.com> Date: Sun, 23 Nov 2025 09:59:58 +0100 Subject: [PATCH 088/585] factorize count leading and trailing zeros code --- src/intrinsic/mod.rs | 298 ++++++++++++++++++------------------------- 1 file changed, 123 insertions(+), 175 deletions(-) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index b1ce33da3a7b..f50d096e2e80 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -848,8 +848,8 @@ fn bit_reverse(&mut self, width: u64, value: RValue<'gcc>) -> RValue<'gcc> { self.gcc_int_cast(result, result_type) } - fn count_leading_zeroes(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { - // if arg is 0, early return 0, else call count_leading_zeroes_nonzero to compute leading zeros + fn count_zeroes(&mut self, width: u64, arg: RValue<'gcc>, count_leading: bool) -> RValue<'gcc> { + // if arg is 0, early return 0, else call count_leading_zeroes_nonzero or count_trailing_zeroes_nonzero let func = self.current_func(); let then_block = func.new_block("then"); let else_block = func.new_block("else"); @@ -864,11 +864,15 @@ fn count_leading_zeroes(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc then_block.add_assignment(None, result, zero_result); then_block.end_with_jump(None, after_block); - // NOTE: since jumps were added in a place count_leading_zeroes_nonzero() does not expect, + // NOTE: since jumps were added in a place count_xxxxing_zeroes_nonzero() does not expect, // the current block in the state need to be updated. self.switch_to_block(else_block); - let zeros = self.count_leading_zeroes_nonzero(width, arg); + let zeros = if count_leading { + self.count_leading_zeroes_nonzero(width, arg) + } else { + self.count_trailing_zeroes_nonzero(width, arg) + }; self.llbb().add_assignment(None, result, zeros); self.llbb().end_with_jump(None, after_block); @@ -879,7 +883,30 @@ fn count_leading_zeroes(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc result.to_rvalue() } - fn count_leading_zeroes_nonzero(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + fn count_zeroes_nonzero( + &mut self, + width: u64, + arg: RValue<'gcc>, + count_leading: bool, + ) -> RValue<'gcc> { + // Pre-condition: arg is guaranteed to not be 0 by caller + fn use_builtin_function<'a, 'gcc, 'tcx>( + builder: &mut Builder<'a, 'gcc, 'tcx>, + builtin: &str, + arg: RValue<'gcc>, + arg_type: gccjit::Type<'gcc>, + expected_type: gccjit::Type<'gcc>, + ) -> RValue<'gcc> { + let arg = if arg_type != expected_type { + builder.context.new_cast(builder.location, arg, expected_type) + } else { + arg + }; + let builtin = builder.context.get_builtin_function(builtin); + let res = builder.context.new_call(builder.location, builtin, &[arg]); + builder.context.new_cast(builder.location, res, builder.u32_type) + } + // TODO(antoyo): use width? let result_type = self.u32_type; let mut arg_type = arg.get_type(); @@ -889,186 +916,107 @@ fn count_leading_zeroes_nonzero(&mut self, width: u64, arg: RValue<'gcc>) -> RVa } else { arg }; - let count_leading_zeroes = - // TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here - // instead of using is_uint(). - if arg_type.is_uchar(self.cx) || arg_type.is_ushort(self.cx) || arg_type.is_uint(self.cx) { - "__builtin_clz" - } - else if arg_type.is_ulong(self.cx) { - "__builtin_clzl" - } - else if arg_type.is_ulonglong(self.cx) { - "__builtin_clzll" - } - else if width == 128 { - // arg is guaranteed to not be 0, so either its 64 high or 64 low bits are not 0 - // __buildin_clzll is UB when called with 0, so call it on the 64 high bits if they are not 0, - // else call it on the 64 low bits and add 64. In the else case, 64 low bits can't be 0 - // because arg is not 0. + // TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here + // instead of using is_uint(). + if arg_type.is_uchar(self.cx) || arg_type.is_ushort(self.cx) || arg_type.is_uint(self.cx) { + let builtin = if count_leading { "__builtin_clz" } else { "__builtin_ctz" }; + use_builtin_function(self, builtin, arg, arg_type, self.cx.uint_type) + } else if arg_type.is_ulong(self.cx) { + let builtin = if count_leading { "__builtin_clzl" } else { "__builtin_ctzl" }; + use_builtin_function(self, builtin, arg, arg_type, self.cx.uint_type) + } else if arg_type.is_ulonglong(self.cx) { + let builtin = if count_leading { "__builtin_clzll" } else { "__builtin_ctzll" }; + use_builtin_function(self, builtin, arg, arg_type, self.cx.uint_type) + } else if width == 128 { + // arg is guaranteed to not be 0, so either its 64 high or 64 low bits are not 0 + // __buildin_clzll is UB when called with 0, so call it on the 64 high bits if they are not 0, + // else call it on the 64 low bits and add 64. In the else case, 64 low bits can't be 0 + // because arg is not 0. + // __buildin_ctzll is UB when called with 0, so call it on the 64 low bits if they are not 0, + // else call it on the 64 high bits and add 64. In the else case, 64 high bits can't be 0 + // because arg is not 0. - let result = self.current_func() - .new_local(None, result_type, "count_leading_zeroes_results"); + let result = self.current_func().new_local(None, result_type, "count_zeroes_results"); - let ctlz_then_block = self.current_func().new_block("ctlz_then"); - let ctlz_else_block = self.current_func().new_block("ctlz_else"); - let ctlz_after_block = self.current_func().new_block("ctlz_after") - ; - let sixty_four = self.const_uint(arg_type, 64); - let shift = self.lshr(arg, sixty_four); - let high = self.gcc_int_cast(shift, self.u64_type); + let cz_then_block = self.current_func().new_block("cz_then"); + let cz_else_block = self.current_func().new_block("cz_else"); + let cz_after_block = self.current_func().new_block("cz_after"); - let clzll = self.context.get_builtin_function("__builtin_clzll"); + let low = self.gcc_int_cast(arg, self.u64_type); + let sixty_four = self.const_uint(arg_type, 64); + let shift = self.lshr(arg, sixty_four); + let high = self.gcc_int_cast(shift, self.u64_type); - let zero_hi = self.const_uint(high.get_type(), 0); - let cond = self.gcc_icmp(IntPredicate::IntNE, high, zero_hi); - self.llbb().end_with_conditional(self.location, cond, ctlz_then_block, ctlz_else_block); - self.switch_to_block(ctlz_then_block); - - let result_128 = - self.gcc_int_cast(self.context.new_call(None, clzll, &[high]), result_type); - - ctlz_then_block.add_assignment(self.location, result, result_128); - ctlz_then_block.end_with_jump(self.location, ctlz_after_block); - - self.switch_to_block(ctlz_else_block); - let low = self.gcc_int_cast(arg, self.u64_type); - let low_leading_zeroes = - self.gcc_int_cast(self.context.new_call(None, clzll, &[low]), result_type); - let sixty_four_result_type = self.const_uint(result_type, 64); - let result_128 = self.add(low_leading_zeroes, sixty_four_result_type); - ctlz_else_block.add_assignment(self.location, result, result_128); - ctlz_else_block.end_with_jump(self.location, ctlz_after_block); - self.switch_to_block(ctlz_after_block); - return result.to_rvalue(); - } - else { - let count_leading_zeroes = self.context.get_builtin_function("__builtin_clzll"); - let arg = self.context.new_cast(self.location, arg, self.ulonglong_type); - let diff = self.ulonglong_type.get_size() as i64 - arg_type.get_size() as i64; - let diff = self.context.new_rvalue_from_long(self.int_type, diff * 8); - let res = self.context.new_call(self.location, count_leading_zeroes, &[arg]) - diff; - return self.context.new_cast(self.location, res, result_type); + let (first, second, builtin) = if count_leading { + (low, high, self.context.get_builtin_function("__builtin_clzll")) + } else { + (high, low, self.context.get_builtin_function("__builtin_ctzll")) }; - let count_leading_zeroes = self.context.get_builtin_function(count_leading_zeroes); - let res = self.context.new_call(self.location, count_leading_zeroes, &[arg]); - self.context.new_cast(self.location, res, result_type) + + let zero_64 = self.const_uint(self.u64_type, 0); + let cond = self.gcc_icmp(IntPredicate::IntNE, second, zero_64); + self.llbb().end_with_conditional(self.location, cond, cz_then_block, cz_else_block); + self.switch_to_block(cz_then_block); + + let result_128 = + self.gcc_int_cast(self.context.new_call(None, builtin, &[second]), result_type); + + cz_then_block.add_assignment(self.location, result, result_128); + cz_then_block.end_with_jump(self.location, cz_after_block); + + self.switch_to_block(cz_else_block); + let count_more_zeroes = + self.gcc_int_cast(self.context.new_call(None, builtin, &[first]), result_type); + let sixty_four_result_type = self.const_uint(result_type, 64); + let count_result_type = self.add(count_more_zeroes, sixty_four_result_type); + cz_else_block.add_assignment(self.location, result, count_result_type); + cz_else_block.end_with_jump(self.location, cz_after_block); + self.switch_to_block(cz_after_block); + result.to_rvalue() + } else { + let byte_diff = self.ulonglong_type.get_size() as i64 - arg_type.get_size() as i64; + let diff = self.context.new_rvalue_from_long(self.int_type, byte_diff * 8); + let ull_arg = self.context.new_cast(self.location, arg, self.ulonglong_type); + + let res = if count_leading { + let count_leading_zeroes = self.context.get_builtin_function("__builtin_clzll"); + self.context.new_call(self.location, count_leading_zeroes, &[ull_arg]) - diff + } else { + let count_trailing_zeroes = self.context.get_builtin_function("__builtin_ctzll"); + let mask = self.context.new_rvalue_from_long(arg_type, -1); // To get the value with all bits set. + let masked = mask + & self.context.new_unary_op( + self.location, + UnaryOp::BitwiseNegate, + arg_type, + arg, + ); + let cond = + self.context.new_comparison(self.location, ComparisonOp::Equals, masked, mask); + let diff = diff * self.context.new_cast(self.location, cond, self.int_type); + + self.context.new_call(self.location, count_trailing_zeroes, &[ull_arg]) - diff + }; + self.context.new_cast(self.location, res, result_type) + } + } + + fn count_leading_zeroes(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + self.count_zeroes(width, arg, true) + } + + fn count_leading_zeroes_nonzero(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + // Pre-condition: arg is guaranteed to not be 0 by caller, else count_leading_zeros should be used + self.count_zeroes_nonzero(width, arg, true) } fn count_trailing_zeroes(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { - // if arg is 0, early return width, else call count_trailing_zeroes_nonzero to compute trailing zeros - let func = self.current_func(); - let then_block = func.new_block("then"); - let else_block = func.new_block("else"); - let after_block = func.new_block("after"); - - let result = func.new_local(None, self.u32_type, "zeros"); - let zero = self.cx.gcc_zero(arg.get_type()); - let cond = self.gcc_icmp(IntPredicate::IntEQ, arg, zero); - self.llbb().end_with_conditional(None, cond, then_block, else_block); - - let zero_result = self.cx.gcc_uint(self.u32_type, width); - then_block.add_assignment(None, result, zero_result); - then_block.end_with_jump(None, after_block); - - // NOTE: since jumps were added in a place count_trailing_zeroes_nonzero() does not expect, - // the current block in the state need to be updated. - self.switch_to_block(else_block); - - let zeros = self.count_trailing_zeroes_nonzero(width, arg); - self.llbb().add_assignment(None, result, zeros); - self.llbb().end_with_jump(None, after_block); - - // NOTE: since jumps were added in a place rustc does not - // expect, the current block in the state need to be updated. - self.switch_to_block(after_block); - - result.to_rvalue() + self.count_zeroes(width, arg, false) } - fn count_trailing_zeroes_nonzero(&mut self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { - let result_type = self.u32_type; - let mut arg_type = arg.get_type(); - let arg = if arg_type.is_signed(self.cx) { - arg_type = arg_type.to_unsigned(self.cx); - self.gcc_int_cast(arg, arg_type) - } else { - arg - }; - let (count_trailing_zeroes, expected_type) = - // TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here - // instead of using is_uint(). - if arg_type.is_uchar(self.cx) || arg_type.is_ushort(self.cx) || arg_type.is_uint(self.cx) { - // NOTE: we don't need to & 0xFF for uchar because the result is undefined on zero. - ("__builtin_ctz", self.cx.uint_type) - } - else if arg_type.is_ulong(self.cx) { - ("__builtin_ctzl", self.cx.ulong_type) - } - else if arg_type.is_ulonglong(self.cx) { - ("__builtin_ctzll", self.cx.ulonglong_type) - } - else if arg_type.is_u128(self.cx) { - // arg is guaranteed to no be 0, so either its 64 high or 64 low bits are not 0 - // __buildin_ctzll is UB when called with 0, so call it on the 64 low bits if they are not 0, - // else call it on the 64 high bits and add 64. In the else case, 64 high bits can't be 0 - // because arg is not 0. - - let result = self.current_func() - .new_local(None, result_type, "count_trailing_zeroes_results"); - - let ctlz_then_block = self.current_func().new_block("cttz_then"); - let ctlz_else_block = self.current_func().new_block("cttz_else"); - let ctlz_after_block = self.current_func().new_block("cttz_after"); - let ctzll = self.context.get_builtin_function("__builtin_ctzll"); - - let low = self.gcc_int_cast(arg, self.u64_type); - let sixty_four = self.const_uint(arg_type, 64); - let shift = self.lshr(arg, sixty_four); - let high = self.gcc_int_cast(shift, self.u64_type); - let zero_low = self.const_uint(low.get_type(), 0); - let cond = self.gcc_icmp(IntPredicate::IntNE, low, zero_low); - self.llbb().end_with_conditional(self.location, cond, ctlz_then_block, ctlz_else_block); - self.switch_to_block(ctlz_then_block); - - let result_128 = - self.gcc_int_cast(self.context.new_call(None, ctzll, &[low]), result_type); - - ctlz_then_block.add_assignment(self.location, result, result_128); - ctlz_then_block.end_with_jump(self.location, ctlz_after_block); - - self.switch_to_block(ctlz_else_block); - let high_trailing_zeroes = - self.gcc_int_cast(self.context.new_call(None, ctzll, &[high]), result_type); - - let sixty_four_result_type = self.const_uint(result_type, 64); - let result_128 = self.add(high_trailing_zeroes, sixty_four_result_type); - ctlz_else_block.add_assignment(self.location, result, result_128); - ctlz_else_block.end_with_jump(self.location, ctlz_after_block); - self.switch_to_block(ctlz_after_block); - return result.to_rvalue(); - } - else { - let count_trailing_zeroes = self.context.get_builtin_function("__builtin_ctzll"); - let arg_size = arg_type.get_size(); - let casted_arg = self.context.new_cast(self.location, arg, self.ulonglong_type); - let byte_diff = self.ulonglong_type.get_size() as i64 - arg_size as i64; - let diff = self.context.new_rvalue_from_long(self.int_type, byte_diff * 8); - let mask = self.context.new_rvalue_from_long(arg_type, -1); // To get the value with all bits set. - let masked = mask & self.context.new_unary_op(self.location, UnaryOp::BitwiseNegate, arg_type, arg); - let cond = self.context.new_comparison(self.location, ComparisonOp::Equals, masked, mask); - let diff = diff * self.context.new_cast(self.location, cond, self.int_type); - let res = self.context.new_call(self.location, count_trailing_zeroes, &[casted_arg]) - diff; - return self.context.new_cast(self.location, res, result_type); - }; - let count_trailing_zeroes = self.context.get_builtin_function(count_trailing_zeroes); - let arg = if arg_type != expected_type { - self.context.new_cast(self.location, arg, expected_type) - } else { - arg - }; - let res = self.context.new_call(self.location, count_trailing_zeroes, &[arg]); - self.context.new_cast(self.location, res, result_type) + fn count_trailing_zeroes_nonzero(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + // Pre-condition: arg is guaranteed to not be 0 by caller, else count_trailing_zeros should be used + self.count_zeroes_nonzero(width, arg, false) } fn pop_count(&mut self, value: RValue<'gcc>) -> RValue<'gcc> { From d7023631df345a927ae0c331cd1a7c0f55bac842 Mon Sep 17 00:00:00 2001 From: dvermd <315743+dvermd@users.noreply.github.com> Date: Mon, 17 Nov 2025 06:01:06 +0100 Subject: [PATCH 089/585] add ctlz and cttz tests --- tests/run/int_intrinsics.rs | 72 +++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tests/run/int_intrinsics.rs diff --git a/tests/run/int_intrinsics.rs b/tests/run/int_intrinsics.rs new file mode 100644 index 000000000000..c3d363c8428b --- /dev/null +++ b/tests/run/int_intrinsics.rs @@ -0,0 +1,72 @@ +// Compiler: +// +// Run-time: +#![feature(core_intrinsics, intrinsics)] +#![no_main] + +use std::intrinsics::black_box; + +#[rustc_intrinsic] +pub const fn ctlz(_x: T) -> u32; + +#[rustc_intrinsic] +pub const fn cttz(_x: T) -> u32; + +#[no_mangle] +extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { + macro_rules! check { + ($func_name:ident, $input:expr, $expected:expr, $res_ident:ident) => {{ + $res_ident += 1; + if $func_name(black_box($input)) != $expected { + return $res_ident; + } + }}; + } + let mut res = 0; + check!(ctlz, 0_u128, 128_u32, res); + check!(ctlz, 1_u128, 127_u32, res); + check!(ctlz, 0x4000_0000_0000_0000_0000_0000_0000_0000_u128, 1_u32, res); + check!(ctlz, 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, 0_u32, res); + check!(cttz, 0_u128, 128_u32, res); + check!(cttz, 1_u128, 0_u32, res); + check!(cttz, 2_u128, 1_u32, res); + check!(cttz, 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, 127_u32, res); + + check!(ctlz, 0_u64, 64_u32, res); + check!(ctlz, 1_u64, 63_u32, res); + check!(ctlz, 0x4000_0000_0000_0000_u64, 1_u32, res); + check!(ctlz, 0x8000_0000_0000_0000_u64, 0_u32, res); + check!(cttz, 0_u64, 64_u32, res); + check!(cttz, 1_u64, 0_u32, res); + check!(cttz, 2_u64, 1_u32, res); + check!(cttz, 0x8000_0000_0000_0000_u64, 63_u32, res); + + check!(ctlz, 0_u32, 32_u32, res); + check!(ctlz, 1_u32, 31_u32, res); + check!(ctlz, 0x4000_0000_u32, 1_u32, res); + check!(ctlz, 0x8000_0000_u32, 0_u32, res); + check!(cttz, 0_u32, 32_u32, res); + check!(cttz, 1_u32, 0_u32, res); + check!(cttz, 2_u32, 1_u32, res); + check!(cttz, 0x8000_0000_u32, 31_u32, res); + + check!(ctlz, 0_u16, 16_u32, res); + check!(ctlz, 1_u16, 15_u32, res); + check!(ctlz, 0x4000_u16, 1_u32, res); + check!(ctlz, 0x8000_u16, 0_u32, res); + check!(cttz, 0_u16, 16_u32, res); + check!(cttz, 1_u16, 0_u32, res); + check!(cttz, 2_u16, 1_u32, res); + check!(cttz, 0x8000_u16, 15_u32, res); + + check!(ctlz, 0_u8, 8_u32, res); + check!(ctlz, 1_u8, 7_u32, res); + check!(ctlz, 0x40_u8, 1_u32, res); + check!(ctlz, 0x80_u8, 0_u32, res); + check!(cttz, 0_u8, 8_u32, res); + check!(cttz, 1_u8, 0_u32, res); + check!(cttz, 2_u8, 1_u32, res); + check!(cttz, 0x80_u8, 7_u32, res); + + 0 +} From a9b15b61033f246d04fe7e568b8d13ecb3da7f06 Mon Sep 17 00:00:00 2001 From: dvermd <315743+dvermd@users.noreply.github.com> Date: Mon, 17 Nov 2025 06:02:25 +0100 Subject: [PATCH 090/585] add ubsan to Debug test Profile --- tests/lang_tests_common.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs index 9abe97b10876..983ffc2b6405 100644 --- a/tests/lang_tests_common.rs +++ b/tests/lang_tests_common.rs @@ -115,7 +115,19 @@ fn filter(filename: &Path) -> bool { } } match profile { - Profile::Debug => {} + Profile::Debug => { + if test_target.is_ok() { + // m68k doesn't have lubsan for now + compiler.args(["-C", "llvm-args=sanitize-undefined"]); + } else { + compiler.args([ + "-C", + "llvm-args=sanitize-undefined", + "-C", + "link-args=-lubsan", + ]); + } + } Profile::Release => { compiler.args(["-C", "opt-level=3", "-C", "lto=no"]); } From b881bd29fdcd5c906396977358ef9b308f982aee Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 25 Nov 2025 15:43:23 -0500 Subject: [PATCH 091/585] add a high-level design description --- src/doc/rustc-dev-guide/src/offload/internals.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/offload/internals.md b/src/doc/rustc-dev-guide/src/offload/internals.md index 28857a6e78bf..77a4cadbcb98 100644 --- a/src/doc/rustc-dev-guide/src/offload/internals.md +++ b/src/doc/rustc-dev-guide/src/offload/internals.md @@ -7,3 +7,10 @@ also offer more advanced, possibly unsafe, interfaces which allow a higher degre The implementation is based on LLVM's "offload" project, which is already used by OpenMP to run Fortran or C++ code on GPUs. While the project is under development, users will need to call other compilers like clang to finish the compilation process. + +## High-level design: +We use a single-source, two-pass compilation approach. + +First we compile all functions that should be offloaded for the device (e.g nvptx64, amdgcn-amd-amdhsa, intel in the future). Currently we require cumbersome `#cfg(target_os="")` annotations, but we intend to recognize those in the future based on our offload intrinsic. + +We then compile the code for the host (e.g. x86-64), where most of the offloading logic happens. On the host side, we generate calls to the openmp offload runtime, to inform it about the layout of the types (a simplified version of the autodiff TypeTrees). We also use the type system to figure out whether kernel arguments have to be moved only to the device (e.g. `&[f32;1024]`), from the device, or both (e.g. `&mut [f64]`). We then launched the kernel, after which we inform the runtime to end this environment and move data back (as far as needed). From 67094fc00a5a1eb5f530d605cfb73adc9f2079ef Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 26 Nov 2025 11:19:52 -0600 Subject: [PATCH 092/585] test(frontmatter): Check handling of long code fences --- tests/ui/frontmatter/fence-too-many-dashes.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/ui/frontmatter/fence-too-many-dashes.rs diff --git a/tests/ui/frontmatter/fence-too-many-dashes.rs b/tests/ui/frontmatter/fence-too-many-dashes.rs new file mode 100644 index 000000000000..2246a14044fc --- /dev/null +++ b/tests/ui/frontmatter/fence-too-many-dashes.rs @@ -0,0 +1,12 @@ +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +// ignore-tidy-linelength +[dependencies] +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +#![feature(frontmatter)] + +//@ check-pass + +// check that we limit fence lengths + +fn main() {} From 70b6d779834becf483fd5186b6f9edb54f16bcf9 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 26 Nov 2025 14:01:22 -0600 Subject: [PATCH 093/585] fix(parse): Limit frontmatter fences to 255 dashes Like raw string literals. --- compiler/rustc_parse/messages.ftl | 1 + compiler/rustc_parse/src/errors.rs | 6 ++++++ compiler/rustc_parse/src/lexer/mod.rs | 5 +++++ tests/ui/frontmatter/fence-too-many-dashes.rs | 3 +-- tests/ui/frontmatter/fence-too-many-dashes.stderr | 4 ++++ 5 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tests/ui/frontmatter/fence-too-many-dashes.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 7055e60956a9..8a556a73dbd0 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -347,6 +347,7 @@ parse_frontmatter_invalid_opening_preceding_whitespace = invalid preceding white parse_frontmatter_length_mismatch = frontmatter close does not match the opening .label_opening = the opening here has {$len_opening} dashes... .label_close = ...while the close has {$len_close} dashes +parse_frontmatter_too_many_dashes = too many `-` symbols: frontmatter openings may be delimited by up to 255 `-` symbols, but found {$len_opening} parse_frontmatter_unclosed = unclosed frontmatter .note = frontmatter opening here was not closed diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 62a333fbf81d..b0236c3538cc 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -822,6 +822,12 @@ pub(crate) struct FrontmatterLengthMismatch { pub len_close: usize, } +#[derive(Diagnostic)] +#[diag(parse_frontmatter_too_many_dashes)] +pub(crate) struct FrontmatterTooManyDashes { + pub len_opening: usize, +} + #[derive(Diagnostic)] #[diag(parse_leading_plus_not_supported)] pub(crate) struct LeadingPlusNotSupported { diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 51019db7c00e..c62c8acced70 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -665,6 +665,11 @@ fn validate_frontmatter( }); } + // Only up to 255 `-`s are allowed in code fences + if u8::try_from(len_opening).is_err() { + self.dcx().emit_err(errors::FrontmatterTooManyDashes { len_opening }); + } + if !rest.trim_matches(is_horizontal_whitespace).is_empty() { let span = self.mk_sp(last_line_start_pos, self.pos); self.dcx().emit_err(errors::FrontmatterExtraCharactersAfterClose { span }); diff --git a/tests/ui/frontmatter/fence-too-many-dashes.rs b/tests/ui/frontmatter/fence-too-many-dashes.rs index 2246a14044fc..abb64748d3d0 100644 --- a/tests/ui/frontmatter/fence-too-many-dashes.rs +++ b/tests/ui/frontmatter/fence-too-many-dashes.rs @@ -1,12 +1,11 @@ ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//~? ERROR: too many `-` symbols: frontmatter openings may be delimited by up to 255 `-` symbols // ignore-tidy-linelength [dependencies] ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- #![feature(frontmatter)] -//@ check-pass - // check that we limit fence lengths fn main() {} diff --git a/tests/ui/frontmatter/fence-too-many-dashes.stderr b/tests/ui/frontmatter/fence-too-many-dashes.stderr new file mode 100644 index 000000000000..09ed9ffa7a42 --- /dev/null +++ b/tests/ui/frontmatter/fence-too-many-dashes.stderr @@ -0,0 +1,4 @@ +error: too many `-` symbols: frontmatter openings may be delimited by up to 255 `-` symbols, but found 256 + +error: aborting due to 1 previous error + From 72076c6b54478159b848552237b1e09e2c39bbce Mon Sep 17 00:00:00 2001 From: Skgland Date: Wed, 26 Nov 2025 21:38:51 +0100 Subject: [PATCH 094/585] move and rename proc_macro::tracked_{env::var,path::path} --- compiler/rustc_fluent_macro/src/fluent.rs | 3 +++ compiler/rustc_fluent_macro/src/lib.rs | 3 ++- compiler/rustc_macros/src/current_version.rs | 4 ++++ compiler/rustc_macros/src/symbols.rs | 8 ++++++- library/proc_macro/src/lib.rs | 22 ++++++++++---------- tests/ui/proc-macro/auxiliary/env.rs | 6 +++--- 6 files changed, 30 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs index e383d085bb3d..46d11d0469a4 100644 --- a/compiler/rustc_fluent_macro/src/fluent.rs +++ b/compiler/rustc_fluent_macro/src/fluent.rs @@ -8,6 +8,9 @@ Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern, PatternElement, }; use fluent_syntax::parser::ParserError; +#[cfg(not(bootstrap))] +use proc_macro::tracked::path; +#[cfg(bootstrap)] use proc_macro::tracked_path::path; use proc_macro::{Diagnostic, Level, Span}; use proc_macro2::TokenStream; diff --git a/compiler/rustc_fluent_macro/src/lib.rs b/compiler/rustc_fluent_macro/src/lib.rs index c2f49de31c23..e9ddeb3b971e 100644 --- a/compiler/rustc_fluent_macro/src/lib.rs +++ b/compiler/rustc_fluent_macro/src/lib.rs @@ -1,7 +1,8 @@ // tidy-alphabetical-start #![allow(rustc::default_hash_types)] +#![cfg_attr(bootstrap, feature(track_path))] +#![cfg_attr(not(bootstrap), feature(proc_macro_tracked_path))] #![feature(proc_macro_diagnostic)] -#![feature(track_path)] // tidy-alphabetical-end use proc_macro::TokenStream; diff --git a/compiler/rustc_macros/src/current_version.rs b/compiler/rustc_macros/src/current_version.rs index 42ca60a6d8ab..6912d68421cb 100644 --- a/compiler/rustc_macros/src/current_version.rs +++ b/compiler/rustc_macros/src/current_version.rs @@ -22,7 +22,11 @@ struct RustcVersion { impl RustcVersion { fn parse_cfg_release(env_var: &str) -> Result> { + #[cfg(not(bootstrap))] + let value = proc_macro::tracked::env_var(env_var)?; + #[cfg(bootstrap)] let value = proc_macro::tracked_env::var(env_var)?; + Self::parse_str(&value) .ok_or_else(|| format!("failed to parse rustc version: {:?}", value).into()) } diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs index 78a4d47ca334..7437dddf58c5 100644 --- a/compiler/rustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -259,7 +259,13 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) { break; } - let value = match proc_macro::tracked_env::var(env_var.value()) { + #[cfg(bootstrap)] + let tracked_env = proc_macro::tracked_env::var(env_var.value()); + + #[cfg(not(bootstrap))] + let tracked_env = proc_macro::tracked::env_var(env_var.value()); + + let value = match tracked_env { Ok(value) => value, Err(err) => { errors.list.push(syn::Error::new_spanned(expr, err)); diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 4efdfcad924b..ee224ceb6045 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1594,9 +1594,14 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } -/// Tracked access to environment variables. -#[unstable(feature = "proc_macro_tracked_env", issue = "99515")] -pub mod tracked_env { +#[unstable( + feature = "proc_macro_tracked_path", + issue = "99515", + implied_by = "proc_macro_tracked_env" +)] +/// Functionality for adding environment state to the build dependency info. +pub mod tracked { + use std::env::{self, VarError}; use std::ffi::OsStr; @@ -1606,23 +1611,18 @@ pub mod tracked_env { /// Besides the dependency tracking this function should be equivalent to `env::var` from the /// standard library, except that the argument must be UTF-8. #[unstable(feature = "proc_macro_tracked_env", issue = "99515")] - pub fn var + AsRef>(key: K) -> Result { + pub fn env_var + AsRef>(key: K) -> Result { let key: &str = key.as_ref(); let value = crate::bridge::client::FreeFunctions::injected_env_var(key) .map_or_else(|| env::var(key), Ok); crate::bridge::client::FreeFunctions::track_env_var(key, value.as_deref().ok()); value } -} -/// Tracked access to additional files. -#[unstable(feature = "track_path", issue = "99515")] -pub mod tracked_path { - - /// Track a file explicitly. + /// Track a file or directory explicitly. /// /// Commonly used for tracking asset preprocessing. - #[unstable(feature = "track_path", issue = "99515")] + #[unstable(feature = "proc_macro_tracked_path", issue = "99515")] pub fn path>(path: P) { let path: &str = path.as_ref(); crate::bridge::client::FreeFunctions::track_path(path); diff --git a/tests/ui/proc-macro/auxiliary/env.rs b/tests/ui/proc-macro/auxiliary/env.rs index d01e3b42d4ce..f0f0328e131e 100644 --- a/tests/ui/proc-macro/auxiliary/env.rs +++ b/tests/ui/proc-macro/auxiliary/env.rs @@ -3,11 +3,11 @@ extern crate proc_macro; use proc_macro::TokenStream; -use proc_macro::tracked_env::var; +use proc_macro::tracked::env_var; #[proc_macro] pub fn generate_const(input: TokenStream) -> TokenStream { - let the_const = match var("THE_CONST") { + let the_const = match env_var("THE_CONST") { Ok(x) if x == "12" => { "const THE_CONST: u32 = 12;" } @@ -15,7 +15,7 @@ pub fn generate_const(input: TokenStream) -> TokenStream { "const THE_CONST: u32 = 0;" } }; - let another = if var("ANOTHER").is_ok() { + let another = if env_var("ANOTHER").is_ok() { "const ANOTHER: u32 = 1;" } else { "const ANOTHER: u32 = 2;" From 8d8d7021c6006481728775ac4db170af05cf161d Mon Sep 17 00:00:00 2001 From: Skgland Date: Wed, 26 Nov 2025 21:43:44 +0100 Subject: [PATCH 095/585] change proc_macro::tracked::path to take an AsRef instead of an AsRef --- library/proc_macro/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index ee224ceb6045..cb9e53780b04 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1604,6 +1604,7 @@ pub mod tracked { use std::env::{self, VarError}; use std::ffi::OsStr; + use std::path::Path; /// Retrieve an environment variable and add it to build dependency info. /// The build system executing the compiler will know that the variable was accessed during @@ -1623,8 +1624,8 @@ pub fn env_var + AsRef>(key: K) -> Result /// /// Commonly used for tracking asset preprocessing. #[unstable(feature = "proc_macro_tracked_path", issue = "99515")] - pub fn path>(path: P) { - let path: &str = path.as_ref(); + pub fn path>(path: P) { + let path: &str = path.as_ref().to_str().unwrap(); crate::bridge::client::FreeFunctions::track_path(path); } } From 2aa9360c359fb9fcf2e9ecf3acb66d5c936ace01 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 27 Nov 2025 06:41:59 +0100 Subject: [PATCH 096/585] Give an overview of our stability guarantees --- src/doc/rustc-dev-guide/src/SUMMARY.md | 1 + .../src/stability-guarantees.md | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/doc/rustc-dev-guide/src/stability-guarantees.md diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 249140956c09..37ab3ff56979 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -52,6 +52,7 @@ - [Mastering @rustbot](./rustbot.md) - [Walkthrough: a typical contribution](./walkthrough.md) - [Implementing new language features](./implementing_new_features.md) +- [Stability guarantees](./stability-guarantees.md) - [Stability attributes](./stability.md) - [Stabilizing language features](./stabilization_guide.md) - [Stabilization report template](./stabilization_report_template.md) diff --git a/src/doc/rustc-dev-guide/src/stability-guarantees.md b/src/doc/rustc-dev-guide/src/stability-guarantees.md new file mode 100644 index 000000000000..21c4f3594d84 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/stability-guarantees.md @@ -0,0 +1,26 @@ +# Stability guarantees + +This page gives an overview of our stability guarantees. + +## RFCs + +* [RFC 1105 api evolution](https://github.com/rust-lang/rfcs/blob/master/text/1105-api-evolution.md) +* [RFC 1122 language semver](https://github.com/rust-lang/rfcs/blob/master/text/1122-language-semver.md) + +## Blog posts + +* [Stability as a Deliverable](https://blog.rust-lang.org/2014/10/30/Stability/) + +## rustc-dev-guide links + +* [Stabilizing library features](./stability.md) +* [Stabilizing language features](./stabilization_guide.md) +* [What qualifies as a bug fix?](./bug-fix-procedure.md#what-qualifies-as-a-bug-fix) + +## Exemptions + +Even if some of our infrastructure can be used by others, it is still considered +internal and comes without stability guarantees. This is a non-exhaustive list +of components without stability guarantees: + +* The CLIs and environment variables used by `remote-test-client` / `remote-test-server` From 430ec291a0ba420c187a5ca22ac05811551efedd Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Thu, 27 Nov 2025 06:58:36 +0000 Subject: [PATCH 097/585] Prepare for merging from rust-lang/rust This updates the rust-version file to 1be6b13be73dc12e98e51b403add4c41a0b77759. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 08324790e311..bddb68a06b02 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -d3e1ccdf40ae7b7a6dc81edc073d80dad7b66f75 +1be6b13be73dc12e98e51b403add4c41a0b77759 From daccd994e5270dd927d5ab295f37511140ef9938 Mon Sep 17 00:00:00 2001 From: bendn Date: Thu, 20 Nov 2025 00:04:50 +0700 Subject: [PATCH 098/585] stabilize maybe_uninit_slice --- library/core/src/mem/maybe_uninit.rs | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index aee28c4590c2..d07115219f8a 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1097,20 +1097,6 @@ pub const fn as_bytes_mut(&mut self) -> &mut [MaybeUninit] { ) } } - - /// Gets a pointer to the first element of the array. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[inline(always)] - pub const fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { - this.as_ptr() as *const T - } - - /// Gets a mutable pointer to the first element of the array. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[inline(always)] - pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { - this.as_mut_ptr() as *mut T - } } impl [MaybeUninit] { @@ -1477,7 +1463,7 @@ pub const fn as_bytes_mut(&mut self) -> &mut [MaybeUninit] { /// requirement the compiler knows about it is that the data pointer must be /// non-null. Dropping such a `Vec` however will cause undefined /// behaviour. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] #[inline(always)] #[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")] pub const unsafe fn assume_init_drop(&mut self) @@ -1499,7 +1485,8 @@ pub const fn as_bytes_mut(&mut self) -> &mut [MaybeUninit] { /// Calling this when the content is not yet fully initialized causes undefined /// behavior: it is up to the caller to guarantee that every `MaybeUninit` in /// the slice really is in an initialized state. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] #[inline(always)] pub const unsafe fn assume_init_ref(&self) -> &[T] { // SAFETY: casting `slice` to a `*const [T]` is safe since the caller guarantees that @@ -1517,7 +1504,8 @@ pub const fn as_bytes_mut(&mut self) -> &mut [MaybeUninit] { /// behavior: it is up to the caller to guarantee that every `MaybeUninit` in the /// slice really is in an initialized state. For instance, `.assume_init_mut()` cannot /// be used to initialize a `MaybeUninit` slice. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] #[inline(always)] pub const unsafe fn assume_init_mut(&mut self) -> &mut [T] { // SAFETY: similar to safety notes for `slice_get_ref`, but we have a From d67f99af2e9851c1d2ce565db848180d03e782b5 Mon Sep 17 00:00:00 2001 From: bendn Date: Thu, 20 Nov 2025 00:40:52 +0700 Subject: [PATCH 099/585] fix --- compiler/rustc_arena/src/lib.rs | 2 +- library/alloc/src/lib.rs | 1 - library/alloctests/lib.rs | 1 - library/core/src/clone/uninit.rs | 8 +------- library/core/src/mem/maybe_uninit.rs | 6 +++--- library/core/src/slice/sort/stable/merge.rs | 2 +- library/core/src/slice/sort/stable/quicksort.rs | 2 +- library/std/src/lib.rs | 1 - library/std/tests/path.rs | 1 - 9 files changed, 7 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index a821d9e7fa23..5151c358774e 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -10,13 +10,13 @@ // tidy-alphabetical-start #![allow(clippy::mut_from_ref)] // Arena allocators are one place where this pattern is fine. #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(maybe_uninit_slice))] #![cfg_attr(test, feature(test))] #![deny(unsafe_op_in_unsafe_fn)] #![doc(test(no_crate_inject, attr(deny(warnings), allow(internal_features))))] #![feature(core_intrinsics)] #![feature(decl_macro)] #![feature(dropck_eyepatch)] -#![feature(maybe_uninit_slice)] #![feature(never_type)] #![feature(rustc_attrs)] #![feature(unwrap_infallible)] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3f391fe2c1de..bf73deb0e837 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -127,7 +127,6 @@ #![feature(layout_for_ptr)] #![feature(legacy_receiver_trait)] #![feature(local_waker)] -#![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(panic_internals)] #![feature(pattern)] diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index 73c25679d05b..f6c7105ea280 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -28,7 +28,6 @@ #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] -#![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(ptr_alignment_type)] #![feature(ptr_internals)] diff --git a/library/core/src/clone/uninit.rs b/library/core/src/clone/uninit.rs index 8d1185067eb8..b6e351fc7c96 100644 --- a/library/core/src/clone/uninit.rs +++ b/library/core/src/clone/uninit.rs @@ -114,16 +114,10 @@ fn push(&mut self, value: T) { impl<'a, T> Drop for InitializingSlice<'a, T> { #[cold] // will only be invoked on unwind fn drop(&mut self) { - let initialized_slice = ptr::slice_from_raw_parts_mut( - MaybeUninit::slice_as_mut_ptr(self.data), - self.initialized_len, - ); // SAFETY: // * the pointer is valid because it was made from a mutable reference // * `initialized_len` counts the initialized elements as an invariant of this type, // so each of the pointed-to elements is initialized and may be dropped. - unsafe { - ptr::drop_in_place::<[T]>(initialized_slice); - } + unsafe { self.data[..self.initialized_len].assume_init_drop() }; } } diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index d07115219f8a..e00cf45fcab2 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1047,7 +1047,7 @@ pub const fn as_mut_ptr(&mut self) -> *mut T { /// # Examples /// /// ``` - /// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)] + /// #![feature(maybe_uninit_as_bytes)] /// use std::mem::MaybeUninit; /// /// let val = 0x12345678_i32; @@ -1396,7 +1396,7 @@ pub fn write_iter(&mut self, it: I) -> (&mut [T], &mut [MaybeUninit]) /// # Examples /// /// ``` - /// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)] + /// #![feature(maybe_uninit_as_bytes)] /// use std::mem::MaybeUninit; /// /// let uninit = [MaybeUninit::new(0x1234u16), MaybeUninit::new(0x5678u16)]; @@ -1423,7 +1423,7 @@ pub const fn as_bytes(&self) -> &[MaybeUninit] { /// # Examples /// /// ``` - /// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)] + /// #![feature(maybe_uninit_as_bytes)] /// use std::mem::MaybeUninit; /// /// let mut uninit = [MaybeUninit::::uninit(), MaybeUninit::::uninit()]; diff --git a/library/core/src/slice/sort/stable/merge.rs b/library/core/src/slice/sort/stable/merge.rs index bb2747bfc78a..26d8480b7f71 100644 --- a/library/core/src/slice/sort/stable/merge.rs +++ b/library/core/src/slice/sort/stable/merge.rs @@ -35,7 +35,7 @@ pub fn merge bool>( // 1. Protects integrity of `v` from panics in `is_less`. // 2. Fills the remaining gap in `v` if the longer run gets consumed first. - let buf = MaybeUninit::slice_as_mut_ptr(scratch); + let buf = scratch.as_mut_ptr().cast_init(); let v_base = v.as_mut_ptr(); let v_mid = v_base.add(mid); diff --git a/library/core/src/slice/sort/stable/quicksort.rs b/library/core/src/slice/sort/stable/quicksort.rs index 0439ba870bd2..734a495ce225 100644 --- a/library/core/src/slice/sort/stable/quicksort.rs +++ b/library/core/src/slice/sort/stable/quicksort.rs @@ -97,7 +97,7 @@ fn stable_partition bool>( } let v_base = v.as_ptr(); - let scratch_base = MaybeUninit::slice_as_mut_ptr(scratch); + let scratch_base = scratch.as_mut_ptr().cast_init(); // The core idea is to write the values that compare as less-than to the left // side of `scratch`, while the values that compared as greater or equal than diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 8df87124245b..21d09d00c15e 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -348,7 +348,6 @@ #![feature(ip)] #![feature(lazy_get)] #![feature(maybe_uninit_array_assume_init)] -#![feature(maybe_uninit_slice)] #![feature(panic_can_unwind)] #![feature(panic_internals)] #![feature(pin_coerce_unsized_trait)] diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index c60edbdf961e..4094b7acd874 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![feature(clone_to_uninit)] -#![feature(maybe_uninit_slice)] #![feature(normalize_lexically)] #![feature(path_trailing_sep)] // tidy-alphabetical-end From 8762fba317922e7346fecad2981e79a8677b8ef4 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 27 Nov 2025 19:33:29 +0200 Subject: [PATCH 100/585] expand valid edition range for use-path-segment-kw.rs --- tests/ui/use/use-path-segment-kw.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/use/use-path-segment-kw.rs b/tests/ui/use/use-path-segment-kw.rs index 137a9e18aef3..680ecd3d03d4 100644 --- a/tests/ui/use/use-path-segment-kw.rs +++ b/tests/ui/use/use-path-segment-kw.rs @@ -1,4 +1,4 @@ -//@ edition: 2021 +//@ edition: 2018.. macro_rules! macro_dollar_crate { () => { From 00ec159c71740764de2c4d39744e99cdb8c9572c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 24 Nov 2025 15:07:32 +0000 Subject: [PATCH 101/585] Remove PathKind from CrateSource It is never used anywhere anymore now that existing_matches doesn't use it anymore. And there is no good reason for any other code to use it in the future either. --- compiler/rustc_codegen_ssa/src/back/link.rs | 18 +++----- compiler/rustc_interface/src/passes.rs | 6 +-- compiler/rustc_metadata/src/creader.rs | 16 +++---- compiler/rustc_metadata/src/locator.rs | 50 ++++++++++----------- compiler/rustc_session/src/cstore.rs | 12 +++-- compiler/rustc_session/src/search_paths.rs | 1 - 6 files changed, 47 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 820f7ba4a6f2..dd497667a4d9 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -278,7 +278,7 @@ pub fn each_linked_rlib( } let crate_name = info.crate_name[&cnum]; let used_crate_source = &info.used_crate_source[&cnum]; - if let Some((path, _)) = &used_crate_source.rlib { + if let Some(path) = &used_crate_source.rlib { f(cnum, path); } else if used_crate_source.rmeta.is_some() { return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name }); @@ -542,7 +542,7 @@ fn link_staticlib( }; let crate_name = codegen_results.crate_info.crate_name[&cnum]; let used_crate_source = &codegen_results.crate_info.used_crate_source[&cnum]; - if let Some((path, _)) = &used_crate_source.dylib { + if let Some(path) = &used_crate_source.dylib { all_rust_dylibs.push(&**path); } else if used_crate_source.rmeta.is_some() { sess.dcx().emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name }); @@ -620,7 +620,6 @@ fn read_input(&self, path: &Path) -> std::io::Result<&[u8]> { .used_crate_source .items() .filter_map(|(_, csource)| csource.rlib.as_ref()) - .map(|(path, _)| path) .into_sorted_stable_ord(); for input_rlib in input_rlibs { @@ -2178,12 +2177,7 @@ fn add_rpath_args( .crate_info .used_crates .iter() - .filter_map(|cnum| { - codegen_results.crate_info.used_crate_source[cnum] - .dylib - .as_ref() - .map(|(path, _)| &**path) - }) + .filter_map(|cnum| codegen_results.crate_info.used_crate_source[cnum].dylib.as_deref()) .collect::>(); let rpath_config = RPathConfig { libs: &*libs, @@ -2661,7 +2655,7 @@ fn add_native_libs_from_crate( if link_static && cnum != LOCAL_CRATE && !bundled_libs.is_empty() { // If rlib contains native libs as archives, unpack them to tmpdir. - let rlib = &codegen_results.crate_info.used_crate_source[&cnum].rlib.as_ref().unwrap().0; + let rlib = codegen_results.crate_info.used_crate_source[&cnum].rlib.as_ref().unwrap(); archive_builder_builder .extract_bundled_libs(rlib, tmpdir, bundled_libs) .unwrap_or_else(|e| sess.dcx().emit_fatal(e)); @@ -2832,7 +2826,7 @@ fn add_upstream_rust_crates( } Linkage::Dynamic => { let src = &codegen_results.crate_info.used_crate_source[&cnum]; - add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0); + add_dynamic_crate(cmd, sess, src.dylib.as_ref().unwrap()); } } @@ -2960,7 +2954,7 @@ fn add_static_crate( bundled_lib_file_names: &FxIndexSet, ) { let src = &codegen_results.crate_info.used_crate_source[&cnum]; - let cratepath = &src.rlib.as_ref().unwrap().0; + let cratepath = src.rlib.as_ref().unwrap(); let mut link_upstream = |path: &Path| cmd.link_staticlib_by_path(&rehome_lib_path(sess, path), false); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index ddfec9f886a6..b7273dd69561 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -684,19 +684,19 @@ fn hash_iter_files>( for &cnum in tcx.crates(()) { let source = tcx.used_crate_source(cnum); - if let Some((path, _)) = &source.dylib { + if let Some(path) = &source.dylib { files.extend(hash_iter_files( iter::once(escape_dep_filename(&path.display().to_string())), checksum_hash_algo, )); } - if let Some((path, _)) = &source.rlib { + if let Some(path) = &source.rlib { files.extend(hash_iter_files( iter::once(escape_dep_filename(&path.display().to_string())), checksum_hash_algo, )); } - if let Some((path, _)) = &source.rmeta { + if let Some(path) = &source.rmeta { files.extend(hash_iter_files( iter::once(escape_dep_filename(&path.display().to_string())), checksum_hash_algo, diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 85fa8cda2229..250aa0769024 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -135,16 +135,16 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(fmt, " priv: {:?}", data.is_private_dep())?; let CrateSource { dylib, rlib, rmeta, sdylib_interface } = data.source(); if let Some(dylib) = dylib { - writeln!(fmt, " dylib: {}", dylib.0.display())?; + writeln!(fmt, " dylib: {}", dylib.display())?; } if let Some(rlib) = rlib { - writeln!(fmt, " rlib: {}", rlib.0.display())?; + writeln!(fmt, " rlib: {}", rlib.display())?; } if let Some(rmeta) = rmeta { - writeln!(fmt, " rmeta: {}", rmeta.0.display())?; + writeln!(fmt, " rmeta: {}", rmeta.display())?; } if let Some(sdylib_interface) = sdylib_interface { - writeln!(fmt, " sdylib interface: {}", sdylib_interface.0.display())?; + writeln!(fmt, " sdylib interface: {}", sdylib_interface.display())?; } } Ok(()) @@ -550,9 +550,9 @@ fn existing_match( if let Some(mut files) = entry.files() { if files.any(|l| { let l = l.canonicalized(); - source.dylib.as_ref().map(|(p, _)| p) == Some(l) - || source.rlib.as_ref().map(|(p, _)| p) == Some(l) - || source.rmeta.as_ref().map(|(p, _)| p) == Some(l) + source.dylib.as_ref() == Some(l) + || source.rlib.as_ref() == Some(l) + || source.rmeta.as_ref() == Some(l) }) { return Some(cnum); } @@ -658,7 +658,7 @@ fn register_crate<'tcx>( None => (&source, &crate_root), }; let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate"); - Some(self.dlsym_proc_macros(tcx.sess, &dlsym_dylib.0, dlsym_root.stable_crate_id())?) + Some(self.dlsym_proc_macros(tcx.sess, dlsym_dylib, dlsym_root.stable_crate_id())?) } else { None }; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 9fef22f9558d..c4083a27e72b 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -218,7 +218,7 @@ use std::path::{Path, PathBuf}; use std::{cmp, fmt}; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned}; use rustc_data_structures::svh::Svh; @@ -401,7 +401,7 @@ fn find_library_crate( let mut candidates: FxIndexMap< _, - (FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>), + (FxIndexSet<_>, FxIndexSet<_>, FxIndexSet<_>, FxIndexSet<_>), > = Default::default(); // First, find all possible candidate rlibs and dylibs purely based on @@ -460,10 +460,10 @@ fn find_library_crate( // filesystem code should not care, but this is nicer for diagnostics. let path = spf.path.to_path_buf(); match kind { - CrateFlavor::Rlib => rlibs.insert(path, search_path.kind), - CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind), - CrateFlavor::Dylib => dylibs.insert(path, search_path.kind), - CrateFlavor::SDylib => interfaces.insert(path, search_path.kind), + CrateFlavor::Rlib => rlibs.insert(path), + CrateFlavor::Rmeta => rmetas.insert(path), + CrateFlavor::Dylib => dylibs.insert(path), + CrateFlavor::SDylib => interfaces.insert(path), }; } } @@ -524,10 +524,10 @@ fn find_library_crate( fn extract_lib( &self, crate_rejections: &mut CrateRejections, - rlibs: FxIndexMap, - rmetas: FxIndexMap, - dylibs: FxIndexMap, - interfaces: FxIndexMap, + rlibs: FxIndexSet, + rmetas: FxIndexSet, + dylibs: FxIndexSet, + interfaces: FxIndexSet, ) -> Result, CrateError> { let mut slot = None; // Order here matters, rmeta should come first. @@ -575,10 +575,10 @@ fn needs_crate_flavor(&self, flavor: CrateFlavor) -> bool { fn extract_one( &self, crate_rejections: &mut CrateRejections, - m: FxIndexMap, + m: FxIndexSet, flavor: CrateFlavor, slot: &mut Option<(Svh, MetadataBlob, PathBuf, CrateFlavor)>, - ) -> Result, CrateError> { + ) -> Result, CrateError> { // If we are producing an rlib, and we've already loaded metadata, then // we should not attempt to discover further crate sources (unless we're // locating a proc macro; exact logic is in needs_crate_flavor). This means @@ -594,9 +594,9 @@ fn extract_one( } } - let mut ret: Option<(PathBuf, PathKind)> = None; + let mut ret: Option = None; let mut err_data: Option> = None; - for (lib, kind) in m { + for lib in m { info!("{} reading metadata from: {}", flavor, lib.display()); if flavor == CrateFlavor::Rmeta && lib.metadata().is_ok_and(|m| m.len() == 0) { // Empty files will cause get_metadata_section to fail. Rmeta @@ -640,7 +640,7 @@ fn extract_one( info!("no metadata found: {}", err); // Metadata was loaded from interface file earlier. if let Some((.., CrateFlavor::SDylib)) = slot { - ret = Some((lib, kind)); + ret = Some(lib); continue; } // The file was present and created by the same compiler version, but we @@ -689,7 +689,7 @@ fn extract_one( // As a result, we favor the sysroot crate here. Note that the // candidates are all canonicalized, so we canonicalize the sysroot // as well. - if let Some((prev, _)) = &ret { + if let Some(prev) = &ret { let sysroot = self.sysroot; let sysroot = try_canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf()); if prev.starts_with(&sysroot) { @@ -714,7 +714,7 @@ fn extract_one( } else { *slot = Some((hash, metadata, lib.clone(), flavor)); } - ret = Some((lib, kind)); + ret = Some(lib); } if let Some(candidates) = err_data { @@ -774,10 +774,10 @@ fn find_commandline_library( // First, filter out all libraries that look suspicious. We only accept // files which actually exist that have the correct naming scheme for // rlibs/dylibs. - let mut rlibs = FxIndexMap::default(); - let mut rmetas = FxIndexMap::default(); - let mut dylibs = FxIndexMap::default(); - let mut sdylib_interfaces = FxIndexMap::default(); + let mut rlibs = FxIndexSet::default(); + let mut rmetas = FxIndexSet::default(); + let mut dylibs = FxIndexSet::default(); + let mut sdylib_interfaces = FxIndexSet::default(); for loc in &self.exact_paths { let loc_canon = loc.canonicalized(); let loc_orig = loc.original(); @@ -798,21 +798,21 @@ fn find_commandline_library( }; if file.starts_with("lib") { if file.ends_with(".rlib") { - rlibs.insert(loc_canon.clone(), PathKind::ExternFlag); + rlibs.insert(loc_canon.clone()); continue; } if file.ends_with(".rmeta") { - rmetas.insert(loc_canon.clone(), PathKind::ExternFlag); + rmetas.insert(loc_canon.clone()); continue; } if file.ends_with(".rs") { - sdylib_interfaces.insert(loc_canon.clone(), PathKind::ExternFlag); + sdylib_interfaces.insert(loc_canon.clone()); } } let dll_prefix = self.target.dll_prefix.as_ref(); let dll_suffix = self.target.dll_suffix.as_ref(); if file.starts_with(dll_prefix) && file.ends_with(dll_suffix) { - dylibs.insert(loc_canon.clone(), PathKind::ExternFlag); + dylibs.insert(loc_canon.clone()); continue; } crate_rejections diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 30f6256a75ef..378c32d22ae2 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -15,24 +15,22 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::{Span, Symbol}; -use crate::search_paths::PathKind; - // lonely orphan structs and enums looking for a better home /// Where a crate came from on the local filesystem. One of these three options /// must be non-None. #[derive(PartialEq, Clone, Debug, HashStable_Generic, Encodable, Decodable)] pub struct CrateSource { - pub dylib: Option<(PathBuf, PathKind)>, - pub rlib: Option<(PathBuf, PathKind)>, - pub rmeta: Option<(PathBuf, PathKind)>, - pub sdylib_interface: Option<(PathBuf, PathKind)>, + pub dylib: Option, + pub rlib: Option, + pub rmeta: Option, + pub sdylib_interface: Option, } impl CrateSource { #[inline] pub fn paths(&self) -> impl Iterator { - self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).map(|p| &p.0) + self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()) } } diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs index 00e12b45bafb..2ca390b50dd0 100644 --- a/compiler/rustc_session/src/search_paths.rs +++ b/compiler/rustc_session/src/search_paths.rs @@ -71,7 +71,6 @@ pub enum PathKind { Crate, Dependency, Framework, - ExternFlag, All, } From d10216a3a8eec34104f6f897689245245e406a8a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:22:37 +0000 Subject: [PATCH 102/585] Fix rustc_hash ambiguity in miri There are two rustc_hash crates in the sysroot when building miri and there is no way to disambiguate between the two. Instead use the re-exports of it in the rustc_data_structures crate. --- compiler/rustc_data_structures/src/fx.rs | 2 +- src/tools/miri/src/diagnostics.rs | 4 ++-- src/tools/miri/src/helpers.rs | 4 ++-- src/tools/miri/src/lib.rs | 1 - 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index f0db9623b674..c1a5c8ebc764 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -1,6 +1,6 @@ use std::hash::BuildHasherDefault; -pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; +pub use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet, FxHasher}; pub type StdEntry<'a, K, V> = std::collections::hash_map::Entry<'a, K, V>; diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index bb8ba196983c..bf037e3e804f 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -3,8 +3,8 @@ use std::sync::Mutex; use rustc_abi::{Align, Size}; +use rustc_data_structures::fx::{FxBuildHasher, FxHashSet}; use rustc_errors::{Diag, DiagMessage, Level}; -use rustc_hash::FxHashSet; use rustc_span::{DUMMY_SP, Span, SpanData, Symbol}; use crate::borrow_tracker::stacked_borrows::diagnostics::TagHistory; @@ -878,6 +878,6 @@ fn dedup_diagnostic( impl SpanDedupDiagnostic { pub const fn new() -> Self { - Self(Mutex::new(FxHashSet::with_hasher(rustc_hash::FxBuildHasher))) + Self(Mutex::new(FxHashSet::with_hasher(FxBuildHasher))) } } diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 383a4e2ea4b0..2ceb12a25062 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -6,7 +6,7 @@ use rand::RngCore; use rustc_abi::{Align, ExternAbi, FieldIdx, FieldsShape, Size, Variants}; use rustc_apfloat::Float; -use rustc_hash::FxHashSet; +use rustc_data_structures::fx::{FxBuildHasher, FxHashSet}; use rustc_hir::Safety; use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefId, LOCAL_CRATE}; @@ -647,7 +647,7 @@ fn reject_in_isolation(&self, op_name: &str, reject_with: RejectOpWith) -> Inter RejectOpWith::WarningWithoutBacktrace => { // Deduplicate these warnings *by shim* (not by span) static DEDUP: Mutex> = - Mutex::new(FxHashSet::with_hasher(rustc_hash::FxBuildHasher)); + Mutex::new(FxHashSet::with_hasher(FxBuildHasher)); let mut emitted_warnings = DEDUP.lock().unwrap(); if !emitted_warnings.contains(op_name) { // First time we are seeing this. diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 5ec2e8edd857..d6d54c5ce056 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -57,7 +57,6 @@ extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors; -extern crate rustc_hash; extern crate rustc_hir; extern crate rustc_index; extern crate rustc_log; From 9289323fe2f081ca3caa43c9f384288fde9b2e42 Mon Sep 17 00:00:00 2001 From: Mattias Petersson Date: Thu, 27 Nov 2025 20:22:51 +0100 Subject: [PATCH 103/585] Specify toolchain part in building and running There was an issue raised that the toolchain explanation for building and running the compiler needed some refinement. This patch aims to remedy that by specifying what "first" and "second" refer to, and what the toolchain does. Small change to the language to specify that the stage2 toolchain is not built, and how one would build it. --- .../src/building/how-to-build-and-run.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md index c924216b8cd3..b15d77111e19 100644 --- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md +++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md @@ -277,18 +277,20 @@ default). Once you have successfully built `rustc`, you will have created a bunch of files in your `build` directory. In order to actually run the resulting `rustc`, we recommend creating rustup toolchains. The first -one will run the stage1 compiler (which we built above). The second -will execute the stage2 compiler (which we did not build, but which -you will likely need to build at some point; for example, if you want -to run the entire test suite). +command listed below runs the stage1 compiler, which was built in the +steps above, with the name `stage1`. The second command runs the stage2 +compiler using the stage1 compiler. This will be needed in the future +if running the entire test suite, but will not be built in this page. +Building stage2 is done with the same `./x build` command as for stage1, +specifying that the stage is 2 instead. ```bash rustup toolchain link stage1 build/host/stage1 rustup toolchain link stage2 build/host/stage2 ``` -Now you can run the `rustc` you built with. If you run with `-vV`, you -should see a version number ending in `-dev`, indicating a build from +Now you can run the `rustc` you built with via the toolchain. If you run with +`-vV`, you should see a version number ending in `-dev`, indicating a build from your local environment: ```bash From f4296bce97007d68ab4236f5293f50bf06a3664e Mon Sep 17 00:00:00 2001 From: Skgland Date: Thu, 27 Nov 2025 22:02:47 +0100 Subject: [PATCH 104/585] fix tests --- tests/run-make/env-dep-info/macro_def.rs | 4 ++-- tests/run-make/track-path-dep-info/macro_def.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/run-make/env-dep-info/macro_def.rs b/tests/run-make/env-dep-info/macro_def.rs index e328eae48326..17d27ebfba3c 100644 --- a/tests/run-make/env-dep-info/macro_def.rs +++ b/tests/run-make/env-dep-info/macro_def.rs @@ -6,7 +6,7 @@ #[proc_macro] pub fn access_env_vars(_: TokenStream) -> TokenStream { - let _ = tracked_env::var("EXISTING_PROC_MACRO_ENV"); - let _ = tracked_env::var("NONEXISTENT_PROC_MACEO_ENV"); + let _ = tracked::env_var("EXISTING_PROC_MACRO_ENV"); + let _ = tracked::env_var("NONEXISTENT_PROC_MACEO_ENV"); TokenStream::new() } diff --git a/tests/run-make/track-path-dep-info/macro_def.rs b/tests/run-make/track-path-dep-info/macro_def.rs index 8777ce21f8b8..032594d905d0 100644 --- a/tests/run-make/track-path-dep-info/macro_def.rs +++ b/tests/run-make/track-path-dep-info/macro_def.rs @@ -1,4 +1,4 @@ -#![feature(track_path)] +#![feature(proc_macro_track_path)] #![crate_type = "proc-macro"] extern crate proc_macro; @@ -6,6 +6,6 @@ #[proc_macro] pub fn access_tracked_paths(_: TokenStream) -> TokenStream { - tracked_path::path("emojis.txt"); + tracked::path("emojis.txt"); TokenStream::new() } From 364af529e78d408da65f67c1b8f640d94d084b03 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 27 Nov 2025 16:14:23 -0500 Subject: [PATCH 105/585] Use generic builtin for checked binary operation --- src/int.rs | 48 +++--------------------------------------------- 1 file changed, 3 insertions(+), 45 deletions(-) diff --git a/src/int.rs b/src/int.rs index aa1d3b6b091c..49de0b490e88 100644 --- a/src/int.rs +++ b/src/int.rs @@ -287,51 +287,9 @@ pub fn gcc_checked_binop( // TODO(antoyo): remove duplication with intrinsic? let name = if self.is_native_int_type(lhs.get_type()) { match oop { - OverflowOp::Add => match new_kind { - Int(I8) => "__builtin_add_overflow", - Int(I16) => "__builtin_add_overflow", - Int(I32) => "__builtin_sadd_overflow", - Int(I64) => "__builtin_saddll_overflow", - Int(I128) => "__builtin_add_overflow", - - Uint(U8) => "__builtin_add_overflow", - Uint(U16) => "__builtin_add_overflow", - Uint(U32) => "__builtin_uadd_overflow", - Uint(U64) => "__builtin_uaddll_overflow", - Uint(U128) => "__builtin_add_overflow", - - _ => unreachable!(), - }, - OverflowOp::Sub => match new_kind { - Int(I8) => "__builtin_sub_overflow", - Int(I16) => "__builtin_sub_overflow", - Int(I32) => "__builtin_ssub_overflow", - Int(I64) => "__builtin_ssubll_overflow", - Int(I128) => "__builtin_sub_overflow", - - Uint(U8) => "__builtin_sub_overflow", - Uint(U16) => "__builtin_sub_overflow", - Uint(U32) => "__builtin_usub_overflow", - Uint(U64) => "__builtin_usubll_overflow", - Uint(U128) => "__builtin_sub_overflow", - - _ => unreachable!(), - }, - OverflowOp::Mul => match new_kind { - Int(I8) => "__builtin_mul_overflow", - Int(I16) => "__builtin_mul_overflow", - Int(I32) => "__builtin_smul_overflow", - Int(I64) => "__builtin_smulll_overflow", - Int(I128) => "__builtin_mul_overflow", - - Uint(U8) => "__builtin_mul_overflow", - Uint(U16) => "__builtin_mul_overflow", - Uint(U32) => "__builtin_umul_overflow", - Uint(U64) => "__builtin_umulll_overflow", - Uint(U128) => "__builtin_mul_overflow", - - _ => unreachable!(), - }, + OverflowOp::Add => "__builtin_add_overflow", + OverflowOp::Sub => "__builtin_sub_overflow", + OverflowOp::Mul => "__builtin_mul_overflow", } } else { let (func_name, width) = match oop { From 6a14a523d286adb2d1d7265f20b6a8e2bd042466 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 20 Nov 2025 12:56:12 +0100 Subject: [PATCH 106/585] clean-up: pass things by value to avoid copying --- clippy_lints/src/missing_asserts_for_indexing.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 808adb7e71ce..9e9aa5ffc544 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -67,14 +67,14 @@ } declare_lint_pass!(MissingAssertsForIndexing => [MISSING_ASSERTS_FOR_INDEXING]); -fn report_lint(cx: &LateContext<'_>, full_span: Span, msg: &'static str, indexes: &[Span], f: F) +fn report_lint(cx: &LateContext<'_>, full_span: Span, msg: &'static str, indexes: Vec, f: F) where F: FnOnce(&mut Diag<'_, ()>), { span_lint_and_then(cx, MISSING_ASSERTS_FOR_INDEXING, full_span, msg, |diag| { f(diag); for span in indexes { - diag.span_note(*span, "slice indexed here"); + diag.span_note(span, "slice indexed here"); } diag.note("asserting the length before indexing will elide bounds checks"); }); @@ -354,8 +354,8 @@ fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Un /// Inspects indexes and reports lints. /// /// Called at the end of this lint after all indexing and `assert!` expressions have been collected. -fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap>>) { - for bucket in map.values() { +fn report_indexes(cx: &LateContext<'_>, map: UnindexMap>>) { + for bucket in map.into_values() { for entry in bucket { let Some(full_span) = entry .index_spans() @@ -365,12 +365,12 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap continue; }; - match *entry { + match entry { IndexEntry::AssertWithIndex { highest_index, is_first_highest, asserted_len, - ref indexes, + indexes, comparison, assert_span, slice, @@ -433,7 +433,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap } }, IndexEntry::IndexWithoutAssert { - ref indexes, + indexes, highest_index, is_first_highest, slice, @@ -469,6 +469,6 @@ fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) { ControlFlow::::Continue(()) }); - report_indexes(cx, &map); + report_indexes(cx, map); } } From 9ced0f5892eaff77f7b707fbd41be92d38b42028 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 20 Nov 2025 12:58:16 +0100 Subject: [PATCH 107/585] use `note_once` This is a general advice, and so shouldn't be repeated --- clippy_lints/src/missing_asserts_for_indexing.rs | 2 +- tests/ui/missing_asserts_for_indexing.stderr | 14 -------------- .../missing_asserts_for_indexing_unfixable.stderr | 9 --------- 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 9e9aa5ffc544..ea65aa274dc4 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -76,7 +76,7 @@ fn report_lint(cx: &LateContext<'_>, full_span: Span, msg: &'static str, inde for span in indexes { diag.span_note(span, "slice indexed here"); } - diag.note("asserting the length before indexing will elide bounds checks"); + diag.note_once("asserting the length before indexing will elide bounds checks"); }); } diff --git a/tests/ui/missing_asserts_for_indexing.stderr b/tests/ui/missing_asserts_for_indexing.stderr index b686eda7530a..d6eef15c0448 100644 --- a/tests/ui/missing_asserts_for_indexing.stderr +++ b/tests/ui/missing_asserts_for_indexing.stderr @@ -68,7 +68,6 @@ note: slice indexed here | LL | v[0] + v[1] + v[2] + v[3] + v[4] | ^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:42:5 @@ -103,7 +102,6 @@ note: slice indexed here | LL | v[0] + v[1] + v[2] + v[3] + v[4] | ^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:48:5 @@ -138,7 +136,6 @@ note: slice indexed here | LL | v[0] + v[1] + v[2] + v[3] + v[4] | ^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:66:13 @@ -161,7 +158,6 @@ note: slice indexed here | LL | let _ = v[1..4]; | ^^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:81:13 @@ -184,7 +180,6 @@ note: slice indexed here | LL | let _ = v[1..=4]; | ^^^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:97:13 @@ -205,7 +200,6 @@ note: slice indexed here | LL | let _ = v1[0] + v1[12]; | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:100:13 @@ -226,7 +220,6 @@ note: slice indexed here | LL | let _ = v2[5] + v2[15]; | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:106:13 @@ -247,7 +240,6 @@ note: slice indexed here | LL | let _ = v1[0] + v1[12]; | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:131:13 @@ -273,7 +265,6 @@ note: slice indexed here | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:136:13 @@ -299,7 +290,6 @@ note: slice indexed here | LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:158:13 @@ -325,7 +315,6 @@ note: slice indexed here | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:163:13 @@ -351,7 +340,6 @@ note: slice indexed here | LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:172:17 @@ -376,7 +364,6 @@ note: slice indexed here | LL | let _ = v[0] + v[1] + v[2]; | ^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:178:17 @@ -401,7 +388,6 @@ note: slice indexed here | LL | let _ = v[0] + v[1] + v[2]; | ^^^^ - = note: asserting the length before indexing will elide bounds checks error: aborting due to 15 previous errors diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.stderr b/tests/ui/missing_asserts_for_indexing_unfixable.stderr index a17ad0232138..aec64857a699 100644 --- a/tests/ui/missing_asserts_for_indexing_unfixable.stderr +++ b/tests/ui/missing_asserts_for_indexing_unfixable.stderr @@ -54,7 +54,6 @@ note: slice indexed here | LL | let _ = v[1..4]; | ^^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:17:13 @@ -83,7 +82,6 @@ note: slice indexed here | LL | let c = v[2]; | ^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:26:13 @@ -102,7 +100,6 @@ note: slice indexed here | LL | let _ = v1[0] + v1[12]; | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:28:13 @@ -121,7 +118,6 @@ note: slice indexed here | LL | let _ = v2[5] + v2[15]; | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:35:13 @@ -140,7 +136,6 @@ note: slice indexed here | LL | let _ = v2[5] + v2[15]; | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:45:13 @@ -159,7 +154,6 @@ note: slice indexed here | LL | let _ = f.v[0] + f.v[1]; | ^^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:59:13 @@ -178,7 +172,6 @@ note: slice indexed here | LL | let _ = x[0] + x[1]; | ^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:13 @@ -197,7 +190,6 @@ note: slice indexed here | LL | let _ = v1[1] + v1[2]; | ^^^^^ - = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:13 @@ -221,7 +213,6 @@ note: slice indexed here | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ - = note: asserting the length before indexing will elide bounds checks error: aborting due to 10 previous errors From 4b021f6b62c5210b4c0e37ae3eb3873081e92128 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 20 Nov 2025 13:30:54 +0100 Subject: [PATCH 108/585] point the suggestion at each individual span This makes the labels redundant. --- .../src/missing_asserts_for_indexing.rs | 30 +- tests/ui/missing_asserts_for_indexing.stderr | 292 ++---------------- ...sing_asserts_for_indexing_unfixable.stderr | 153 +-------- 3 files changed, 37 insertions(+), 438 deletions(-) diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index ea65aa274dc4..a89a460cdfb3 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -67,15 +67,12 @@ } declare_lint_pass!(MissingAssertsForIndexing => [MISSING_ASSERTS_FOR_INDEXING]); -fn report_lint(cx: &LateContext<'_>, full_span: Span, msg: &'static str, indexes: Vec, f: F) +fn report_lint(cx: &LateContext<'_>, index_spans: Vec, msg: &'static str, f: F) where F: FnOnce(&mut Diag<'_, ()>), { - span_lint_and_then(cx, MISSING_ASSERTS_FOR_INDEXING, full_span, msg, |diag| { + span_lint_and_then(cx, MISSING_ASSERTS_FOR_INDEXING, index_spans, msg, |diag| { f(diag); - for span in indexes { - diag.span_note(span, "slice indexed here"); - } diag.note_once("asserting the length before indexing will elide bounds checks"); }); } @@ -213,15 +210,6 @@ pub fn slice(&self) -> &'hir Expr<'hir> { | IndexEntry::IndexWithoutAssert { slice, .. } => slice, } } - - pub fn index_spans(&self) -> Option<&[Span]> { - match self { - IndexEntry::StrayAssert { .. } => None, - IndexEntry::AssertWithIndex { indexes, .. } | IndexEntry::IndexWithoutAssert { indexes, .. } => { - Some(indexes) - }, - } - } } /// Extracts the upper index of a slice indexing expression. @@ -357,14 +345,6 @@ fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Un fn report_indexes(cx: &LateContext<'_>, map: UnindexMap>>) { for bucket in map.into_values() { for entry in bucket { - let Some(full_span) = entry - .index_spans() - .and_then(|spans| spans.first().zip(spans.last())) - .map(|(low, &high)| low.to(high)) - else { - continue; - }; - match entry { IndexEntry::AssertWithIndex { highest_index, @@ -418,9 +398,8 @@ fn report_indexes(cx: &LateContext<'_>, map: UnindexMap> if let Some(sugg) = sugg { report_lint( cx, - full_span, - "indexing into a slice multiple times with an `assert` that does not cover the highest index", indexes, + "indexing into a slice multiple times with an `assert` that does not cover the highest index", |diag| { diag.span_suggestion( assert_span, @@ -442,9 +421,8 @@ fn report_indexes(cx: &LateContext<'_>, map: UnindexMap> // adding an `assert!` that covers the highest index report_lint( cx, - full_span, - "indexing into a slice multiple times without an `assert`", indexes, + "indexing into a slice multiple times without an `assert`", |diag| { diag.help(format!( "consider asserting the length before indexing: `assert!({}.len() > {highest_index});`", diff --git a/tests/ui/missing_asserts_for_indexing.stderr b/tests/ui/missing_asserts_for_indexing.stderr index d6eef15c0448..30a35a21e5d3 100644 --- a/tests/ui/missing_asserts_for_indexing.stderr +++ b/tests/ui/missing_asserts_for_indexing.stderr @@ -4,33 +4,8 @@ error: indexing into a slice multiple times with an `assert` that does not cover LL | assert!(v.len() < 5); | -------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:30:5 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:30:12 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:30:19 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:30:26 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:30:33 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ = note: asserting the length before indexing will elide bounds checks = note: `-D clippy::missing-asserts-for-indexing` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_asserts_for_indexing)]` @@ -41,33 +16,7 @@ error: indexing into a slice multiple times with an `assert` that does not cover LL | assert!(v.len() <= 5); | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:36:5 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:36:12 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:36:19 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:36:26 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:36:33 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ + | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:42:5 @@ -75,33 +24,7 @@ error: indexing into a slice multiple times with an `assert` that does not cover LL | assert!(v.len() > 3); | -------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:42:5 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:42:12 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:42:19 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:42:26 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:42:33 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ + | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:48:5 @@ -109,75 +32,27 @@ error: indexing into a slice multiple times with an `assert` that does not cover LL | assert!(v.len() >= 4); | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:48:5 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:48:12 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:48:19 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:48:26 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:48:33 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ + | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:66:13 | -LL | assert!(v.len() >= 3); - | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 3)` -LL | let _ = v[0]; - | _____________^ -... | -LL | | let _ = v[1..4]; - | |___________________^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:66:13 - | +LL | assert!(v.len() >= 3); + | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 3)` LL | let _ = v[0]; | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:69:13 - | +... LL | let _ = v[1..4]; | ^^^^^^^ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:81:13 | -LL | assert!(v.len() >= 4); - | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` -LL | let _ = v[0]; - | _____________^ -... | -LL | | let _ = v[1..=4]; - | |____________________^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:81:13 - | +LL | assert!(v.len() >= 4); + | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` LL | let _ = v[0]; | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:84:13 - | +... LL | let _ = v[1..=4]; | ^^^^^^^^ @@ -188,18 +63,7 @@ LL | assert!(v1.len() >= 12); | ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() > 12)` LL | assert!(v2.len() >= 15); LL | let _ = v1[0] + v1[12]; - | ^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:97:13 - | -LL | let _ = v1[0] + v1[12]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:97:21 - | -LL | let _ = v1[0] + v1[12]; - | ^^^^^^ + | ^^^^^ ^^^^^^ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:100:13 @@ -208,18 +72,7 @@ LL | assert!(v2.len() >= 15); | ----------------------- help: provide the highest index that is indexed with: `assert!(v2.len() > 15)` ... LL | let _ = v2[5] + v2[15]; - | ^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:100:13 - | -LL | let _ = v2[5] + v2[15]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:100:21 - | -LL | let _ = v2[5] + v2[15]; - | ^^^^^^ + | ^^^^^ ^^^^^^ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:106:13 @@ -228,18 +81,7 @@ LL | assert!(v1.len() >= 12); | ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() > 12)` LL | assert!(v2.len() > 15); LL | let _ = v1[0] + v1[12]; - | ^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:106:13 - | -LL | let _ = v1[0] + v1[12]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:106:21 - | -LL | let _ = v1[0] + v1[12]; - | ^^^^^^ + | ^^^^^ ^^^^^^ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:131:13 @@ -248,23 +90,7 @@ LL | assert!(v1.len() == 2); | ---------------------- help: provide the highest index that is indexed with: `assert!(v1.len() == 3)` ... LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:131:13 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:131:21 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:131:29 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ + | ^^^^^ ^^^^^ ^^^^^ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:136:13 @@ -273,23 +99,7 @@ LL | assert!(2 == v3.len()); | ---------------------- help: provide the highest index that is indexed with: `assert!(v3.len() == 3)` ... LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:136:13 - | -LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:136:21 - | -LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:136:29 - | -LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^ + | ^^^^^ ^^^^^ ^^^^^ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:158:13 @@ -298,23 +108,7 @@ LL | assert_eq!(v1.len(), 2); | ----------------------- help: provide the highest index that is indexed with: `assert_eq!(v1.len(), 3)` ... LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:158:13 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:158:21 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:158:29 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ + | ^^^^^ ^^^^^ ^^^^^ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:163:13 @@ -323,23 +117,7 @@ LL | assert_eq!(2, v3.len()); | ----------------------- help: provide the highest index that is indexed with: `assert_eq!(v3.len(), 3)` ... LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:163:13 - | -LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:163:21 - | -LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:163:29 - | -LL | let _ = v3[0] + v3[1] + v3[2]; - | ^^^^^ + | ^^^^^ ^^^^^ ^^^^^ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:172:17 @@ -347,23 +125,7 @@ error: indexing into a slice multiple times with an `assert` that does not cover LL | assert_eq!(v.len(), 2); | ---------------------- help: provide the highest index that is indexed with: `assert_eq!(v.len(), 3)` LL | let _ = v[0] + v[1] + v[2]; - | ^^^^^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:172:17 - | -LL | let _ = v[0] + v[1] + v[2]; - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:172:24 - | -LL | let _ = v[0] + v[1] + v[2]; - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:172:31 - | -LL | let _ = v[0] + v[1] + v[2]; - | ^^^^ + | ^^^^ ^^^^ ^^^^ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:178:17 @@ -371,23 +133,7 @@ error: indexing into a slice multiple times with an `assert` that does not cover LL | debug_assert_eq!(v.len(), 2); | ---------------------------- help: provide the highest index that is indexed with: `debug_assert_eq!(v.len(), 3)` LL | let _ = v[0] + v[1] + v[2]; - | ^^^^^^^^^^^^^^^^^^ - | -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:178:17 - | -LL | let _ = v[0] + v[1] + v[2]; - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:178:24 - | -LL | let _ = v[0] + v[1] + v[2]; - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:178:31 - | -LL | let _ = v[0] + v[1] + v[2]; - | ^^^^ + | ^^^^ ^^^^ ^^^^ error: aborting due to 15 previous errors diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.stderr b/tests/ui/missing_asserts_for_indexing_unfixable.stderr index aec64857a699..2929646494a4 100644 --- a/tests/ui/missing_asserts_for_indexing_unfixable.stderr +++ b/tests/ui/missing_asserts_for_indexing_unfixable.stderr @@ -2,34 +2,9 @@ error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:5 | LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ | = help: consider asserting the length before indexing: `assert!(v.len() > 4);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:5 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:12 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:19 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:26 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:33 - | -LL | v[0] + v[1] + v[2] + v[3] + v[4] - | ^^^^ = note: asserting the length before indexing will elide bounds checks = note: `-D clippy::missing-asserts-for-indexing` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_asserts_for_indexing)]` @@ -37,182 +12,82 @@ LL | v[0] + v[1] + v[2] + v[3] + v[4] error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:10:13 | -LL | let _ = v[0]; - | _____________^ -... | -LL | | let _ = v[1..4]; - | |___________________^ - | - = help: consider asserting the length before indexing: `assert!(v.len() > 3);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:10:13 - | LL | let _ = v[0]; | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:13:13 - | +... LL | let _ = v[1..4]; | ^^^^^^^ + | + = help: consider asserting the length before indexing: `assert!(v.len() > 3);` error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:17:13 | -LL | let a = v[0]; - | _____________^ -LL | | -LL | | -LL | | let b = v[1]; -LL | | let c = v[2]; - | |________________^ - | - = help: consider asserting the length before indexing: `assert!(v.len() > 2);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:17:13 - | LL | let a = v[0]; | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:20:13 - | +... LL | let b = v[1]; | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:21:13 - | LL | let c = v[2]; | ^^^^ + | + = help: consider asserting the length before indexing: `assert!(v.len() > 2);` error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:26:13 | LL | let _ = v1[0] + v1[12]; - | ^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^^ | = help: consider asserting the length before indexing: `assert!(v1.len() > 12);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:26:13 - | -LL | let _ = v1[0] + v1[12]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:26:21 - | -LL | let _ = v1[0] + v1[12]; - | ^^^^^^ error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:28:13 | LL | let _ = v2[5] + v2[15]; - | ^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^^ | = help: consider asserting the length before indexing: `assert!(v2.len() > 15);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:28:13 - | -LL | let _ = v2[5] + v2[15]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:28:21 - | -LL | let _ = v2[5] + v2[15]; - | ^^^^^^ error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:35:13 | LL | let _ = v2[5] + v2[15]; - | ^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^^ | = help: consider asserting the length before indexing: `assert!(v2.len() > 15);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:35:13 - | -LL | let _ = v2[5] + v2[15]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:35:21 - | -LL | let _ = v2[5] + v2[15]; - | ^^^^^^ error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:45:13 | LL | let _ = f.v[0] + f.v[1]; - | ^^^^^^^^^^^^^^^ + | ^^^^^^ ^^^^^^ | = help: consider asserting the length before indexing: `assert!(f.v.len() > 1);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:45:13 - | -LL | let _ = f.v[0] + f.v[1]; - | ^^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:45:22 - | -LL | let _ = f.v[0] + f.v[1]; - | ^^^^^^ error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:59:13 | LL | let _ = x[0] + x[1]; - | ^^^^^^^^^^^ + | ^^^^ ^^^^ | = help: consider asserting the length before indexing: `assert!(x.len() > 1);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:59:13 - | -LL | let _ = x[0] + x[1]; - | ^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:59:20 - | -LL | let _ = x[0] + x[1]; - | ^^^^ error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:13 | LL | let _ = v1[1] + v1[2]; - | ^^^^^^^^^^^^^ + | ^^^^^ ^^^^^ | = help: consider asserting the length before indexing: `assert!(v1.len() > 2);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:13 - | -LL | let _ = v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:21 - | -LL | let _ = v1[1] + v1[2]; - | ^^^^^ error: indexing into a slice multiple times without an `assert` --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:13 | LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ ^^^^^ ^^^^^ | = help: consider asserting the length before indexing: `assert!(v1.len() > 2);` -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:13 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:21 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ -note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:29 - | -LL | let _ = v1[0] + v1[1] + v1[2]; - | ^^^^^ error: aborting due to 10 previous errors From f3b905d4a84b4d7ef58bcda3e2dcff08df979d2c Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 20 Nov 2025 13:46:55 +0100 Subject: [PATCH 109/585] use `span_suggestion_verbose` --- .../src/missing_asserts_for_indexing.rs | 2 +- tests/ui/missing_asserts_for_indexing.stderr | 126 +++++++++++++----- 2 files changed, 90 insertions(+), 38 deletions(-) diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index a89a460cdfb3..72bfe830da81 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -401,7 +401,7 @@ fn report_indexes(cx: &LateContext<'_>, map: UnindexMap> indexes, "indexing into a slice multiple times with an `assert` that does not cover the highest index", |diag| { - diag.span_suggestion( + diag.span_suggestion_verbose( assert_span, "provide the highest index that is indexed with", sugg, diff --git a/tests/ui/missing_asserts_for_indexing.stderr b/tests/ui/missing_asserts_for_indexing.stderr index 30a35a21e5d3..d5b5455343e4 100644 --- a/tests/ui/missing_asserts_for_indexing.stderr +++ b/tests/ui/missing_asserts_for_indexing.stderr @@ -1,139 +1,191 @@ error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:30:5 | -LL | assert!(v.len() < 5); - | -------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` LL | v[0] + v[1] + v[2] + v[3] + v[4] | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ | = note: asserting the length before indexing will elide bounds checks = note: `-D clippy::missing-asserts-for-indexing` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_asserts_for_indexing)]` +help: provide the highest index that is indexed with + | +LL - assert!(v.len() < 5); +LL + assert!(v.len() > 4); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:36:5 | -LL | assert!(v.len() <= 5); - | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` LL | v[0] + v[1] + v[2] + v[3] + v[4] | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ + | +help: provide the highest index that is indexed with + | +LL - assert!(v.len() <= 5); +LL + assert!(v.len() > 4); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:42:5 | -LL | assert!(v.len() > 3); - | -------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` LL | v[0] + v[1] + v[2] + v[3] + v[4] | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ + | +help: provide the highest index that is indexed with + | +LL - assert!(v.len() > 3); +LL + assert!(v.len() > 4); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:48:5 | -LL | assert!(v.len() >= 4); - | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` LL | v[0] + v[1] + v[2] + v[3] + v[4] | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ + | +help: provide the highest index that is indexed with + | +LL - assert!(v.len() >= 4); +LL + assert!(v.len() > 4); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:66:13 | -LL | assert!(v.len() >= 3); - | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 3)` LL | let _ = v[0]; | ^^^^ ... LL | let _ = v[1..4]; | ^^^^^^^ + | +help: provide the highest index that is indexed with + | +LL - assert!(v.len() >= 3); +LL + assert!(v.len() > 3); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:81:13 | -LL | assert!(v.len() >= 4); - | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` LL | let _ = v[0]; | ^^^^ ... LL | let _ = v[1..=4]; | ^^^^^^^^ + | +help: provide the highest index that is indexed with + | +LL - assert!(v.len() >= 4); +LL + assert!(v.len() > 4); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:97:13 | -LL | assert!(v1.len() >= 12); - | ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() > 12)` -LL | assert!(v2.len() >= 15); LL | let _ = v1[0] + v1[12]; | ^^^^^ ^^^^^^ + | +help: provide the highest index that is indexed with + | +LL - assert!(v1.len() >= 12); +LL + assert!(v1.len() > 12); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:100:13 | -LL | assert!(v2.len() >= 15); - | ----------------------- help: provide the highest index that is indexed with: `assert!(v2.len() > 15)` -... LL | let _ = v2[5] + v2[15]; | ^^^^^ ^^^^^^ + | +help: provide the highest index that is indexed with + | +LL - assert!(v2.len() >= 15); +LL + assert!(v2.len() > 15); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:106:13 | -LL | assert!(v1.len() >= 12); - | ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() > 12)` -LL | assert!(v2.len() > 15); LL | let _ = v1[0] + v1[12]; | ^^^^^ ^^^^^^ + | +help: provide the highest index that is indexed with + | +LL - assert!(v1.len() >= 12); +LL + assert!(v1.len() > 12); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:131:13 | -LL | assert!(v1.len() == 2); - | ---------------------- help: provide the highest index that is indexed with: `assert!(v1.len() == 3)` -... LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ ^^^^^ ^^^^^ + | +help: provide the highest index that is indexed with + | +LL - assert!(v1.len() == 2); +LL + assert!(v1.len() == 3); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:136:13 | -LL | assert!(2 == v3.len()); - | ---------------------- help: provide the highest index that is indexed with: `assert!(v3.len() == 3)` -... LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ ^^^^^ ^^^^^ + | +help: provide the highest index that is indexed with + | +LL - assert!(2 == v3.len()); +LL + assert!(v3.len() == 3); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:158:13 | -LL | assert_eq!(v1.len(), 2); - | ----------------------- help: provide the highest index that is indexed with: `assert_eq!(v1.len(), 3)` -... LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ ^^^^^ ^^^^^ + | +help: provide the highest index that is indexed with + | +LL - assert_eq!(v1.len(), 2); +LL + assert_eq!(v1.len(), 3); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:163:13 | -LL | assert_eq!(2, v3.len()); - | ----------------------- help: provide the highest index that is indexed with: `assert_eq!(v3.len(), 3)` -... LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ ^^^^^ ^^^^^ + | +help: provide the highest index that is indexed with + | +LL - assert_eq!(2, v3.len()); +LL + assert_eq!(v3.len(), 3); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:172:17 | -LL | assert_eq!(v.len(), 2); - | ---------------------- help: provide the highest index that is indexed with: `assert_eq!(v.len(), 3)` LL | let _ = v[0] + v[1] + v[2]; | ^^^^ ^^^^ ^^^^ + | +help: provide the highest index that is indexed with + | +LL - assert_eq!(v.len(), 2); +LL + assert_eq!(v.len(), 3); + | error: indexing into a slice multiple times with an `assert` that does not cover the highest index --> tests/ui/missing_asserts_for_indexing.rs:178:17 | -LL | debug_assert_eq!(v.len(), 2); - | ---------------------------- help: provide the highest index that is indexed with: `debug_assert_eq!(v.len(), 3)` LL | let _ = v[0] + v[1] + v[2]; | ^^^^ ^^^^ ^^^^ + | +help: provide the highest index that is indexed with + | +LL - debug_assert_eq!(v.len(), 2); +LL + debug_assert_eq!(v.len(), 3); + | error: aborting due to 15 previous errors From 129a39d6be3e18ea1ad3daae992901e1a27f7851 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 20 Nov 2025 14:53:19 +0100 Subject: [PATCH 110/585] fix: adjust the applicability for the suggestion --- .../src/missing_asserts_for_indexing.rs | 48 ++++++++----------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 72bfe830da81..87ee164a1760 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::{If, Range}; use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace, root_macro_call}; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{eq_expr_value, hash_expr}; use rustc_ast::{BinOpKind, LitKind, RangeLimits}; @@ -356,41 +356,33 @@ fn report_indexes(cx: &LateContext<'_>, map: UnindexMap> slice, macro_call, } if indexes.len() > 1 && !is_first_highest => { + let mut app = Applicability::MachineApplicable; + let slice_str = snippet_with_applicability(cx, slice.span, "_", &mut app); // if we have found an `assert!`, let's also check that it's actually right // and if it covers the highest index and if not, suggest the correct length let sugg = match comparison { // `v.len() < 5` and `v.len() <= 5` does nothing in terms of bounds checks. // The user probably meant `v.len() > 5` - LengthComparison::LengthLessThanInt | LengthComparison::LengthLessThanOrEqualInt => Some( - format!("assert!({}.len() > {highest_index})", snippet(cx, slice.span, "..")), - ), + LengthComparison::LengthLessThanInt | LengthComparison::LengthLessThanOrEqualInt => { + Some(format!("assert!({slice_str}.len() > {highest_index})",)) + }, // `5 < v.len()` == `v.len() > 5` - LengthComparison::IntLessThanLength if asserted_len < highest_index => Some(format!( - "assert!({}.len() > {highest_index})", - snippet(cx, slice.span, "..") - )), + LengthComparison::IntLessThanLength if asserted_len < highest_index => { + Some(format!("assert!({slice_str}.len() > {highest_index})",)) + }, // `5 <= v.len() == `v.len() >= 5` - LengthComparison::IntLessThanOrEqualLength if asserted_len <= highest_index => Some(format!( - "assert!({}.len() > {highest_index})", - snippet(cx, slice.span, "..") - )), + LengthComparison::IntLessThanOrEqualLength if asserted_len <= highest_index => { + Some(format!("assert!({slice_str}.len() > {highest_index})",)) + }, // `highest_index` here is rather a length, so we need to add 1 to it LengthComparison::LengthEqualInt if asserted_len < highest_index + 1 => match macro_call { - sym::assert_eq_macro => Some(format!( - "assert_eq!({}.len(), {})", - snippet(cx, slice.span, ".."), - highest_index + 1 - )), - sym::debug_assert_eq_macro => Some(format!( - "debug_assert_eq!({}.len(), {})", - snippet(cx, slice.span, ".."), - highest_index + 1 - )), - _ => Some(format!( - "assert!({}.len() == {})", - snippet(cx, slice.span, ".."), - highest_index + 1 - )), + sym::assert_eq_macro => { + Some(format!("assert_eq!({slice_str}.len(), {})", highest_index + 1)) + }, + sym::debug_assert_eq_macro => { + Some(format!("debug_assert_eq!({slice_str}.len(), {})", highest_index + 1)) + }, + _ => Some(format!("assert!({slice_str}.len() == {})", highest_index + 1)), }, _ => None, }; @@ -405,7 +397,7 @@ fn report_indexes(cx: &LateContext<'_>, map: UnindexMap> assert_span, "provide the highest index that is indexed with", sugg, - Applicability::MachineApplicable, + app, ); }, ); From c1f50c0a17946ac5365c867107af90de9305dd47 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 27 Nov 2025 17:02:13 -0500 Subject: [PATCH 111/585] Use generic builtin for saturating add/sub --- src/intrinsic/mod.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index db9f32bad5a7..26240d470b2d 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -1160,14 +1160,7 @@ fn saturating_add( let res = func.new_local(self.location, result_type, "saturating_sum"); let supports_native_type = self.is_native_int_type(result_type); let overflow = if supports_native_type { - let func_name = match width { - 8 => "__builtin_add_overflow", - 16 => "__builtin_add_overflow", - 32 => "__builtin_sadd_overflow", - 64 => "__builtin_saddll_overflow", - 128 => "__builtin_add_overflow", - _ => unreachable!(), - }; + let func_name = "__builtin_add_overflow"; let overflow_func = self.context.get_builtin_function(func_name); self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(self.location)], None) } else { @@ -1231,14 +1224,7 @@ fn saturating_sub( let res = func.new_local(self.location, result_type, "saturating_diff"); let supports_native_type = self.is_native_int_type(result_type); let overflow = if supports_native_type { - let func_name = match width { - 8 => "__builtin_sub_overflow", - 16 => "__builtin_sub_overflow", - 32 => "__builtin_ssub_overflow", - 64 => "__builtin_ssubll_overflow", - 128 => "__builtin_sub_overflow", - _ => unreachable!(), - }; + let func_name = "__builtin_sub_overflow"; let overflow_func = self.context.get_builtin_function(func_name); self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(self.location)], None) } else { From 16a47d97267748f98fbc084afcff67a6ff962530 Mon Sep 17 00:00:00 2001 From: Mattias Petersson <61464624+Mattias-Petersson@users.noreply.github.com> Date: Fri, 28 Nov 2025 07:44:24 +0100 Subject: [PATCH 112/585] Update src/building/how-to-build-and-run.md Co-authored-by: Tshepang Mbambo --- .../rustc-dev-guide/src/building/how-to-build-and-run.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md index b15d77111e19..d0a38b12c550 100644 --- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md +++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md @@ -277,9 +277,9 @@ default). Once you have successfully built `rustc`, you will have created a bunch of files in your `build` directory. In order to actually run the resulting `rustc`, we recommend creating rustup toolchains. The first -command listed below runs the stage1 compiler, which was built in the -steps above, with the name `stage1`. The second command runs the stage2 -compiler using the stage1 compiler. This will be needed in the future +command listed below creates the stage1 toolchain, which was built in the +steps above, with the name `stage1`. The second command creates the stage2 +toolchain using the stage1 compiler. This will be needed in the future if running the entire test suite, but will not be built in this page. Building stage2 is done with the same `./x build` command as for stage1, specifying that the stage is 2 instead. From e6ad406d48956b2b3f159d116af2d05cda5da79a Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 11 Oct 2025 13:13:48 +0200 Subject: [PATCH 113/585] feat(manual_ilog2): new lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/manual_ilog2.rs | 115 +++++++++++++++++++++++++++++ clippy_utils/src/msrvs.rs | 1 + clippy_utils/src/sym.rs | 2 + tests/ui/manual_ilog2.fixed | 32 ++++++++ tests/ui/manual_ilog2.rs | 32 ++++++++ tests/ui/manual_ilog2.stderr | 23 ++++++ 9 files changed, 209 insertions(+) create mode 100644 clippy_lints/src/manual_ilog2.rs create mode 100644 tests/ui/manual_ilog2.fixed create mode 100644 tests/ui/manual_ilog2.rs create mode 100644 tests/ui/manual_ilog2.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 78b81b5b74d6..76de222960e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6541,6 +6541,7 @@ Released 2018-09-13 [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten [`manual_hash_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one [`manual_ignore_case_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ignore_case_cmp +[`manual_ilog2`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ilog2 [`manual_inspect`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_inspect [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 4a350dca2993..edaea69d01a5 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -300,6 +300,7 @@ crate::manual_float_methods::MANUAL_IS_INFINITE_INFO, crate::manual_hash_one::MANUAL_HASH_ONE_INFO, crate::manual_ignore_case_cmp::MANUAL_IGNORE_CASE_CMP_INFO, + crate::manual_ilog2::MANUAL_ILOG2_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, crate::manual_is_power_of_two::MANUAL_IS_POWER_OF_TWO_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 230d83dacc95..cad36b7f197a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -201,6 +201,7 @@ mod manual_float_methods; mod manual_hash_one; mod manual_ignore_case_cmp; +mod manual_ilog2; mod manual_is_ascii_check; mod manual_is_power_of_two; mod manual_let_else; @@ -848,6 +849,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(|_| Box::new(toplevel_ref_arg::ToplevelRefArg)), Box::new(|_| Box::new(volatile_composites::VolatileComposites)), Box::new(|_| Box::::default()), + Box::new(move |_| Box::new(manual_ilog2::ManualIlog2::new(conf))), // add late passes here, used by `cargo dev new_lint` ]; store.late_passes.extend(late_lints); diff --git a/clippy_lints/src/manual_ilog2.rs b/clippy_lints/src/manual_ilog2.rs new file mode 100644 index 000000000000..1c61db530606 --- /dev/null +++ b/clippy_lints/src/manual_ilog2.rs @@ -0,0 +1,115 @@ +use clippy_config::Conf; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{is_from_proc_macro, sym}; +use rustc_ast::LitKind; +use rustc_data_structures::packed::Pu128; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::ty; +use rustc_session::impl_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for expressions like `N - x.leading_zeros()` (where `N` is one less than bit width + /// of `x`) or `x.ilog(2)`, which are manual reimplementations of `x.ilog2()` + /// + /// ### Why is this bad? + /// Manual reimplementations of `ilog2` increase code complexity for little benefit. + /// + /// ### Example + /// ```no_run + /// let x: u32 = 5; + /// let log = 31 - x.leading_zeros(); + /// let log = x.ilog(2); + /// ``` + /// Use instead: + /// ```no_run + /// let x: u32 = 5; + /// let log = x.ilog2(); + /// let log = x.ilog2(); + /// ``` + #[clippy::version = "1.93.0"] + pub MANUAL_ILOG2, + pedantic, + "manually reimplementing `ilog2`" +} + +pub struct ManualIlog2 { + msrv: Msrv, +} + +impl ManualIlog2 { + pub fn new(conf: &Conf) -> Self { + Self { msrv: conf.msrv } + } +} + +impl_lint_pass!(ManualIlog2 => [MANUAL_ILOG2]); + +impl LateLintPass<'_> for ManualIlog2 { + fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if expr.span.in_external_macro(cx.sess().source_map()) { + return; + } + + match expr.kind { + // `BIT_WIDTH - 1 - n.leading_zeros()` + ExprKind::Binary(op, left, right) + if left.span.eq_ctxt(right.span) + && op.node == BinOpKind::Sub + && let ExprKind::Lit(lit) = left.kind + && let LitKind::Int(Pu128(val), _) = lit.node + && let ExprKind::MethodCall(leading_zeros, recv, [], _) = right.kind + && leading_zeros.ident.name == sym::leading_zeros + && let ty = cx.typeck_results().expr_ty(recv) + && let Some(bit_width) = match ty.kind() { + ty::Uint(uint_ty) => uint_ty.bit_width(), + ty::Int(_) => { + // On non-positive integers, `ilog2` would panic, which might be a sign that the author does + // in fact want to calculate something different, so stay on the safer side and don't + // suggest anything. + return; + }, + _ => return, + } + && val == u128::from(bit_width) - 1 + && self.msrv.meets(cx, msrvs::ILOG2) + && !is_from_proc_macro(cx, expr) => + { + emit(cx, recv, expr); + }, + + // `n.ilog(2)` + ExprKind::MethodCall(ilog, recv, [two], _) + if expr.span.eq_ctxt(two.span) + && ilog.ident.name == sym::ilog + && let ExprKind::Lit(lit) = two.kind + && let LitKind::Int(Pu128(2), _) = lit.node + && cx.typeck_results().expr_ty_adjusted(recv).is_integral() + /* no need to check MSRV here, as `ilog` and `ilog2` were introduced simultaneously */ + && !is_from_proc_macro(cx, expr) => + { + emit(cx, recv, expr); + }, + + _ => {}, + } + } +} + +fn emit(cx: &LateContext<'_>, recv: &Expr<'_>, full_expr: &Expr<'_>) { + let mut app = Applicability::MachineApplicable; + let recv = snippet_with_applicability(cx, recv.span, "_", &mut app); + span_lint_and_sugg( + cx, + MANUAL_ILOG2, + full_expr.span, + "manually reimplementing `ilog2`", + "try", + format!("{recv}.ilog2()"), + app, + ); +} diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 86d17a8231d5..4a7fa3472cae 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -40,6 +40,7 @@ macro_rules! msrv_aliases { 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } + 1,67,0 { ILOG2 } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,63,0 { CLONE_INTO, CONST_SLICE_FROM_REF } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN } diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 1d1537dd0e91..00f4a9c7e586 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -180,6 +180,7 @@ macro_rules! generate { has_significant_drop, hidden_glob_reexports, hygiene, + ilog, insert, insert_str, inspect, @@ -207,6 +208,7 @@ macro_rules! generate { join, kw, lazy_static, + leading_zeros, lint_vec, ln, lock, diff --git a/tests/ui/manual_ilog2.fixed b/tests/ui/manual_ilog2.fixed new file mode 100644 index 000000000000..a0f6d9392c30 --- /dev/null +++ b/tests/ui/manual_ilog2.fixed @@ -0,0 +1,32 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::manual_ilog2)] +#![allow(clippy::unnecessary_operation)] + +use proc_macros::{external, with_span}; + +fn foo(a: u32, b: u64) { + a.ilog2(); //~ manual_ilog2 + a.ilog2(); //~ manual_ilog2 + + b.ilog2(); //~ manual_ilog2 + 64 - b.leading_zeros(); // No lint because manual ilog2 is `BIT_WIDTH - 1 - x.leading_zeros()` + + // don't lint when macros are involved + macro_rules! two { + () => { + 2 + }; + }; + + macro_rules! thirty_one { + () => { + 31 + }; + }; + + a.ilog(two!()); + thirty_one!() - a.leading_zeros(); + + external!($a.ilog(2)); + with_span!(span; a.ilog(2)); +} diff --git a/tests/ui/manual_ilog2.rs b/tests/ui/manual_ilog2.rs new file mode 100644 index 000000000000..bd4b5d9d3c0d --- /dev/null +++ b/tests/ui/manual_ilog2.rs @@ -0,0 +1,32 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::manual_ilog2)] +#![allow(clippy::unnecessary_operation)] + +use proc_macros::{external, with_span}; + +fn foo(a: u32, b: u64) { + 31 - a.leading_zeros(); //~ manual_ilog2 + a.ilog(2); //~ manual_ilog2 + + 63 - b.leading_zeros(); //~ manual_ilog2 + 64 - b.leading_zeros(); // No lint because manual ilog2 is `BIT_WIDTH - 1 - x.leading_zeros()` + + // don't lint when macros are involved + macro_rules! two { + () => { + 2 + }; + }; + + macro_rules! thirty_one { + () => { + 31 + }; + }; + + a.ilog(two!()); + thirty_one!() - a.leading_zeros(); + + external!($a.ilog(2)); + with_span!(span; a.ilog(2)); +} diff --git a/tests/ui/manual_ilog2.stderr b/tests/ui/manual_ilog2.stderr new file mode 100644 index 000000000000..7c9694f35330 --- /dev/null +++ b/tests/ui/manual_ilog2.stderr @@ -0,0 +1,23 @@ +error: manually reimplementing `ilog2` + --> tests/ui/manual_ilog2.rs:8:5 + | +LL | 31 - a.leading_zeros(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.ilog2()` + | + = note: `-D clippy::manual-ilog2` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_ilog2)]` + +error: manually reimplementing `ilog2` + --> tests/ui/manual_ilog2.rs:9:5 + | +LL | a.ilog(2); + | ^^^^^^^^^ help: try: `a.ilog2()` + +error: manually reimplementing `ilog2` + --> tests/ui/manual_ilog2.rs:11:5 + | +LL | 63 - b.leading_zeros(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `b.ilog2()` + +error: aborting due to 3 previous errors + From 7cd6922f6be880c4ee330bfa0d7fd6d9a93149f1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 28 Nov 2025 10:51:35 +0000 Subject: [PATCH 114/585] Rustup to rustc 1.93.0-nightly (c86564c41 2025-11-27) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 5eba4411d78b..4bbbc12cdd0b 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-11-19" +channel = "nightly-2025-11-28" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 110649f0a8dfb21e65ee8114c05eacf5260307b1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 28 Nov 2025 13:09:08 +0100 Subject: [PATCH 115/585] Fix display of dropdown menu "buttons" --- util/gh-pages/style.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/gh-pages/style.css b/util/gh-pages/style.css index 242e2227ed94..ce478a3e18d0 100644 --- a/util/gh-pages/style.css +++ b/util/gh-pages/style.css @@ -637,14 +637,14 @@ pre, hr { display: flex; } -ul.dropdown-menu li.checkbox > button { +#menu-filters ul.dropdown-menu li.checkbox > button { border: 0; width: 100%; background: var(--theme-popup-bg); color: var(--fg); } -ul.dropdown-menu li.checkbox > button:hover { +#menu-filters ul.dropdown-menu li.checkbox > button:hover { background: var(--theme-hover); box-shadow: none; } From e163707c70dd5490b13b68f1ed111bdea2785f98 Mon Sep 17 00:00:00 2001 From: nxsaken Date: Sun, 9 Nov 2025 21:07:54 +0400 Subject: [PATCH 116/585] Constify `DropGuard` methods --- library/core/src/mem/drop_guard.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/library/core/src/mem/drop_guard.rs b/library/core/src/mem/drop_guard.rs index 1301dedf1241..013134727b7f 100644 --- a/library/core/src/mem/drop_guard.rs +++ b/library/core/src/mem/drop_guard.rs @@ -1,4 +1,5 @@ use crate::fmt::{self, Debug}; +use crate::marker::Destruct; use crate::mem::ManuallyDrop; use crate::ops::{Deref, DerefMut}; @@ -81,8 +82,12 @@ pub const fn new(inner: T, f: F) -> Self { /// assert_eq!(guard.dismiss(), "Nori likes chicken"); /// ``` #[unstable(feature = "drop_guard", issue = "144426")] + #[rustc_const_unstable(feature = "const_drop_guard", issue = "none")] #[inline] - pub fn dismiss(self) -> T { + pub const fn dismiss(self) -> T + where + F: [const] Destruct, + { // First we ensure that dropping the guard will not trigger // its destructor let mut this = ManuallyDrop::new(self); @@ -103,7 +108,8 @@ pub fn dismiss(self) -> T { } #[unstable(feature = "drop_guard", issue = "144426")] -impl Deref for DropGuard +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const Deref for DropGuard where F: FnOnce(T), { @@ -115,7 +121,8 @@ fn deref(&self) -> &T { } #[unstable(feature = "drop_guard", issue = "144426")] -impl DerefMut for DropGuard +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const DerefMut for DropGuard where F: FnOnce(T), { @@ -125,9 +132,10 @@ fn deref_mut(&mut self) -> &mut T { } #[unstable(feature = "drop_guard", issue = "144426")] -impl Drop for DropGuard +#[rustc_const_unstable(feature = "const_drop_guard", issue = "none")] +impl const Drop for DropGuard where - F: FnOnce(T), + F: [const] FnOnce(T), { fn drop(&mut self) { // SAFETY: `DropGuard` is in the process of being dropped. From 85e24b0d3625f6ae16f61a7e352384b8419401b5 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Fri, 28 Nov 2025 19:45:07 +0100 Subject: [PATCH 117/585] Make the capitalization explicit on keyword misspell error --- compiler/rustc_errors/src/emitter.rs | 2 ++ compiler/rustc_parse/messages.ftl | 2 +- compiler/rustc_parse/src/errors.rs | 23 ++++++++++++++-- compiler/rustc_parse/src/parser/mod.rs | 15 ++++++++++- tests/ui/parser/item-kw-case-mismatch.stderr | 28 ++++++++++---------- 5 files changed, 52 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index d9132ca12349..d08d5a5a1ea2 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -3544,6 +3544,8 @@ pub fn detect_confusion_type(sm: &SourceMap, suggested: &str, sp: Span) -> Confu let mut has_digit_letter_confusable = false; let mut has_other_diff = false; + // Letters whose lowercase version is very similar to the uppercase + // version. let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z']; let digit_letter_confusables = [('0', 'O'), ('1', 'l'), ('5', 'S'), ('8', 'B'), ('9', 'g')]; diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 7055e60956a9..bc81acefef74 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -512,7 +512,7 @@ parse_keyword_lifetime = lifetimes cannot use keyword names parse_kw_bad_case = keyword `{$kw}` is written in the wrong case - .suggestion = write it in the correct case + .suggestion = write it in {$case} parse_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item} parse_label_unexpected_token = unexpected token diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 62a333fbf81d..9344848c7653 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1,14 +1,15 @@ // ignore-tidy-filelength use std::borrow::Cow; +use std::path::PathBuf; use rustc_ast::token::Token; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{Path, Visibility}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic, - SuggestionStyle, + Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, + Level, Subdiagnostic, SuggestionStyle, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_session::errors::ExprParenthesesNeeded; @@ -3335,6 +3336,24 @@ pub(crate) struct KwBadCase<'a> { #[suggestion(code = "{kw}", style = "verbose", applicability = "machine-applicable")] pub span: Span, pub kw: &'a str, + pub case: Case, +} + +pub(crate) enum Case { + Upper, + Lower, + Mixed, +} + +impl IntoDiagArg for Case { + fn into_diag_arg(self, path: &mut Option) -> DiagArgValue { + match self { + Case::Upper => "uppercase", + Case::Lower => "lowercase", + Case::Mixed => "the correct case", + } + .into_diag_arg(path) + } } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 14a738fb9d24..8577ea40589a 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -606,7 +606,20 @@ fn eat_keyword_case(&mut self, exp: ExpKeywordPair, case: Case) -> bool { // Do an ASCII case-insensitive match, because all keywords are ASCII. && ident.as_str().eq_ignore_ascii_case(exp.kw.as_str()) { - self.dcx().emit_err(errors::KwBadCase { span: ident.span, kw: exp.kw.as_str() }); + let kw = exp.kw.as_str(); + let is_upper = kw.chars().all(char::is_uppercase); + let is_lower = kw.chars().all(char::is_lowercase); + + let case = match (is_upper, is_lower) { + (true, true) => { + unreachable!("keyword that is both fully upper- and fully lowercase") + } + (true, false) => errors::Case::Upper, + (false, true) => errors::Case::Lower, + (false, false) => errors::Case::Mixed, + }; + + self.dcx().emit_err(errors::KwBadCase { span: ident.span, kw, case }); self.bump(); true } else { diff --git a/tests/ui/parser/item-kw-case-mismatch.stderr b/tests/ui/parser/item-kw-case-mismatch.stderr index d2a1eb7f2f52..55cbc6be943c 100644 --- a/tests/ui/parser/item-kw-case-mismatch.stderr +++ b/tests/ui/parser/item-kw-case-mismatch.stderr @@ -4,7 +4,7 @@ error: keyword `use` is written in the wrong case LL | Use std::ptr::read; | ^^^ | -help: write it in the correct case (notice the capitalization) +help: write it in lowercase (notice the capitalization) | LL - Use std::ptr::read; LL + use std::ptr::read; @@ -16,7 +16,7 @@ error: keyword `use` is written in the wrong case LL | USE std::ptr::write; | ^^^ | -help: write it in the correct case +help: write it in lowercase | LL - USE std::ptr::write; LL + use std::ptr::write; @@ -28,7 +28,7 @@ error: keyword `fn` is written in the wrong case LL | async Fn _a() {} | ^^ | -help: write it in the correct case (notice the capitalization) +help: write it in lowercase (notice the capitalization) | LL - async Fn _a() {} LL + async fn _a() {} @@ -40,7 +40,7 @@ error: keyword `fn` is written in the wrong case LL | Fn _b() {} | ^^ | -help: write it in the correct case (notice the capitalization) +help: write it in lowercase (notice the capitalization) | LL - Fn _b() {} LL + fn _b() {} @@ -52,7 +52,7 @@ error: keyword `async` is written in the wrong case LL | aSYNC fN _c() {} | ^^^^^ | -help: write it in the correct case +help: write it in lowercase | LL - aSYNC fN _c() {} LL + async fN _c() {} @@ -64,7 +64,7 @@ error: keyword `fn` is written in the wrong case LL | aSYNC fN _c() {} | ^^ | -help: write it in the correct case +help: write it in lowercase | LL - aSYNC fN _c() {} LL + aSYNC fn _c() {} @@ -76,7 +76,7 @@ error: keyword `async` is written in the wrong case LL | Async fn _d() {} | ^^^^^ | -help: write it in the correct case +help: write it in lowercase | LL - Async fn _d() {} LL + async fn _d() {} @@ -88,7 +88,7 @@ error: keyword `const` is written in the wrong case LL | CONST UNSAFE FN _e() {} | ^^^^^ | -help: write it in the correct case +help: write it in lowercase | LL - CONST UNSAFE FN _e() {} LL + const UNSAFE FN _e() {} @@ -100,7 +100,7 @@ error: keyword `unsafe` is written in the wrong case LL | CONST UNSAFE FN _e() {} | ^^^^^^ | -help: write it in the correct case +help: write it in lowercase | LL - CONST UNSAFE FN _e() {} LL + CONST unsafe FN _e() {} @@ -112,7 +112,7 @@ error: keyword `fn` is written in the wrong case LL | CONST UNSAFE FN _e() {} | ^^ | -help: write it in the correct case +help: write it in lowercase | LL - CONST UNSAFE FN _e() {} LL + CONST UNSAFE fn _e() {} @@ -124,7 +124,7 @@ error: keyword `unsafe` is written in the wrong case LL | unSAFE EXTern "C" fn _f() {} | ^^^^^^ | -help: write it in the correct case +help: write it in lowercase | LL - unSAFE EXTern "C" fn _f() {} LL + unsafe EXTern "C" fn _f() {} @@ -136,7 +136,7 @@ error: keyword `extern` is written in the wrong case LL | unSAFE EXTern "C" fn _f() {} | ^^^^^^ | -help: write it in the correct case +help: write it in lowercase | LL - unSAFE EXTern "C" fn _f() {} LL + unSAFE extern "C" fn _f() {} @@ -148,7 +148,7 @@ error: keyword `extern` is written in the wrong case LL | EXTERN "C" FN _g() {} | ^^^^^^ | -help: write it in the correct case +help: write it in lowercase | LL - EXTERN "C" FN _g() {} LL + extern "C" FN _g() {} @@ -160,7 +160,7 @@ error: keyword `fn` is written in the wrong case LL | EXTERN "C" FN _g() {} | ^^ | -help: write it in the correct case +help: write it in lowercase | LL - EXTERN "C" FN _g() {} LL + EXTERN "C" fn _g() {} From bd211952823c79c382bf0f6a8ace3fddee860c1e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 22 Nov 2025 13:29:55 -0800 Subject: [PATCH 118/585] Update to mdbook 0.5 Changelog: https://github.com/rust-lang/mdBook/blob/master/CHANGELOG.md#mdbook-051 --- src/doc/rustc-dev-guide/.github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/.github/workflows/ci.yml b/src/doc/rustc-dev-guide/.github/workflows/ci.yml index 76e1d0a8f7cf..fe92bc876cf7 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/ci.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/ci.yml @@ -14,9 +14,9 @@ jobs: if: github.repository == 'rust-lang/rustc-dev-guide' runs-on: ubuntu-latest env: - MDBOOK_VERSION: 0.4.52 - MDBOOK_LINKCHECK2_VERSION: 0.9.1 - MDBOOK_MERMAID_VERSION: 0.12.6 + MDBOOK_VERSION: 0.5.1 + MDBOOK_LINKCHECK2_VERSION: 0.11.0 + MDBOOK_MERMAID_VERSION: 0.17.0 MDBOOK_OUTPUT__LINKCHECK__FOLLOW_WEB_LINKS: ${{ github.event_name != 'pull_request' }} DEPLOY_DIR: book/html BASE_SHA: ${{ github.event.pull_request.base.sha }} From 099308af902a1d2bc6104192c276b7e946eb5aae Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 28 Nov 2025 20:25:22 +0100 Subject: [PATCH 119/585] Merge commit '92b4b68683249c781c3acad742fc6e57c4140ad9' into clippy-subtree-update --- .github/workflows/clippy_mq.yml | 10 +- .github/workflows/deploy.yml | 4 +- .github/workflows/lintcheck.yml | 6 +- .github/workflows/remark.yml | 7 +- CHANGELOG.md | 2 + .../continuous_integration/github_actions.md | 2 +- book/src/lint_configuration.md | 11 + clippy_config/src/conf.rs | 4 + clippy_lints/src/byte_char_slices.rs | 51 +- clippy_lints/src/declared_lints.rs | 3 +- clippy_lints/src/dereference.rs | 460 ++++--- .../doc/doc_paragraphs_missing_punctuation.rs | 126 ++ clippy_lints/src/doc/mod.rs | 38 + clippy_lints/src/equatable_if_let.rs | 80 +- clippy_lints/src/functions/mod.rs | 30 +- clippy_lints/src/functions/result.rs | 30 +- clippy_lints/src/implicit_hasher.rs | 40 +- clippy_lints/src/lib.rs | 4 +- .../src/methods/sliced_string_as_bytes.rs | 10 +- clippy_lints/src/methods/useless_asref.rs | 28 +- clippy_lints/src/missing_doc.rs | 443 ++++--- .../src/multiple_unsafe_ops_per_block.rs | 115 +- clippy_lints/src/ptr/ptr_arg.rs | 6 +- clippy_lints/src/time_subtraction.rs | 68 +- .../src/transmute/transmute_ptr_to_ptr.rs | 66 +- .../src/transmute/transmute_ref_to_ref.rs | 42 +- clippy_lints/src/unwrap.rs | 229 +++- clippy_lints/src/{vec.rs => useless_vec.rs} | 35 +- clippy_utils/README.md | 2 +- clippy_utils/src/ast_utils/mod.rs | 4 +- clippy_utils/src/check_proc_macro.rs | 9 +- clippy_utils/src/lib.rs | 3 + clippy_utils/src/sugg.rs | 11 +- rust-toolchain.toml | 2 +- src/driver.rs | 7 +- .../missing_docs_allow_unused.rs | 26 - .../missing_docs_allow_unused.stderr | 38 - .../allow_unused}/clippy.toml | 0 .../crate_root}/clippy.toml | 0 .../default/clippy.toml | 0 ..._docs_in_private_items.allow_unused.stderr | 644 +++++++++ ...ng_docs_in_private_items.crate_root.stderr | 500 +++++++ ...ssing_docs_in_private_items.default.stderr | 704 ++++++++++ .../missing_docs_in_private_items.rs | 1167 +++++++++++++++++ .../pub_crate_missing_doc.rs | 67 - .../pub_crate_missing_doc.stderr | 53 - tests/ui-toml/result_large_err/clippy.toml | 1 + .../result_large_err/result_large_err.rs | 20 + .../result_large_err/result_large_err.stderr | 2 +- .../toml_unknown_key/conf_unknown_key.stderr | 3 + tests/ui/blanket_clippy_restriction_lints.rs | 2 +- tests/ui/byte_char_slices.fixed | 1 - tests/ui/byte_char_slices.rs | 1 - tests/ui/byte_char_slices.stderr | 10 +- tests/ui/cast.rs | 10 + tests/ui/cast.stderr | 8 +- .../ui/checked_unwrap/complex_conditionals.rs | 28 +- .../complex_conditionals.stderr | 56 +- .../complex_conditionals_nested.rs | 11 +- .../complex_conditionals_nested.stderr | 19 +- tests/ui/checked_unwrap/if_let_chains.rs | 2 +- tests/ui/checked_unwrap/if_let_chains.stderr | 7 +- .../ui/checked_unwrap/simple_conditionals.rs | 225 +++- .../checked_unwrap/simple_conditionals.stderr | 390 ++++-- .../doc_paragraphs_missing_punctuation.fixed | 172 +++ .../doc/doc_paragraphs_missing_punctuation.rs | 172 +++ .../doc_paragraphs_missing_punctuation.stderr | 113 ++ ...aragraphs_missing_punctuation_unfixable.rs | 13 + ...raphs_missing_punctuation_unfixable.stderr | 20 + tests/ui/equatable_if_let.fixed | 107 +- tests/ui/equatable_if_let.rs | 107 +- tests/ui/equatable_if_let.stderr | 52 +- tests/ui/equatable_if_let_const_cmp.fixed | 24 + tests/ui/equatable_if_let_const_cmp.rs | 24 + tests/ui/equatable_if_let_const_cmp.stderr | 17 + tests/ui/explicit_deref_methods.fixed | 113 ++ tests/ui/explicit_deref_methods.rs | 113 ++ tests/ui/implicit_hasher.fixed | 24 + tests/ui/implicit_hasher.rs | 24 + tests/ui/implicit_hasher.stderr | 30 +- tests/ui/missing_doc.rs | 148 --- tests/ui/missing_doc.stderr | 102 -- tests/ui/missing_doc_crate.rs | 7 - tests/ui/missing_doc_crate_missing.rs | 4 - tests/ui/missing_doc_crate_missing.stderr | 13 - tests/ui/missing_doc_impl.rs | 114 -- tests/ui/missing_doc_impl.stderr | 57 - tests/ui/multiple_unsafe_ops_per_block.rs | 103 ++ tests/ui/multiple_unsafe_ops_per_block.stderr | 148 ++- .../redundant_pattern_matching_option.fixed | 29 + tests/ui/redundant_pattern_matching_option.rs | 29 + .../redundant_pattern_matching_option.stderr | 14 +- tests/ui/sliced_string_as_bytes.fixed | 6 + tests/ui/sliced_string_as_bytes.rs | 6 + tests/ui/transmute.rs | 13 + tests/ui/transmute.stderr | 8 +- tests/ui/transmute_ref_to_ref.rs | 20 + tests/ui/transmute_ref_to_ref.stderr | 20 +- tests/ui/unchecked_time_subtraction.stderr | 16 +- ...nchecked_time_subtraction_unfixable.stderr | 8 +- tests/ui/useless_asref.fixed | 35 + tests/ui/useless_asref.rs | 35 + tests/ui/useless_asref.stderr | 32 +- tests/ui/{vec.fixed => useless_vec.fixed} | 38 +- tests/ui/useless_vec.rs | 258 +++- tests/ui/useless_vec.stderr | 132 +- tests/ui/useless_vec_unfixable.rs | 14 + tests/ui/useless_vec_unfixable.stderr | 21 + tests/ui/vec.rs | 253 ---- tests/ui/vec.stderr | 137 -- triagebot.toml | 3 +- util/gh-pages/index_template.html | 216 ++- util/gh-pages/style.css | 79 +- 113 files changed, 6904 insertions(+), 2322 deletions(-) create mode 100644 clippy_lints/src/doc/doc_paragraphs_missing_punctuation.rs rename clippy_lints/src/{vec.rs => useless_vec.rs} (90%) delete mode 100644 tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs delete mode 100644 tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr rename tests/ui-toml/{missing_docs_allow_unused => missing_docs_in_private_items/allow_unused}/clippy.toml (100%) rename tests/ui-toml/{pub_crate_missing_docs => missing_docs_in_private_items/crate_root}/clippy.toml (100%) create mode 100644 tests/ui-toml/missing_docs_in_private_items/default/clippy.toml create mode 100644 tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.allow_unused.stderr create mode 100644 tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.crate_root.stderr create mode 100644 tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.default.stderr create mode 100644 tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs delete mode 100644 tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs delete mode 100644 tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr create mode 100644 tests/ui/doc/doc_paragraphs_missing_punctuation.fixed create mode 100644 tests/ui/doc/doc_paragraphs_missing_punctuation.rs create mode 100644 tests/ui/doc/doc_paragraphs_missing_punctuation.stderr create mode 100644 tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.rs create mode 100644 tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.stderr create mode 100644 tests/ui/equatable_if_let_const_cmp.fixed create mode 100644 tests/ui/equatable_if_let_const_cmp.rs create mode 100644 tests/ui/equatable_if_let_const_cmp.stderr delete mode 100644 tests/ui/missing_doc.rs delete mode 100644 tests/ui/missing_doc.stderr delete mode 100644 tests/ui/missing_doc_crate.rs delete mode 100644 tests/ui/missing_doc_crate_missing.rs delete mode 100644 tests/ui/missing_doc_crate_missing.stderr delete mode 100644 tests/ui/missing_doc_impl.rs delete mode 100644 tests/ui/missing_doc_impl.stderr rename tests/ui/{vec.fixed => useless_vec.fixed} (90%) create mode 100644 tests/ui/useless_vec_unfixable.rs create mode 100644 tests/ui/useless_vec_unfixable.stderr delete mode 100644 tests/ui/vec.rs delete mode 100644 tests/ui/vec.stderr diff --git a/.github/workflows/clippy_mq.yml b/.github/workflows/clippy_mq.yml index ce15a861bb07..c49241bdff1b 100644 --- a/.github/workflows/clippy_mq.yml +++ b/.github/workflows/clippy_mq.yml @@ -34,7 +34,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false @@ -94,7 +94,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false @@ -112,7 +112,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false @@ -168,7 +168,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false @@ -179,7 +179,7 @@ jobs: # Download - name: Download target dir - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: name: binaries path: target/debug diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 48c5bd36dbcd..872931160c35 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -25,13 +25,13 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ env.TARGET_BRANCH }} path: 'out' diff --git a/.github/workflows/lintcheck.yml b/.github/workflows/lintcheck.yml index 45fd10ae7614..9ce0b7f5fc46 100644 --- a/.github/workflows/lintcheck.yml +++ b/.github/workflows/lintcheck.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 2 # Unsetting this would make so that any malicious package could get our Github Token @@ -80,7 +80,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false @@ -113,7 +113,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index c2cc48ab9511..03641a9aa62f 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -4,6 +4,9 @@ on: merge_group: pull_request: +env: + MDBOOK_VERSION: 0.5.1 + jobs: remark: runs-on: ubuntu-latest @@ -11,7 +14,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false @@ -27,7 +30,7 @@ jobs: - name: Install mdbook run: | mkdir mdbook - curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.43/mdbook-v0.4.43-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook + curl -Lf https://github.com/rust-lang/mdBook/releases/download/v${MDBOOK_VERSION}/mdbook-v${MDBOOK_VERSION}-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook echo `pwd`/mdbook >> $GITHUB_PATH # Run diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cb2755be0ee..78b81b5b74d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6314,6 +6314,7 @@ Released 2018-09-13 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown [`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs [`doc_overindented_list_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_overindented_list_items +[`doc_paragraphs_missing_punctuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_paragraphs_missing_punctuation [`doc_suspicious_footnotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_suspicious_footnotes [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons [`double_ended_iterator_last`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_ended_iterator_last @@ -7121,6 +7122,7 @@ Released 2018-09-13 [`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold [`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability [`inherent-impl-lint-scope`]: https://doc.rust-lang.org/clippy/lint_configuration.html#inherent-impl-lint-scope +[`large-error-ignored`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-ignored [`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold [`lint-commented-code`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-commented-code [`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold diff --git a/book/src/continuous_integration/github_actions.md b/book/src/continuous_integration/github_actions.md index 62d32446d920..bed0f66bab33 100644 --- a/book/src/continuous_integration/github_actions.md +++ b/book/src/continuous_integration/github_actions.md @@ -15,7 +15,7 @@ jobs: clippy_check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Run Clippy run: cargo clippy --all-targets --all-features ``` diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 6569bdabf115..2e185fb3a086 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -681,6 +681,17 @@ Sets the scope ("crate", "file", or "module") in which duplicate inherent `impl` * [`multiple_inherent_impl`](https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl) +## `large-error-ignored` +A list of paths to types that should be ignored as overly large `Err`-variants in a +`Result` returned from a function + +**Default Value:** `[]` + +--- +**Affected lints:** +* [`result_large_err`](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err) + + ## `large-error-threshold` The maximum size of the `Err`-variant in a `Result` returned from a function diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 8cdd99ac44a8..2e9cf8e91f7d 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -666,6 +666,10 @@ fn span_from_toml_range(file: &SourceFile, span: Range) -> Span { /// Sets the scope ("crate", "file", or "module") in which duplicate inherent `impl` blocks for the same type are linted. #[lints(multiple_inherent_impl)] inherent_impl_lint_scope: InherentImplLintScope = InherentImplLintScope::Crate, + /// A list of paths to types that should be ignored as overly large `Err`-variants in a + /// `Result` returned from a function + #[lints(result_large_err)] + large_error_ignored: Vec = Vec::default(), /// The maximum size of the `Err`-variant in a `Result` returned from a function #[lints(result_large_err)] large_error_threshold: u64 = 128, diff --git a/clippy_lints/src/byte_char_slices.rs b/clippy_lints/src/byte_char_slices.rs index d88c0711b397..fc9931439e93 100644 --- a/clippy_lints/src/byte_char_slices.rs +++ b/clippy_lints/src/byte_char_slices.rs @@ -31,8 +31,8 @@ impl EarlyLintPass for ByteCharSlice { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if let Some(slice) = is_byte_char_slices(expr) - && !expr.span.from_expansion() + if !expr.span.from_expansion() + && let Some(slice) = is_byte_char_slices(expr) { span_lint_and_sugg( cx, @@ -47,33 +47,28 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { } } +/// Checks whether the slice is that of byte chars, and if so, builds a byte-string out of it fn is_byte_char_slices(expr: &Expr) -> Option { - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = &expr.kind { - match &expr.kind { - ExprKind::Array(members) => { - if members.is_empty() { - return None; - } - - members - .iter() - .map(|member| match &member.kind { - ExprKind::Lit(Lit { - kind: LitKind::Byte, - symbol, - .. - }) => Some(symbol.as_str()), - _ => None, - }) - .map(|maybe_quote| match maybe_quote { - Some("\"") => Some("\\\""), - Some("\\'") => Some("'"), - other => other, - }) - .collect::>() - }, - _ => None, - } + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = &expr.kind + && let ExprKind::Array(members) = &expr.kind + && !members.is_empty() + { + members + .iter() + .map(|member| match &member.kind { + ExprKind::Lit(Lit { + kind: LitKind::Byte, + symbol, + .. + }) => Some(symbol.as_str()), + _ => None, + }) + .map(|maybe_quote| match maybe_quote { + Some("\"") => Some("\\\""), + Some("\\'") => Some("'"), + other => other, + }) + .collect::>() } else { None } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index a754eea31165..4a350dca2993 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -118,6 +118,7 @@ crate::doc::DOC_MARKDOWN_INFO, crate::doc::DOC_NESTED_REFDEFS_INFO, crate::doc::DOC_OVERINDENTED_LIST_ITEMS_INFO, + crate::doc::DOC_PARAGRAPHS_MISSING_PUNCTUATION_INFO, crate::doc::DOC_SUSPICIOUS_FOOTNOTES_INFO, crate::doc::EMPTY_DOCS_INFO, crate::doc::MISSING_ERRORS_DOC_INFO, @@ -777,7 +778,7 @@ crate::use_self::USE_SELF_INFO, crate::useless_concat::USELESS_CONCAT_INFO, crate::useless_conversion::USELESS_CONVERSION_INFO, - crate::vec::USELESS_VEC_INFO, + crate::useless_vec::USELESS_VEC_INFO, crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO, crate::visibility::NEEDLESS_PUB_SELF_INFO, crate::visibility::PUB_WITHOUT_SHORTHAND_INFO, diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 548f03c9f205..32fd4afb122e 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -12,8 +12,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty}; use rustc_hir::{ - self as hir, AmbigArg, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, - Pat, PatKind, Path, QPath, TyKind, UnOp, + self as hir, AmbigArg, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Item, MatchSource, Mutability, + Node, OwnerId, Pat, PatKind, Path, QPath, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; @@ -27,6 +27,8 @@ /// ### What it does /// Checks for explicit `deref()` or `deref_mut()` method calls. /// + /// Doesn't lint inside the implementation of the `Deref` or `DerefMut` traits. + /// /// ### Why is this bad? /// Dereferencing by `&*x` or `&mut *x` is clearer and more concise, /// when not part of a method chain. @@ -169,6 +171,10 @@ pub struct Dereferencing<'tcx> { /// /// e.g. `m!(x) | Foo::Bar(ref x)` ref_locals: FxIndexMap>, + + /// The outermost `impl Deref` we're currently in. While we're in one, + /// `explicit_deref_methods` is deactivated + outermost_deref_impl: Option, } #[derive(Debug)] @@ -246,7 +252,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // Stop processing sub expressions when a macro call is seen if expr.span.from_expansion() { if let Some((state, data)) = self.state.take() { - report(cx, expr, state, data, cx.typeck_results()); + self.report(cx, expr, state, data, cx.typeck_results()); } return; } @@ -255,7 +261,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let Some((kind, sub_expr, skip_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else { // The whole chain of reference operations has been seen if let Some((state, data)) = self.state.take() { - report(cx, expr, state, data, typeck); + self.report(cx, expr, state, data, typeck); } return; }; @@ -263,7 +269,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if is_from_proc_macro(cx, expr) { if let Some((state, data)) = self.state.take() { - report(cx, expr, state, data, cx.typeck_results()); + self.report(cx, expr, state, data, cx.typeck_results()); } return; } @@ -515,7 +521,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => { let adjusted_ty = data.adjusted_ty; let stability = state.stability; - report(cx, expr, State::DerefedBorrow(state), data, typeck); + self.report(cx, expr, State::DerefedBorrow(state), data, typeck); if stability.is_deref_stable() { self.state = Some(( State::Borrow { mutability }, @@ -530,7 +536,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let adjusted_ty = data.adjusted_ty; let stability = state.stability; let for_field_access = state.for_field_access; - report(cx, expr, State::DerefedBorrow(state), data, typeck); + self.report(cx, expr, State::DerefedBorrow(state), data, typeck); if let Some(name) = for_field_access && let sub_expr_ty = typeck.expr_ty(sub_expr) && !ty_contains_field(sub_expr_ty, name) @@ -602,7 +608,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { )); }, - (Some((state, data)), _) => report(cx, expr, state, data, typeck), + (Some((state, data)), _) => self.report(cx, expr, state, data, typeck), } } @@ -673,6 +679,31 @@ fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &Body<'_>) { self.current_body = None; } } + + fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + // Only check for `impl Deref(Mut)`s if we're not already in one + if !self.in_deref_impl() && is_deref_or_derefmut_impl(cx, item) { + self.outermost_deref_impl = Some(item.owner_id); + } + } + + fn check_item_post(&mut self, _cx: &LateContext<'_>, item: &Item<'_>) { + // Only clear `self.outermost_deref_impl` if we're escaping the _outermost_ `impl Deref(Mut)` + if self.outermost_deref_impl == Some(item.owner_id) { + self.outermost_deref_impl = None; + } + } +} + +fn is_deref_or_derefmut_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool { + if let hir::ItemKind::Impl(impl_) = item.kind + && let Some(of_trait) = impl_.of_trait + && let Some(trait_id) = of_trait.trait_ref.trait_def_id() + { + cx.tcx.lang_items().deref_trait() == Some(trait_id) || cx.tcx.lang_items().deref_mut_trait() == Some(trait_id) + } else { + false + } } fn try_parse_ref_op<'tcx>( @@ -930,209 +961,11 @@ fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool { } } -#[expect(clippy::needless_pass_by_value, clippy::too_many_lines)] -fn report<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'_>, - state: State, - data: StateData<'tcx>, - typeck: &'tcx TypeckResults<'tcx>, -) { - match state { - State::DerefMethod { - ty_changed_count, - is_ufcs, - mutbl, - } => { - let mut app = Applicability::MachineApplicable; - let (expr_str, expr_is_macro_call) = - snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); - let ty = typeck.expr_ty(expr); - let (_, ref_count, _) = peel_and_count_ty_refs(ty); - let deref_str = if ty_changed_count >= ref_count && ref_count != 0 { - // a deref call changing &T -> &U requires two deref operators the first time - // this occurs. One to remove the reference, a second to call the deref impl. - "*".repeat(ty_changed_count + 1) - } else { - "*".repeat(ty_changed_count) - }; - let addr_of_str = if ty_changed_count < ref_count { - // Check if a reborrow from &mut T -> &T is required. - if mutbl == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) { - "&*" - } else { - "" - } - } else if mutbl == Mutability::Mut { - "&mut " - } else { - "&" - }; - - let expr_str = if !expr_is_macro_call && is_ufcs && cx.precedence(expr) < ExprPrecedence::Prefix { - Cow::Owned(format!("({expr_str})")) - } else { - expr_str - }; - - span_lint_and_sugg( - cx, - EXPLICIT_DEREF_METHODS, - data.first_expr.span, - match mutbl { - Mutability::Not => "explicit `deref` method call", - Mutability::Mut => "explicit `deref_mut` method call", - }, - "try", - format!("{addr_of_str}{deref_str}{expr_str}"), - app, - ); - }, - State::DerefedBorrow(state) => { - // Do not suggest removing a non-mandatory `&` in `&*rawptr` in an `unsafe` context, - // as this may make rustc trigger its `dangerous_implicit_autorefs` lint. - if let ExprKind::AddrOf(BorrowKind::Ref, _, subexpr) = data.first_expr.kind - && let ExprKind::Unary(UnOp::Deref, subsubexpr) = subexpr.kind - && cx.typeck_results().expr_ty_adjusted(subsubexpr).is_raw_ptr() - { - return; - } - - let mut app = Applicability::MachineApplicable; - let (snip, snip_is_macro) = - snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); - span_lint_hir_and_then( - cx, - NEEDLESS_BORROW, - data.first_expr.hir_id, - data.first_expr.span, - state.msg, - |diag| { - let needs_paren = match cx.tcx.parent_hir_node(data.first_expr.hir_id) { - Node::Expr(e) => match e.kind { - ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => false, - ExprKind::Call(..) => { - cx.precedence(expr) < ExprPrecedence::Unambiguous - || matches!(expr.kind, ExprKind::Field(..)) - }, - _ => cx.precedence(expr) < cx.precedence(e), - }, - _ => false, - }; - let is_in_tuple = matches!( - get_parent_expr(cx, data.first_expr), - Some(Expr { - kind: ExprKind::Tup(..), - .. - }) - ); - - let sugg = if !snip_is_macro && needs_paren && !has_enclosing_paren(&snip) && !is_in_tuple { - format!("({snip})") - } else { - snip.into() - }; - diag.span_suggestion(data.first_expr.span, "change this to", sugg, app); - }, - ); - }, - State::ExplicitDeref { mutability } => { - if is_block_like(expr) - && let ty::Ref(_, ty, _) = data.adjusted_ty.kind() - && ty.is_sized(cx.tcx, cx.typing_env()) - { - // Rustc bug: auto deref doesn't work on block expression when targeting sized types. - return; - } - - let ty = typeck.expr_ty(expr); - - // `&&[T; N]`, or `&&..&[T; N]` (src) cannot coerce to `&[T]` (dst). - if let ty::Ref(_, dst, _) = data.adjusted_ty.kind() - && dst.is_slice() - { - let (src, n_src_refs, _) = peel_and_count_ty_refs(ty); - if n_src_refs >= 2 && src.is_array() { - return; - } - } - - let (prefix, needs_paren) = match mutability { - Some(mutability) if !ty.is_ref() => { - let prefix = match mutability { - Mutability::Not => "&", - Mutability::Mut => "&mut ", - }; - (prefix, cx.precedence(expr) < ExprPrecedence::Prefix) - }, - None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", false), - _ => ("", false), - }; - span_lint_hir_and_then( - cx, - EXPLICIT_AUTO_DEREF, - data.first_expr.hir_id, - data.first_expr.span, - "deref which would be done by auto-deref", - |diag| { - let mut app = Applicability::MachineApplicable; - let (snip, snip_is_macro) = - snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); - let sugg = if !snip_is_macro && needs_paren && !has_enclosing_paren(&snip) { - format!("{prefix}({snip})") - } else { - format!("{prefix}{snip}") - }; - diag.span_suggestion(data.first_expr.span, "try", sugg, app); - }, - ); - }, - State::ExplicitDerefField { - derefs_manually_drop, .. - } => { - let (snip_span, needs_parens) = if matches!(expr.kind, ExprKind::Field(..)) - && (derefs_manually_drop - || adjust_derefs_manually_drop( - typeck.expr_adjustments(data.first_expr), - typeck.expr_ty(data.first_expr), - )) { - // `DerefMut` will not be automatically applied to `ManuallyDrop<_>` - // field expressions when the base type is a union and the parent - // expression is also a field access. - // - // e.g. `&mut x.y.z` where `x` is a union, and accessing `z` requires a - // deref through `ManuallyDrop<_>` will not compile. - let parent_id = cx.tcx.parent_hir_id(expr.hir_id); - if parent_id == data.first_expr.hir_id { - return; - } - (cx.tcx.hir_node(parent_id).expect_expr().span, true) - } else { - (expr.span, false) - }; - span_lint_hir_and_then( - cx, - EXPLICIT_AUTO_DEREF, - data.first_expr.hir_id, - data.first_expr.span, - "deref which would be done by auto-deref", - |diag| { - let mut app = Applicability::MachineApplicable; - let snip = snippet_with_context(cx, snip_span, data.first_expr.span.ctxt(), "..", &mut app).0; - let sugg = if needs_parens { - format!("({snip})") - } else { - snip.into_owned() - }; - diag.span_suggestion(data.first_expr.span, "try", sugg, app); - }, - ); - }, - State::Borrow { .. } | State::Reborrow { .. } => (), - } -} - impl<'tcx> Dereferencing<'tcx> { + fn in_deref_impl(&self) -> bool { + self.outermost_deref_impl.is_some() + } + fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &Expr<'tcx>, local: HirId) { if let Some(outer_pat) = self.ref_locals.get_mut(&local) && let Some(pat) = outer_pat @@ -1191,4 +1024,211 @@ fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &Expr<'tcx>, local: H } } } + + #[expect(clippy::needless_pass_by_value, clippy::too_many_lines)] + fn report( + &self, + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + state: State, + data: StateData<'tcx>, + typeck: &'tcx TypeckResults<'tcx>, + ) { + match state { + State::DerefMethod { + ty_changed_count, + is_ufcs, + mutbl, + } => { + if self.in_deref_impl() { + // `deref(_mut)` is fine in an `impl Deref(Mut)` + return; + } + let mut app = Applicability::MachineApplicable; + let (expr_str, expr_is_macro_call) = + snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); + let ty = typeck.expr_ty(expr); + let (_, ref_count, _) = peel_and_count_ty_refs(ty); + let deref_str = if ty_changed_count >= ref_count && ref_count != 0 { + // a deref call changing &T -> &U requires two deref operators the first time + // this occurs. One to remove the reference, a second to call the deref impl. + "*".repeat(ty_changed_count + 1) + } else { + "*".repeat(ty_changed_count) + }; + let addr_of_str = if ty_changed_count < ref_count { + // Check if a reborrow from &mut T -> &T is required. + if mutbl == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) { + "&*" + } else { + "" + } + } else if mutbl == Mutability::Mut { + "&mut " + } else { + "&" + }; + + let expr_str = if !expr_is_macro_call && is_ufcs && cx.precedence(expr) < ExprPrecedence::Prefix { + Cow::Owned(format!("({expr_str})")) + } else { + expr_str + }; + + span_lint_and_sugg( + cx, + EXPLICIT_DEREF_METHODS, + data.first_expr.span, + match mutbl { + Mutability::Not => "explicit `deref` method call", + Mutability::Mut => "explicit `deref_mut` method call", + }, + "try", + format!("{addr_of_str}{deref_str}{expr_str}"), + app, + ); + }, + State::DerefedBorrow(state) => { + // Do not suggest removing a non-mandatory `&` in `&*rawptr` in an `unsafe` context, + // as this may make rustc trigger its `dangerous_implicit_autorefs` lint. + if let ExprKind::AddrOf(BorrowKind::Ref, _, subexpr) = data.first_expr.kind + && let ExprKind::Unary(UnOp::Deref, subsubexpr) = subexpr.kind + && cx.typeck_results().expr_ty_adjusted(subsubexpr).is_raw_ptr() + { + return; + } + + let mut app = Applicability::MachineApplicable; + let (snip, snip_is_macro) = + snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); + span_lint_hir_and_then( + cx, + NEEDLESS_BORROW, + data.first_expr.hir_id, + data.first_expr.span, + state.msg, + |diag| { + let needs_paren = match cx.tcx.parent_hir_node(data.first_expr.hir_id) { + Node::Expr(e) => match e.kind { + ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => false, + ExprKind::Call(..) => { + cx.precedence(expr) < ExprPrecedence::Unambiguous + || matches!(expr.kind, ExprKind::Field(..)) + }, + _ => cx.precedence(expr) < cx.precedence(e), + }, + _ => false, + }; + let is_in_tuple = matches!( + get_parent_expr(cx, data.first_expr), + Some(Expr { + kind: ExprKind::Tup(..), + .. + }) + ); + + let sugg = if !snip_is_macro && needs_paren && !has_enclosing_paren(&snip) && !is_in_tuple { + format!("({snip})") + } else { + snip.into() + }; + diag.span_suggestion(data.first_expr.span, "change this to", sugg, app); + }, + ); + }, + State::ExplicitDeref { mutability } => { + if is_block_like(expr) + && let ty::Ref(_, ty, _) = data.adjusted_ty.kind() + && ty.is_sized(cx.tcx, cx.typing_env()) + { + // Rustc bug: auto deref doesn't work on block expression when targeting sized types. + return; + } + + let ty = typeck.expr_ty(expr); + + // `&&[T; N]`, or `&&..&[T; N]` (src) cannot coerce to `&[T]` (dst). + if let ty::Ref(_, dst, _) = data.adjusted_ty.kind() + && dst.is_slice() + { + let (src, n_src_refs, _) = peel_and_count_ty_refs(ty); + if n_src_refs >= 2 && src.is_array() { + return; + } + } + + let (prefix, needs_paren) = match mutability { + Some(mutability) if !ty.is_ref() => { + let prefix = match mutability { + Mutability::Not => "&", + Mutability::Mut => "&mut ", + }; + (prefix, cx.precedence(expr) < ExprPrecedence::Prefix) + }, + None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", false), + _ => ("", false), + }; + span_lint_hir_and_then( + cx, + EXPLICIT_AUTO_DEREF, + data.first_expr.hir_id, + data.first_expr.span, + "deref which would be done by auto-deref", + |diag| { + let mut app = Applicability::MachineApplicable; + let (snip, snip_is_macro) = + snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); + let sugg = if !snip_is_macro && needs_paren && !has_enclosing_paren(&snip) { + format!("{prefix}({snip})") + } else { + format!("{prefix}{snip}") + }; + diag.span_suggestion(data.first_expr.span, "try", sugg, app); + }, + ); + }, + State::ExplicitDerefField { + derefs_manually_drop, .. + } => { + let (snip_span, needs_parens) = if matches!(expr.kind, ExprKind::Field(..)) + && (derefs_manually_drop + || adjust_derefs_manually_drop( + typeck.expr_adjustments(data.first_expr), + typeck.expr_ty(data.first_expr), + )) { + // `DerefMut` will not be automatically applied to `ManuallyDrop<_>` + // field expressions when the base type is a union and the parent + // expression is also a field access. + // + // e.g. `&mut x.y.z` where `x` is a union, and accessing `z` requires a + // deref through `ManuallyDrop<_>` will not compile. + let parent_id = cx.tcx.parent_hir_id(expr.hir_id); + if parent_id == data.first_expr.hir_id { + return; + } + (cx.tcx.hir_node(parent_id).expect_expr().span, true) + } else { + (expr.span, false) + }; + span_lint_hir_and_then( + cx, + EXPLICIT_AUTO_DEREF, + data.first_expr.hir_id, + data.first_expr.span, + "deref which would be done by auto-deref", + |diag| { + let mut app = Applicability::MachineApplicable; + let snip = snippet_with_context(cx, snip_span, data.first_expr.span.ctxt(), "..", &mut app).0; + let sugg = if needs_parens { + format!("({snip})") + } else { + snip.into_owned() + }; + diag.span_suggestion(data.first_expr.span, "try", sugg, app); + }, + ); + }, + State::Borrow { .. } | State::Reborrow { .. } => (), + } + } } diff --git a/clippy_lints/src/doc/doc_paragraphs_missing_punctuation.rs b/clippy_lints/src/doc/doc_paragraphs_missing_punctuation.rs new file mode 100644 index 000000000000..a8f734637672 --- /dev/null +++ b/clippy_lints/src/doc/doc_paragraphs_missing_punctuation.rs @@ -0,0 +1,126 @@ +use rustc_errors::Applicability; +use rustc_lint::LateContext; +use rustc_resolve::rustdoc::main_body_opts; + +use rustc_resolve::rustdoc::pulldown_cmark::{Event, Options, Parser, Tag, TagEnd}; + +use super::{DOC_PARAGRAPHS_MISSING_PUNCTUATION, Fragments}; + +const MSG: &str = "doc paragraphs should end with a terminal punctuation mark"; +const PUNCTUATION_SUGGESTION: char = '.'; + +pub fn check(cx: &LateContext<'_>, doc: &str, fragments: Fragments<'_>) { + for missing_punctuation in is_missing_punctuation(doc) { + match missing_punctuation { + MissingPunctuation::Fixable(offset) => { + // This ignores `#[doc]` attributes, which we do not handle. + if let Some(span) = fragments.span(cx, offset..offset) { + clippy_utils::diagnostics::span_lint_and_sugg( + cx, + DOC_PARAGRAPHS_MISSING_PUNCTUATION, + span, + MSG, + "end the paragraph with some punctuation", + PUNCTUATION_SUGGESTION.to_string(), + Applicability::MaybeIncorrect, + ); + } + }, + MissingPunctuation::Unfixable(offset) => { + // This ignores `#[doc]` attributes, which we do not handle. + if let Some(span) = fragments.span(cx, offset..offset) { + clippy_utils::diagnostics::span_lint_and_help( + cx, + DOC_PARAGRAPHS_MISSING_PUNCTUATION, + span, + MSG, + None, + "end the paragraph with some punctuation", + ); + } + }, + } + } +} + +#[must_use] +/// If punctuation is missing, returns the offset where new punctuation should be inserted. +fn is_missing_punctuation(doc_string: &str) -> Vec { + // The colon is not exactly a terminal punctuation mark, but this is required for paragraphs that + // introduce a table or a list for example. + const TERMINAL_PUNCTUATION_MARKS: &[char] = &['.', '?', '!', '…', ':']; + + let mut no_report_depth = 0; + let mut missing_punctuation = Vec::new(); + let mut current_paragraph = None; + + for (event, offset) in + Parser::new_ext(doc_string, main_body_opts() - Options::ENABLE_SMART_PUNCTUATION).into_offset_iter() + { + match event { + Event::Start( + Tag::CodeBlock(..) + | Tag::FootnoteDefinition(_) + | Tag::Heading { .. } + | Tag::HtmlBlock + | Tag::List(..) + | Tag::Table(_), + ) => { + no_report_depth += 1; + }, + Event::End(TagEnd::FootnoteDefinition) => { + no_report_depth -= 1; + }, + Event::End( + TagEnd::CodeBlock | TagEnd::Heading(_) | TagEnd::HtmlBlock | TagEnd::List(_) | TagEnd::Table, + ) => { + no_report_depth -= 1; + current_paragraph = None; + }, + Event::InlineHtml(_) | Event::Start(Tag::Image { .. }) | Event::End(TagEnd::Image) => { + current_paragraph = None; + }, + Event::End(TagEnd::Paragraph) => { + if let Some(mp) = current_paragraph { + missing_punctuation.push(mp); + } + }, + Event::Code(..) | Event::Start(Tag::Link { .. }) | Event::End(TagEnd::Link) + if no_report_depth == 0 && !offset.is_empty() => + { + if doc_string[..offset.end] + .trim_end() + .ends_with(TERMINAL_PUNCTUATION_MARKS) + { + current_paragraph = None; + } else { + current_paragraph = Some(MissingPunctuation::Fixable(offset.end)); + } + }, + Event::Text(..) if no_report_depth == 0 && !offset.is_empty() => { + let trimmed = doc_string[..offset.end].trim_end(); + if trimmed.ends_with(TERMINAL_PUNCTUATION_MARKS) { + current_paragraph = None; + } else if let Some(t) = trimmed.strip_suffix(|c| c == ')' || c == '"') { + if t.ends_with(TERMINAL_PUNCTUATION_MARKS) { + // Avoid false positives. + current_paragraph = None; + } else { + current_paragraph = Some(MissingPunctuation::Unfixable(offset.end)); + } + } else { + current_paragraph = Some(MissingPunctuation::Fixable(offset.end)); + } + }, + _ => {}, + } + } + + missing_punctuation +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum MissingPunctuation { + Fixable(usize), + Unfixable(usize), +} diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 1e1d6e69cc91..120da92da944 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -27,6 +27,7 @@ mod broken_link; mod doc_comment_double_space_linebreaks; +mod doc_paragraphs_missing_punctuation; mod doc_suspicious_footnotes; mod include_in_doc_without_cfg; mod lazy_continuation; @@ -670,6 +671,33 @@ "looks like a link or footnote ref, but with no definition" } +declare_clippy_lint! { + /// ### What it does + /// Checks for doc comments whose paragraphs do not end with a period or another punctuation mark. + /// Various Markdowns constructs are taken into account to avoid false positives. + /// + /// ### Why is this bad? + /// A project may wish to enforce consistent doc comments by making sure paragraphs end with a + /// punctuation mark. + /// + /// ### Example + /// ```no_run + /// /// Returns a random number + /// /// + /// /// It was chosen by a fair dice roll + /// ``` + /// Use instead: + /// ```no_run + /// /// Returns a random number. + /// /// + /// /// It was chosen by a fair dice roll. + /// ``` + #[clippy::version = "1.93.0"] + pub DOC_PARAGRAPHS_MISSING_PUNCTUATION, + restriction, + "missing terminal punctuation in doc comments" +} + pub struct Documentation { valid_idents: FxHashSet, check_private_items: bool, @@ -704,6 +732,7 @@ pub fn new(conf: &'static Conf) -> Self { DOC_INCLUDE_WITHOUT_CFG, DOC_COMMENT_DOUBLE_SPACE_LINEBREAKS, DOC_SUSPICIOUS_FOOTNOTES, + DOC_PARAGRAPHS_MISSING_PUNCTUATION, ]); impl EarlyLintPass for Documentation { @@ -875,6 +904,15 @@ fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowSt }, ); + doc_paragraphs_missing_punctuation::check( + cx, + &doc, + Fragments { + doc: &doc, + fragments: &fragments, + }, + ); + // NOTE: check_doc uses it own cb function, // to avoid causing duplicated diagnostics for the broken link checker. let mut full_fake_broken_link_callback = |bl: BrokenLink<'_>| -> Option<(CowStr<'_>, CowStr<'_>)> { diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index 9b5cd7e1731f..a92bfd45df0c 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -1,4 +1,5 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_in_const_context; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; @@ -40,9 +41,9 @@ declare_lint_pass!(PatternEquality => [EQUATABLE_IF_LET]); /// detects if pattern matches just one thing -fn unary_pattern(pat: &Pat<'_>) -> bool { +fn is_unary_pattern(pat: &Pat<'_>) -> bool { fn array_rec(pats: &[Pat<'_>]) -> bool { - pats.iter().all(unary_pattern) + pats.iter().all(is_unary_pattern) } match &pat.kind { PatKind::Missing => unreachable!(), @@ -53,9 +54,9 @@ fn array_rec(pats: &[Pat<'_>]) -> bool { | PatKind::Never | PatKind::Or(_) | PatKind::Err(_) => false, - PatKind::Struct(_, a, etc) => etc.is_none() && a.iter().all(|x| unary_pattern(x.pat)), + PatKind::Struct(_, a, etc) => etc.is_none() && a.iter().all(|x| is_unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), - PatKind::Ref(x, _, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x), + PatKind::Ref(x, _, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => is_unary_pattern(x), PatKind::Expr(_) => true, } } @@ -103,48 +104,63 @@ fn contains_type_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { impl<'tcx> LateLintPass<'tcx> for PatternEquality { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::Let(let_expr) = expr.kind - && unary_pattern(let_expr.pat) + && is_unary_pattern(let_expr.pat) && !expr.span.in_external_macro(cx.sess().source_map()) + && !let_expr.pat.span.from_expansion() + && !let_expr.init.span.from_expansion() { let exp_ty = cx.typeck_results().expr_ty(let_expr.init); let pat_ty = cx.typeck_results().pat_ty(let_expr.pat); - let mut applicability = Applicability::MachineApplicable; - if is_structural_partial_eq(cx, exp_ty, pat_ty) && !contains_type_mismatch(cx, let_expr.pat) { - let pat_str = match let_expr.pat.kind { - PatKind::Struct(..) => format!( - "({})", - snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0, - ), - _ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability) - .0 - .to_string(), - }; - span_lint_and_sugg( + let mut app = Applicability::MachineApplicable; + let ctxt = expr.span.ctxt(); + + if is_structural_partial_eq(cx, exp_ty, pat_ty) + && !contains_type_mismatch(cx, let_expr.pat) + // Calls to trait methods (`PartialEq::eq` in this case) aren't stable yet. We could _technically_ + // try looking at whether: + // 1) features `const_trait_impl` and `const_cmp` are enabled + // 2) implementation of `PartialEq for ExpTy` has `fn eq` that is `const` + // + // but that didn't quite work out (see #15482), so we just reject outright in this case + && !is_in_const_context(cx) + { + span_lint_and_then( cx, EQUATABLE_IF_LET, expr.span, "this pattern matching can be expressed using equality", - "try", - format!( - "{} == {pat_str}", - snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0, - ), - applicability, + |diag| { + let pat_str = { + let str = snippet_with_context(cx, let_expr.pat.span, ctxt, "..", &mut app).0; + if let PatKind::Struct(..) = let_expr.pat.kind { + format!("({str})").into() + } else { + str + } + }; + + let sugg = format!( + "{} == {pat_str}", + snippet_with_context(cx, let_expr.init.span, ctxt, "..", &mut app).0, + ); + diag.span_suggestion(expr.span, "try", sugg, app); + }, ); } else { - span_lint_and_sugg( + span_lint_and_then( cx, EQUATABLE_IF_LET, expr.span, "this pattern matching can be expressed using `matches!`", - "try", - format!( - "matches!({}, {})", - snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0, - snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0, - ), - applicability, + |diag| { + let sugg = format!( + "matches!({}, {})", + snippet_with_context(cx, let_expr.init.span, ctxt, "..", &mut app).0, + snippet_with_context(cx, let_expr.pat.span, ctxt, "..", &mut app).0, + ); + diag.span_suggestion(expr.span, "try", sugg, app); + }, ); } } diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 5a40af421942..bdc366f6878a 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -485,6 +485,7 @@ pub struct Functions { too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64, + large_error_ignored: DefIdSet, avoid_breaking_exported_api: bool, /// A set of resolved `def_id` of traits that are configured to allow /// function params renaming. @@ -498,6 +499,11 @@ pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { too_many_arguments_threshold: conf.too_many_arguments_threshold, too_many_lines_threshold: conf.too_many_lines_threshold, large_error_threshold: conf.large_error_threshold, + large_error_ignored: conf + .large_error_ignored + .iter() + .flat_map(|ignored_ty| lookup_path_str(tcx, PathNS::Type, ignored_ty)) + .collect(), avoid_breaking_exported_api: conf.avoid_breaking_exported_api, trait_ids: conf .allow_renamed_params_for @@ -554,12 +560,24 @@ fn check_fn( fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { must_use::check_item(cx, item); - result::check_item(cx, item, self.large_error_threshold, self.msrv); + result::check_item( + cx, + item, + self.large_error_threshold, + &self.large_error_ignored, + self.msrv, + ); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { must_use::check_impl_item(cx, item); - result::check_impl_item(cx, item, self.large_error_threshold, self.msrv); + result::check_impl_item( + cx, + item, + self.large_error_threshold, + &self.large_error_ignored, + self.msrv, + ); impl_trait_in_params::check_impl_item(cx, item); renamed_function_params::check_impl_item(cx, item, &self.trait_ids); } @@ -568,7 +586,13 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitIte too_many_arguments::check_trait_item(cx, item, self.too_many_arguments_threshold); not_unsafe_ptr_arg_deref::check_trait_item(cx, item); must_use::check_trait_item(cx, item); - result::check_trait_item(cx, item, self.large_error_threshold, self.msrv); + result::check_trait_item( + cx, + item, + self.large_error_threshold, + &self.large_error_ignored, + self.msrv, + ); impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api); ref_option::check_trait_item(cx, item, self.avoid_breaking_exported_api); } diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index fb80cc1a63a3..04e15a1d8a0e 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -4,6 +4,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::{self, Ty}; +use rustc_span::def_id::DefIdSet; use rustc_span::{Span, sym}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; @@ -35,7 +36,13 @@ fn result_err_ty<'tcx>( } } -pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64, msrv: Msrv) { +pub(super) fn check_item<'tcx>( + cx: &LateContext<'tcx>, + item: &hir::Item<'tcx>, + large_err_threshold: u64, + large_err_ignored: &DefIdSet, + msrv: Msrv, +) { if let hir::ItemKind::Fn { ref sig, .. } = item.kind && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span) { @@ -43,7 +50,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, l let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); check_result_unit_err(cx, err_ty, fn_header_span, msrv); } - check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored); } } @@ -51,6 +58,7 @@ pub(super) fn check_impl_item<'tcx>( cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64, + large_err_ignored: &DefIdSet, msrv: Msrv, ) { // Don't lint if method is a trait's implementation, we can't do anything about those @@ -62,7 +70,7 @@ pub(super) fn check_impl_item<'tcx>( let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); check_result_unit_err(cx, err_ty, fn_header_span, msrv); } - check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored); } } @@ -70,6 +78,7 @@ pub(super) fn check_trait_item<'tcx>( cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64, + large_err_ignored: &DefIdSet, msrv: Msrv, ) { if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { @@ -78,7 +87,7 @@ pub(super) fn check_trait_item<'tcx>( if cx.effective_visibilities.is_exported(item.owner_id.def_id) { check_result_unit_err(cx, err_ty, fn_header_span, msrv); } - check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored); } } } @@ -96,7 +105,18 @@ fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: S } } -fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) { +fn check_result_large_err<'tcx>( + cx: &LateContext<'tcx>, + err_ty: Ty<'tcx>, + hir_ty_span: Span, + large_err_threshold: u64, + large_err_ignored: &DefIdSet, +) { + if let ty::Adt(adt, _) = err_ty.kind() + && large_err_ignored.contains(&adt.did()) + { + return; + } if let ty::Adt(adt, subst) = err_ty.kind() && let Some(local_def_id) = adt.did().as_local() && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_def_id) diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index d2bc0b6d9935..638a08b096db 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -13,7 +13,7 @@ use rustc_span::Span; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet}; +use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet, snippet_with_context}; use clippy_utils::sym; declare_clippy_lint! { @@ -335,29 +335,29 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) { return; } - match (self.cx.tcx.get_diagnostic_name(ty_did), method.ident.name) { - (Some(sym::HashMap), sym::new) => { - self.suggestions.insert(e.span, "HashMap::default()".to_string()); + let container_name = match self.cx.tcx.get_diagnostic_name(ty_did) { + Some(sym::HashMap) => "HashMap", + Some(sym::HashSet) => "HashSet", + _ => return, + }; + + match method.ident.name { + sym::new => { + self.suggestions.insert(e.span, format!("{container_name}::default()")); }, - (Some(sym::HashMap), sym::with_capacity) => { - self.suggestions.insert( - e.span, - format!( - "HashMap::with_capacity_and_hasher({}, Default::default())", - snippet(self.cx, args[0].span, "capacity"), - ), + sym::with_capacity => { + let (arg_snippet, _) = snippet_with_context( + self.cx, + args[0].span, + e.span.ctxt(), + "..", + // We can throw-away the applicability here since the whole suggestion is + // marked as `MaybeIncorrect` later. + &mut Applicability::MaybeIncorrect, ); - }, - (Some(sym::HashSet), sym::new) => { - self.suggestions.insert(e.span, "HashSet::default()".to_string()); - }, - (Some(sym::HashSet), sym::with_capacity) => { self.suggestions.insert( e.span, - format!( - "HashSet::with_capacity_and_hasher({}, Default::default())", - snippet(self.cx, args[0].span, "capacity"), - ), + format!("{container_name}::with_capacity_and_hasher({arg_snippet}, Default::default())",), ); }, _ => {}, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4542105d3277..230d83dacc95 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -386,7 +386,7 @@ mod use_self; mod useless_concat; mod useless_conversion; -mod vec; +mod useless_vec; mod vec_init_then_push; mod visibility; mod volatile_composites; @@ -592,7 +592,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(move |_| Box::new(transmute::Transmute::new(conf))), Box::new(move |_| Box::new(cognitive_complexity::CognitiveComplexity::new(conf))), Box::new(move |_| Box::new(escape::BoxedLocal::new(conf))), - Box::new(move |_| Box::new(vec::UselessVec::new(conf))), + Box::new(move |_| Box::new(useless_vec::UselessVec::new(conf))), Box::new(move |_| Box::new(panic_unimplemented::PanicUnimplemented::new(conf))), Box::new(|_| Box::new(strings::StringLitAsBytes)), Box::new(|_| Box::new(derive::Derive)), diff --git a/clippy_lints/src/methods/sliced_string_as_bytes.rs b/clippy_lints/src/methods/sliced_string_as_bytes.rs index 4aff194923a6..fb124f3605b9 100644 --- a/clippy_lints/src/methods/sliced_string_as_bytes.rs +++ b/clippy_lints/src/methods/sliced_string_as_bytes.rs @@ -1,15 +1,21 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher; use clippy_utils::res::MaybeDef; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, LangItem, is_range_literal}; +use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; use super::SLICED_STRING_AS_BYTES; +/// Checks if `index` is any type of range except `RangeFull` (i.e. `..`) +fn is_bounded_range_literal(cx: &LateContext<'_>, index: &Expr<'_>) -> bool { + higher::Range::hir(cx, index).is_some_and(|range| Option::or(range.start, range.end).is_some()) +} + pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>) { if let ExprKind::Index(indexed, index, _) = recv.kind - && is_range_literal(index) + && is_bounded_range_literal(cx, index) && let ty = cx.typeck_results().expr_ty(indexed).peel_refs() && (ty.is_str() || ty.is_lang_item(cx, LangItem::String)) { diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index 972304d79e75..f852080d0f2a 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -4,7 +4,8 @@ use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs, should_call_clone_as_function}; use clippy_utils::{get_parent_expr, peel_blocks, strip_pat_refs}; use rustc_errors::Applicability; -use rustc_hir::{self as hir, LangItem}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{self as hir, LangItem, Node}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; @@ -69,14 +70,37 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: Symbo } } + // Add `*` derefs if the expr is used in a ctor, because automatic derefs don't apply in that case. + let deref = if rcv_depth > res_depth { + let parent = cx.tcx.parent_hir_node(expr.hir_id); + match parent { + Node::ExprField(_) => "*".repeat(rcv_depth - res_depth), + Node::Expr(parent) + if let hir::ExprKind::Call(func, _) = parent.kind + && let (_, Some(path)) = func.opt_res_path() + && matches!(path.res, Res::Def(DefKind::Ctor(_, _), _) | Res::SelfCtor(_)) => + { + "*".repeat(rcv_depth - res_depth) + }, + _ => String::new(), + } + } else { + String::new() + }; + let mut applicability = Applicability::MachineApplicable; + let suggestion = format!( + "{deref}{}", + snippet_with_applicability(cx, recvr.span, "..", &mut applicability) + ); + span_lint_and_sugg( cx, USELESS_ASREF, expr.span, format!("this call to `{call_name}` does nothing"), "try", - snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(), + suggestion, applicability, ); } diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 1c62caa1c827..ac221743cfd6 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -1,26 +1,18 @@ -// Note: More specifically this lint is largely inspired (aka copied) from -// *rustc*'s -// [`missing_doc`]. -// -// [`missing_doc`]: https://github.com/rust-lang/rust/blob/cf9cf7c923eb01146971429044f216a3ca905e06/compiler/rustc_lint/src/builtin.rs#L415 -// - use clippy_config::Conf; -use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_from_proc_macro; -use clippy_utils::source::SpanRangeExt; -use rustc_ast::ast::MetaItemInner; -use rustc_hir as hir; -use rustc_hir::Attribute; -use rustc_hir::def::DefKind; +use clippy_utils::{is_doc_hidden, is_from_proc_macro}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::LocalDefId; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::{AssocContainer, Visibility}; +use rustc_hir::{ + AttrArgs, Attribute, Body, BodyId, FieldDef, HirId, ImplItem, Item, ItemKind, Node, TraitItem, Variant, +}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::middle::privacy::Level; +use rustc_middle::ty::Visibility; use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; +use rustc_span::sym; use rustc_span::symbol::kw; -use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -37,24 +29,27 @@ "detects missing documentation for private members" } -macro_rules! note_prev_span_then_ret { - ($prev_span:expr, $span:expr) => {{ - $prev_span = Some($span); - return; - }}; -} - pub struct MissingDoc { /// Whether to **only** check for missing documentation in items visible within the current /// crate. For example, `pub(crate)` items. crate_items_only: bool, /// Whether to allow fields starting with an underscore to skip documentation requirements allow_unused: bool, - /// Stack of whether #[doc(hidden)] is set - /// at each level which has lint attributes. - doc_hidden_stack: Vec, - /// Used to keep tracking of the previous item, field or variants etc, to get the search span. - prev_span: Option, + /// The current number of modules since the crate root. + module_depth: u32, + macro_module_depth: u32, + /// The current level of the attribute stack. + attr_depth: u32, + /// What `attr_depth` level the first `doc(hidden)` attribute was seen. This is zero if the + /// attribute hasn't been seen. + doc_hidden_depth: u32, + /// What `attr_depth` level the first `automatically_derived` attribute was seen. This is zero + /// if the attribute hasn't been seen. + automatically_derived_depth: u32, + /// The id of the first body we've seen. + in_body: Option, + /// The module/crate id an item must be visible at to be linted. + require_visibility_at: Option, } impl MissingDoc { @@ -62,113 +57,45 @@ pub fn new(conf: &'static Conf) -> Self { Self { crate_items_only: conf.missing_docs_in_crate_items, allow_unused: conf.missing_docs_allow_unused, - doc_hidden_stack: vec![false], - prev_span: None, + module_depth: 0, + macro_module_depth: 0, + attr_depth: 0, + doc_hidden_depth: 0, + automatically_derived_depth: 0, + in_body: None, + require_visibility_at: None, } } - fn doc_hidden(&self) -> bool { - *self.doc_hidden_stack.last().expect("empty doc_hidden_stack") - } - - fn has_include(meta: Option<&[MetaItemInner]>) -> bool { - if let Some(list) = meta - && let Some(meta) = list.first() - && let Some(name) = meta.ident() - { - name.name == sym::include - } else { - false - } - } - - fn check_missing_docs_attrs( - &self, - cx: &LateContext<'_>, - def_id: LocalDefId, - attrs: &[Attribute], - sp: Span, - article: &'static str, - desc: &'static str, - ) { - // If we're building a test harness, then warning about - // documentation is probably not really relevant right now. - if cx.sess().opts.test { - return; + fn is_missing_docs(&self, cx: &LateContext<'_>, def_id: LocalDefId, hir_id: HirId) -> bool { + if cx.tcx.sess.opts.test { + return false; } - // `#[doc(hidden)]` disables missing_docs check. - if self.doc_hidden() { - return; + match cx.effective_visibilities.effective_vis(def_id) { + None if self.require_visibility_at.is_some() => return false, + None if self.crate_items_only && self.module_depth != 0 => return false, + // `missing_docs` lint uses `Reexported` because rustdoc doesn't render documentation + // for items without a reachable path. + Some(vis) if vis.is_public_at_level(Level::Reexported) => return false, + Some(vis) => { + if self.crate_items_only { + // Use the `Reachable` level since rustdoc will be able to render the documentation + // when building private docs. + let vis = vis.at_level(Level::Reachable); + if !(vis.is_public() || matches!(vis, Visibility::Restricted(id) if id.is_top_level_module())) { + return false; + } + } else if let Some(id) = self.require_visibility_at + && !vis.at_level(Level::Reexported).is_accessible_from(id, cx.tcx) + { + return false; + } + }, + None => {}, } - if sp.from_expansion() { - return; - } - - if self.crate_items_only && def_id != CRATE_DEF_ID { - let vis = cx.tcx.visibility(def_id); - if vis == Visibility::Public || vis != Visibility::Restricted(CRATE_DEF_ID.into()) { - return; - } - } else if def_id != CRATE_DEF_ID && cx.effective_visibilities.is_exported(def_id) { - return; - } - - if let Some(parent_def_id) = cx.tcx.opt_parent(def_id.to_def_id()) - && let DefKind::AnonConst - | DefKind::AssocConst - | DefKind::AssocFn - | DefKind::Closure - | DefKind::Const - | DefKind::Fn - | DefKind::InlineConst - | DefKind::Static { .. } - | DefKind::SyntheticCoroutineBody = cx.tcx.def_kind(parent_def_id) - { - // Nested item has no generated documentation, so it doesn't need to be documented. - return; - } - - let has_doc = attrs - .iter() - .any(|a| a.doc_str().is_some() || Self::has_include(a.meta_item_list().as_deref())) - || matches!(self.search_span(sp), Some(span) if span_to_snippet_contains_docs(cx, span)); - - if !has_doc { - span_lint( - cx, - MISSING_DOCS_IN_PRIVATE_ITEMS, - sp, - format!("missing documentation for {article} {desc}"), - ); - } - } - - /// Return a span to search for doc comments manually. - /// - /// # Example - /// ```ignore - /// fn foo() { ... } - /// ^^^^^^^^^^^^^^^^ prev_span - /// ↑ - /// | search_span | - /// ↓ - /// fn bar() { ... } - /// ^^^^^^^^^^^^^^^^ cur_span - /// ``` - fn search_span(&self, cur_span: Span) -> Option { - let prev_span = self.prev_span?; - let start_pos = if prev_span.contains(cur_span) { - // In case when the prev_span is an entire struct, or enum, - // and the current span is a field, or variant, we need to search from - // the starting pos of the previous span. - prev_span.lo() - } else { - prev_span.hi() - }; - let search_span = cur_span.with_lo(start_pos).with_hi(cur_span.lo()); - Some(search_span) + !cx.tcx.hir_attrs(hir_id).iter().any(is_doc_attr) } } @@ -176,111 +103,195 @@ fn search_span(&self, cur_span: Span) -> Option { impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn check_attributes(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { - let doc_hidden = self.doc_hidden() || is_doc_hidden(attrs); - self.doc_hidden_stack.push(doc_hidden); + self.attr_depth += 1; + if self.doc_hidden_depth == 0 && is_doc_hidden(attrs) { + self.doc_hidden_depth = self.attr_depth; + } } fn check_attributes_post(&mut self, _: &LateContext<'tcx>, _: &'tcx [Attribute]) { - self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); + self.attr_depth -= 1; + if self.attr_depth < self.doc_hidden_depth { + self.doc_hidden_depth = 0; + } + if self.attr_depth < self.automatically_derived_depth { + self.automatically_derived_depth = 0; + } } - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - let attrs = cx.tcx.hir_attrs(hir::CRATE_HIR_ID); - self.check_missing_docs_attrs(cx, CRATE_DEF_ID, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate"); - } + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if self.doc_hidden_depth != 0 || self.automatically_derived_depth != 0 || self.in_body.is_some() { + return; + } - fn check_crate_post(&mut self, _: &LateContext<'tcx>) { - self.prev_span = None; - } - - fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) { - match it.kind { - hir::ItemKind::Fn { ident, .. } => { - // ignore main() - if ident.name == sym::main { - let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID; - if at_root { - note_prev_span_then_ret!(self.prev_span, it.span); - } + let span = match item.kind { + // ignore main() + ItemKind::Fn { ident, .. } + if ident.name == sym::main && cx.tcx.local_parent(item.owner_id.def_id) == CRATE_DEF_ID => + { + return; + }, + ItemKind::Const(ident, ..) if ident.name == kw::Underscore => return, + ItemKind::Impl { .. } => { + if cx.tcx.is_automatically_derived(item.owner_id.def_id.to_def_id()) { + self.automatically_derived_depth = self.attr_depth; } + return; }, - hir::ItemKind::Const(ident, ..) => { - if ident.name == kw::Underscore { - note_prev_span_then_ret!(self.prev_span, it.span); + ItemKind::ExternCrate(..) + | ItemKind::ForeignMod { .. } + | ItemKind::GlobalAsm { .. } + | ItemKind::Use(..) => return, + + ItemKind::Mod(ident, ..) => { + if item.span.from_expansion() && item.span.eq_ctxt(ident.span) { + self.module_depth += 1; + self.require_visibility_at = cx.tcx.opt_local_parent(item.owner_id.def_id); + self.macro_module_depth = self.module_depth; + return; } + ident.span }, - hir::ItemKind::Enum(..) - | hir::ItemKind::Macro(..) - | hir::ItemKind::Mod(..) - | hir::ItemKind::Static(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Trait(..) - | hir::ItemKind::TraitAlias(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Union(..) => {}, - hir::ItemKind::ExternCrate(..) - | hir::ItemKind::ForeignMod { .. } - | hir::ItemKind::GlobalAsm { .. } - | hir::ItemKind::Impl { .. } - | hir::ItemKind::Use(..) => note_prev_span_then_ret!(self.prev_span, it.span), - } - let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id()); + ItemKind::Const(ident, ..) + | ItemKind::Enum(ident, ..) + | ItemKind::Fn { ident, .. } + | ItemKind::Macro(ident, ..) + | ItemKind::Static(_, ident, ..) + | ItemKind::Struct(ident, ..) + | ItemKind::Trait(_, _, _, ident, ..) + | ItemKind::TraitAlias(_, ident, ..) + | ItemKind::TyAlias(ident, ..) + | ItemKind::Union(ident, ..) => ident.span, + }; - let attrs = cx.tcx.hir_attrs(it.hir_id()); - if !is_from_proc_macro(cx, it) { - self.check_missing_docs_attrs(cx, it.owner_id.def_id, attrs, it.span, article, desc); - } - self.prev_span = Some(it.span); - } - - fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) { - let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id()); - - let attrs = cx.tcx.hir_attrs(trait_item.hir_id()); - if !is_from_proc_macro(cx, trait_item) { - self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, attrs, trait_item.span, article, desc); - } - self.prev_span = Some(trait_item.span); - } - - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { - // If the method is an impl for a trait, don't doc. - match cx.tcx.associated_item(impl_item.owner_id).container { - AssocContainer::Trait | AssocContainer::TraitImpl(_) => { - note_prev_span_then_ret!(self.prev_span, impl_item.span); - }, - AssocContainer::InherentImpl => {}, - } - - let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id()); - let attrs = cx.tcx.hir_attrs(impl_item.hir_id()); - if !is_from_proc_macro(cx, impl_item) { - self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, attrs, impl_item.span, article, desc); - } - self.prev_span = Some(impl_item.span); - } - - fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) { - if !(sf.is_positional() - || is_from_proc_macro(cx, sf) - || self.allow_unused && sf.ident.as_str().starts_with('_')) + if !item.span.from_expansion() + && self.is_missing_docs(cx, item.owner_id.def_id, item.hir_id()) + && !is_from_proc_macro(cx, item) { - let attrs = cx.tcx.hir_attrs(sf.hir_id); - self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field"); + let (article, desc) = cx.tcx.article_and_description(item.owner_id.to_def_id()); + span_lint( + cx, + MISSING_DOCS_IN_PRIVATE_ITEMS, + span, + format!("missing documentation for {article} {desc}"), + ); + } + if matches!(item.kind, ItemKind::Mod(..)) { + self.module_depth += 1; } - self.prev_span = Some(sf.span); } - fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) { - let attrs = cx.tcx.hir_attrs(v.hir_id); - if !is_from_proc_macro(cx, v) { - self.check_missing_docs_attrs(cx, v.def_id, attrs, v.span, "a", "variant"); + fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if matches!(item.kind, ItemKind::Mod(..)) + && self.doc_hidden_depth == 0 + && self.automatically_derived_depth == 0 + && self.in_body.is_none() + { + self.module_depth -= 1; + if self.module_depth < self.macro_module_depth { + self.require_visibility_at = None; + } + } + } + + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { + if self.doc_hidden_depth == 0 + && self.automatically_derived_depth == 0 + && self.in_body.is_none() + && !item.span.from_expansion() + && self.is_missing_docs(cx, item.owner_id.def_id, item.hir_id()) + && !is_from_proc_macro(cx, item) + { + let (article, desc) = cx.tcx.article_and_description(item.owner_id.to_def_id()); + span_lint( + cx, + MISSING_DOCS_IN_PRIVATE_ITEMS, + item.ident.span, + format!("missing documentation for {article} {desc}"), + ); + } + } + + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { + if self.doc_hidden_depth == 0 + && self.automatically_derived_depth == 0 + && self.in_body.is_none() + && let Node::Item(parent) = cx.tcx.parent_hir_node(item.hir_id()) + && let ItemKind::Impl(impl_) = parent.kind + && impl_.of_trait.is_none() + && !item.span.from_expansion() + && self.is_missing_docs(cx, item.owner_id.def_id, item.hir_id()) + && !is_from_proc_macro(cx, item) + { + let (article, desc) = cx.tcx.article_and_description(item.owner_id.to_def_id()); + span_lint( + cx, + MISSING_DOCS_IN_PRIVATE_ITEMS, + item.ident.span, + format!("missing documentation for {article} {desc}"), + ); + } + } + + fn check_body(&mut self, _: &LateContext<'tcx>, body: &Body<'tcx>) { + if self.doc_hidden_depth == 0 && self.automatically_derived_depth == 0 && self.in_body.is_none() { + self.in_body = Some(body.id()); + } + } + + fn check_body_post(&mut self, _: &LateContext<'tcx>, body: &Body<'tcx>) { + if self.in_body == Some(body.id()) { + self.in_body = None; + } + } + + fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx FieldDef<'_>) { + if self.doc_hidden_depth == 0 + && self.automatically_derived_depth == 0 + && self.in_body.is_none() + && !field.is_positional() + && !field.span.from_expansion() + && !(self.allow_unused && field.ident.name.as_str().starts_with('_')) + && self.is_missing_docs(cx, field.def_id, field.hir_id) + && !is_from_proc_macro(cx, field) + { + span_lint( + cx, + MISSING_DOCS_IN_PRIVATE_ITEMS, + field.ident.span, + "missing documentation for a field", + ); + } + } + + fn check_variant(&mut self, cx: &LateContext<'tcx>, variant: &'tcx Variant<'_>) { + if self.doc_hidden_depth == 0 + && self.automatically_derived_depth == 0 + && self.in_body.is_none() + && !variant.span.from_expansion() + && self.is_missing_docs(cx, variant.def_id, variant.hir_id) + && !is_from_proc_macro(cx, variant) + { + span_lint( + cx, + MISSING_DOCS_IN_PRIVATE_ITEMS, + variant.ident.span, + "missing documentation for a variant", + ); } - self.prev_span = Some(v.span); } } -fn span_to_snippet_contains_docs(cx: &LateContext<'_>, search_span: Span) -> bool { - search_span.check_source_text(cx, |src| src.lines().rev().any(|line| line.trim().starts_with("///"))) +fn is_doc_attr(attr: &Attribute) -> bool { + match attr { + Attribute::Parsed(AttributeKind::DocComment { .. }) => true, + Attribute::Unparsed(attr) + if let [ident] = &*attr.path.segments + && ident.name == sym::doc => + { + matches!(attr.args, AttrArgs::Eq { .. }) + }, + _ => false, + } } diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index bc5e72270f4e..80cf081992cc 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -1,13 +1,13 @@ use clippy_utils::desugar_await; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::visitors::{Descend, Visitable, for_each_expr}; -use core::ops::ControlFlow::Continue; use hir::def::{DefKind, Res}; use hir::{BlockCheckMode, ExprKind, QPath, UnOp}; -use rustc_ast::Mutability; +use rustc_ast::{BorrowKind, Mutability}; use rustc_hir as hir; +use rustc_hir::intravisit::{Visitor, walk_body, walk_expr}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; +use rustc_middle::hir::nested_filter; +use rustc_middle::ty::{self, TyCtxt, TypeckResults}; use rustc_session::declare_lint_pass; use rustc_span::{DesugaringKind, Span}; @@ -55,6 +55,13 @@ /// unsafe { char::from_u32_unchecked(int_value) } /// } /// ``` + /// + /// ### Note + /// + /// Taking a raw pointer to a union field is always safe and will + /// not be considered unsafe by this lint, even when linting code written + /// with a specified Rust version of 1.91 or earlier (which required + /// using an `unsafe` block). #[clippy::version = "1.69.0"] pub MULTIPLE_UNSAFE_OPS_PER_BLOCK, restriction, @@ -70,8 +77,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { { return; } - let mut unsafe_ops = vec![]; - collect_unsafe_exprs(cx, block, &mut unsafe_ops); + let unsafe_ops = UnsafeExprCollector::collect_unsafe_exprs(cx, block); if unsafe_ops.len() > 1 { span_lint_and_then( cx, @@ -91,25 +97,49 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { } } -fn collect_unsafe_exprs<'tcx>( - cx: &LateContext<'tcx>, - node: impl Visitable<'tcx>, - unsafe_ops: &mut Vec<(&'static str, Span)>, -) { - for_each_expr(cx, node, |expr| { +struct UnsafeExprCollector<'tcx> { + tcx: TyCtxt<'tcx>, + typeck_results: &'tcx TypeckResults<'tcx>, + unsafe_ops: Vec<(&'static str, Span)>, +} + +impl<'tcx> UnsafeExprCollector<'tcx> { + fn collect_unsafe_exprs(cx: &LateContext<'tcx>, block: &'tcx hir::Block<'tcx>) -> Vec<(&'static str, Span)> { + let mut collector = Self { + tcx: cx.tcx, + typeck_results: cx.typeck_results(), + unsafe_ops: vec![], + }; + collector.visit_block(block); + collector.unsafe_ops + } +} + +impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { + type NestedFilter = nested_filter::OnlyBodies; + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { match expr.kind { // The `await` itself will desugar to two unsafe calls, but we should ignore those. // Instead, check the expression that is `await`ed _ if let Some(e) = desugar_await(expr) => { - collect_unsafe_exprs(cx, e, unsafe_ops); - return Continue(Descend::No); + return self.visit_expr(e); }, - ExprKind::InlineAsm(_) => unsafe_ops.push(("inline assembly used here", expr.span)), + ExprKind::InlineAsm(_) => self.unsafe_ops.push(("inline assembly used here", expr.span)), + + ExprKind::AddrOf(BorrowKind::Raw, _, mut inner) => { + while let ExprKind::Field(prefix, _) = inner.kind + && self.typeck_results.expr_adjustments(prefix).is_empty() + { + inner = prefix; + } + return self.visit_expr(inner); + }, ExprKind::Field(e, _) => { - if cx.typeck_results().expr_ty(e).is_union() { - unsafe_ops.push(("union field access occurs here", expr.span)); + if self.typeck_results.expr_ty(e).is_union() { + self.unsafe_ops.push(("union field access occurs here", expr.span)); } }, @@ -127,32 +157,32 @@ fn collect_unsafe_exprs<'tcx>( .. }, )) => { - unsafe_ops.push(("access of a mutable static occurs here", expr.span)); + self.unsafe_ops + .push(("access of a mutable static occurs here", expr.span)); }, - ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty_adjusted(e).is_raw_ptr() => { - unsafe_ops.push(("raw pointer dereference occurs here", expr.span)); + ExprKind::Unary(UnOp::Deref, e) if self.typeck_results.expr_ty(e).is_raw_ptr() => { + self.unsafe_ops.push(("raw pointer dereference occurs here", expr.span)); }, ExprKind::Call(path_expr, _) => { - let sig = match *cx.typeck_results().expr_ty(path_expr).kind() { - ty::FnDef(id, _) => cx.tcx.fn_sig(id).skip_binder(), - ty::FnPtr(sig_tys, hdr) => sig_tys.with(hdr), - _ => return Continue(Descend::Yes), + let opt_sig = match *self.typeck_results.expr_ty_adjusted(path_expr).kind() { + ty::FnDef(id, _) => Some(self.tcx.fn_sig(id).skip_binder()), + ty::FnPtr(sig_tys, hdr) => Some(sig_tys.with(hdr)), + _ => None, }; - if sig.safety().is_unsafe() { - unsafe_ops.push(("unsafe function call occurs here", expr.span)); + if opt_sig.is_some_and(|sig| sig.safety().is_unsafe()) { + self.unsafe_ops.push(("unsafe function call occurs here", expr.span)); } }, ExprKind::MethodCall(..) => { - if let Some(sig) = cx - .typeck_results() + let opt_sig = self + .typeck_results .type_dependent_def_id(expr.hir_id) - .map(|def_id| cx.tcx.fn_sig(def_id)) - && sig.skip_binder().safety().is_unsafe() - { - unsafe_ops.push(("unsafe method call occurs here", expr.span)); + .map(|def_id| self.tcx.fn_sig(def_id)); + if opt_sig.is_some_and(|sig| sig.skip_binder().safety().is_unsafe()) { + self.unsafe_ops.push(("unsafe method call occurs here", expr.span)); } }, @@ -173,15 +203,26 @@ fn collect_unsafe_exprs<'tcx>( } )) ) { - unsafe_ops.push(("modification of a mutable static occurs here", expr.span)); - collect_unsafe_exprs(cx, rhs, unsafe_ops); - return Continue(Descend::No); + self.unsafe_ops + .push(("modification of a mutable static occurs here", expr.span)); + return self.visit_expr(rhs); } }, _ => {}, } - Continue::<(), _>(Descend::Yes) - }); + walk_expr(self, expr); + } + + fn visit_body(&mut self, body: &hir::Body<'tcx>) { + let saved_typeck_results = self.typeck_results; + self.typeck_results = self.tcx.typeck_body(body.id()); + walk_body(self, body); + self.typeck_results = saved_typeck_results; + } + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } } diff --git a/clippy_lints/src/ptr/ptr_arg.rs b/clippy_lints/src/ptr/ptr_arg.rs index fd9230f00a8b..4bfff64b1bd4 100644 --- a/clippy_lints/src/ptr/ptr_arg.rs +++ b/clippy_lints/src/ptr/ptr_arg.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::res::MaybeResPath; use clippy_utils::source::SpanRangeExt; -use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, sym}; +use clippy_utils::{VEC_METHODS_SHADOWING_SLICE_METHODS, get_expr_use_or_unification_node, is_lint_allowed, sym}; use hir::LifetimeKind; use rustc_abi::ExternAbi; use rustc_errors::Applicability; @@ -23,8 +23,6 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use std::{fmt, iter}; -use crate::vec::is_allowed_vec_method; - pub(super) fn check_body<'tcx>( cx: &LateContext<'tcx>, body: &Body<'tcx>, @@ -383,7 +381,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) { // Some methods exist on both `[T]` and `Vec`, such as `len`, where the receiver type // doesn't coerce to a slice and our adjusted type check below isn't enough, // but it would still be valid to call with a slice - if is_allowed_vec_method(use_expr) { + if VEC_METHODS_SHADOWING_SLICE_METHODS.contains(&name) { return; } } diff --git a/clippy_lints/src/time_subtraction.rs b/clippy_lints/src/time_subtraction.rs index dbd4ec77fd5f..e0fdca97dbee 100644 --- a/clippy_lints/src/time_subtraction.rs +++ b/clippy_lints/src/time_subtraction.rs @@ -1,5 +1,5 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; use clippy_utils::sugg::Sugg; @@ -109,36 +109,16 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { && !expr.span.from_expansion() && self.msrv.meets(cx, msrvs::TRY_FROM) { - // For chained subtraction like (instant - dur1) - dur2, avoid suggestions - if is_chained_time_subtraction(cx, lhs) { - span_lint( - cx, - UNCHECKED_TIME_SUBTRACTION, - expr.span, - "unchecked subtraction of a 'Duration' from an 'Instant'", - ); - } else { - // instant - duration - print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); - } + print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } - } else if lhs_ty.is_diag_item(cx, sym::Duration) + } + // duration - duration + else if lhs_ty.is_diag_item(cx, sym::Duration) && rhs_ty.is_diag_item(cx, sym::Duration) && !expr.span.from_expansion() && self.msrv.meets(cx, msrvs::TRY_FROM) { - // For chained subtraction like (dur1 - dur2) - dur3, avoid suggestions - if is_chained_time_subtraction(cx, lhs) { - span_lint( - cx, - UNCHECKED_TIME_SUBTRACTION, - expr.span, - "unchecked subtraction between 'Duration' values", - ); - } else { - // duration - duration - print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); - } + print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } } } @@ -191,26 +171,26 @@ fn print_unchecked_duration_subtraction_sugg( right_expr: &Expr<'_>, expr: &Expr<'_>, ) { - let typeck = cx.typeck_results(); - let left_ty = typeck.expr_ty(left_expr); - - let lint_msg = if left_ty.is_diag_item(cx, sym::Instant) { - "unchecked subtraction of a 'Duration' from an 'Instant'" - } else { - "unchecked subtraction between 'Duration' values" - }; - - let mut applicability = Applicability::MachineApplicable; - let left_sugg = Sugg::hir_with_applicability(cx, left_expr, "", &mut applicability); - let right_sugg = Sugg::hir_with_applicability(cx, right_expr, "", &mut applicability); - - span_lint_and_sugg( + span_lint_and_then( cx, UNCHECKED_TIME_SUBTRACTION, expr.span, - lint_msg, - "try", - format!("{}.checked_sub({}).unwrap()", left_sugg.maybe_paren(), right_sugg), - applicability, + "unchecked subtraction of a `Duration`", + |diag| { + // For chained subtraction, like `(dur1 - dur2) - dur3` or `(instant - dur1) - dur2`, + // avoid suggestions + if !is_chained_time_subtraction(cx, left_expr) { + let mut applicability = Applicability::MachineApplicable; + let left_sugg = Sugg::hir_with_applicability(cx, left_expr, "", &mut applicability); + let right_sugg = Sugg::hir_with_applicability(cx, right_expr, "", &mut applicability); + + diag.span_suggestion( + expr.span, + "try", + format!("{}.checked_sub({}).unwrap()", left_sugg.maybe_paren(), right_sugg), + applicability, + ); + } + }, ); } diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index 933e25fe98c6..91fce5d5bd68 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -17,6 +17,8 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, msrv: Msrv, ) -> bool { + let mut applicability = Applicability::MachineApplicable; + let arg_sugg = sugg::Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut applicability); match (from_ty.kind(), to_ty.kind()) { (ty::RawPtr(from_pointee_ty, from_mutbl), ty::RawPtr(to_pointee_ty, to_mutbl)) => { span_lint_and_then( @@ -25,40 +27,38 @@ pub(super) fn check<'tcx>( e.span, "transmute from a pointer to a pointer", |diag| { - if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - if from_mutbl == to_mutbl - && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) - && msrv.meets(cx, msrvs::POINTER_CAST) - { - diag.span_suggestion_verbose( - e.span, - "use `pointer::cast` instead", - format!("{}.cast::<{to_pointee_ty}>()", arg.maybe_paren()), - Applicability::MaybeIncorrect, - ); - } else if from_pointee_ty == to_pointee_ty - && let Some(method) = match (from_mutbl, to_mutbl) { - (ty::Mutability::Not, ty::Mutability::Mut) => Some("cast_mut"), - (ty::Mutability::Mut, ty::Mutability::Not) => Some("cast_const"), - _ => None, - } - && !from_pointee_ty.has_erased_regions() - && msrv.meets(cx, msrvs::POINTER_CAST_CONSTNESS) - { - diag.span_suggestion_verbose( - e.span, - format!("use `pointer::{method}` instead"), - format!("{}.{method}()", arg.maybe_paren()), - Applicability::MaybeIncorrect, - ); - } else { - diag.span_suggestion_verbose( - e.span, - "use an `as` cast instead", - arg.as_ty(to_ty), - Applicability::MaybeIncorrect, - ); + if from_mutbl == to_mutbl + && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) + && msrv.meets(cx, msrvs::POINTER_CAST) + { + diag.span_suggestion_verbose( + e.span, + "use `pointer::cast` instead", + format!("{}.cast::<{to_pointee_ty}>()", arg_sugg.maybe_paren()), + Applicability::MaybeIncorrect, + ); + } else if from_pointee_ty == to_pointee_ty + && let Some(method) = match (from_mutbl, to_mutbl) { + (ty::Mutability::Not, ty::Mutability::Mut) => Some("cast_mut"), + (ty::Mutability::Mut, ty::Mutability::Not) => Some("cast_const"), + _ => None, } + && !from_pointee_ty.has_erased_regions() + && msrv.meets(cx, msrvs::POINTER_CAST_CONSTNESS) + { + diag.span_suggestion_verbose( + e.span, + format!("use `pointer::{method}` instead"), + format!("{}.{method}()", arg_sugg.maybe_paren()), + Applicability::MaybeIncorrect, + ); + } else { + diag.span_suggestion_verbose( + e.span, + "use an `as` cast instead", + arg_sugg.as_ty(to_ty), + Applicability::MaybeIncorrect, + ); } }, ); diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 70c2a73ce6ef..39b1ccdc9426 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -1,6 +1,5 @@ use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::snippet; use clippy_utils::{std_or_core, sugg}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; @@ -17,8 +16,7 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, const_context: bool, ) -> bool { - let mut triggered = false; - + let arg_sugg = || sugg::Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut Applicability::Unspecified); if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (*from_ty.kind(), *to_ty.kind()) { if let ty::Slice(slice_ty) = *ty_from.kind() && ty_to.is_str() @@ -29,8 +27,6 @@ pub(super) fn check<'tcx>( let postfix = if from_mutbl == Mutability::Mut { "_mut" } else { "" }; - let snippet = snippet(cx, arg.span, ".."); - span_lint_and_sugg( cx, TRANSMUTE_BYTES_TO_STR, @@ -38,15 +34,17 @@ pub(super) fn check<'tcx>( format!("transmute from a `{from_ty}` to a `{to_ty}`"), "consider using", if const_context { - format!("{top_crate}::str::from_utf8_unchecked{postfix}({snippet})") + format!("{top_crate}::str::from_utf8_unchecked{postfix}({})", arg_sugg()) } else { - format!("{top_crate}::str::from_utf8{postfix}({snippet}).unwrap()") + format!("{top_crate}::str::from_utf8{postfix}({}).unwrap()", arg_sugg()) }, Applicability::MaybeIncorrect, ); - triggered = true; - } else if (cx.tcx.erase_and_anonymize_regions(from_ty) != cx.tcx.erase_and_anonymize_regions(to_ty)) - && !const_context + + return true; + } + + if (cx.tcx.erase_and_anonymize_regions(from_ty) != cx.tcx.erase_and_anonymize_regions(to_ty)) && !const_context { span_lint_and_then( cx, @@ -54,23 +52,21 @@ pub(super) fn check<'tcx>( e.span, "transmute from a reference to a reference", |diag| { - if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - let sugg_paren = arg - .as_ty(Ty::new_ptr(cx.tcx, ty_from, from_mutbl)) - .as_ty(Ty::new_ptr(cx.tcx, ty_to, to_mutbl)); - let sugg = if to_mutbl == Mutability::Mut { - sugg_paren.mut_addr_deref() - } else { - sugg_paren.addr_deref() - }; - diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified); - } + let sugg_paren = arg_sugg() + .as_ty(Ty::new_ptr(cx.tcx, ty_from, from_mutbl)) + .as_ty(Ty::new_ptr(cx.tcx, ty_to, to_mutbl)); + let sugg = if to_mutbl == Mutability::Mut { + sugg_paren.mut_addr_deref() + } else { + sugg_paren.addr_deref() + }; + diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified); }, ); - triggered = true; + return true; } } - triggered + false } diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 99201a1ca215..8ed3df8731b3 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,15 +1,21 @@ +use std::borrow::Cow; +use std::iter; + use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::Msrv; use clippy_utils::res::{MaybeDef, MaybeResPath}; +use clippy_utils::source::snippet; use clippy_utils::usage::is_potentially_local_place; use clippy_utils::{can_use_if_let_chains, higher, sym}; +use rustc_abi::FieldIdx; use rustc_errors::Applicability; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, UnOp}; -use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, Place, PlaceWithHirId}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; +use rustc_middle::hir::place::ProjectionKind; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; @@ -114,11 +120,91 @@ fn error_variant_pattern(self) -> &'static str { } } +#[derive(Clone, Debug, Eq)] +enum Local { + /// `x.field1.field2.field3` + WithFieldAccess { + local_id: HirId, + /// The indices of the field accessed. + /// + /// Stored last-to-first, e.g. for the example above: `[field3, field2, field1]` + field_indices: Vec, + /// The span of the whole expression + span: Span, + }, + /// `x` + Pure { local_id: HirId }, +} + +/// Identical to derived impl, but ignores `span` on [`Local::WithFieldAccess`] +impl PartialEq for Local { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + ( + Self::WithFieldAccess { + local_id: self_local_id, + field_indices: self_field_indices, + .. + }, + Self::WithFieldAccess { + local_id: other_local_id, + field_indices: other_field_indices, + .. + }, + ) => self_local_id == other_local_id && self_field_indices == other_field_indices, + ( + Self::Pure { + local_id: self_local_id, + }, + Self::Pure { + local_id: other_local_id, + }, + ) => self_local_id == other_local_id, + _ => false, + } + } +} + +impl Local { + fn snippet(&self, cx: &LateContext<'_>) -> Cow<'static, str> { + match *self { + Self::WithFieldAccess { span, .. } => snippet(cx.sess(), span, "_"), + Self::Pure { local_id } => cx.tcx.hir_name(local_id).to_string().into(), + } + } + + fn is_potentially_local_place(&self, place: &Place<'_>) -> bool { + match self { + Self::WithFieldAccess { + local_id, + field_indices, + .. + } => { + is_potentially_local_place(*local_id, place) + // If there were projections other than field projections, err on the side of caution and say that they + // _might_ be mutating something. + // + // The reason we use `<=` and not `==` is that a mutation of `struct` or `struct.field1` should count as + // mutation of the child fields such as `struct.field1.field2` + && place.projections.len() <= field_indices.len() + && iter::zip(&place.projections, field_indices.iter().copied().rev()).all(|(proj, field_idx)| { + match proj.kind { + ProjectionKind::Field(f_idx, _) => f_idx == field_idx, + // If this is a projection we don't expect, it _might_ be mutating something + _ => false, + } + }) + }, + Self::Pure { local_id } => is_potentially_local_place(*local_id, place), + } + } +} + /// Contains information about whether a variable can be unwrapped. -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Debug)] struct UnwrapInfo<'tcx> { /// The variable that is checked - local_id: HirId, + local: Local, /// The if itself if_expr: &'tcx Expr<'tcx>, /// The check, like `x.is_ok()` @@ -156,38 +242,77 @@ fn option_or_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) } } - match expr.kind { - ExprKind::Binary(op, left, right) - if matches!( - (invert, op.node), - (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) - ) => - { - let mut unwrap_info = collect_unwrap_info(cx, if_expr, left, branch, invert, false); - unwrap_info.extend(collect_unwrap_info(cx, if_expr, right, branch, invert, false)); - unwrap_info - }, - ExprKind::Unary(UnOp::Not, expr) => collect_unwrap_info(cx, if_expr, expr, branch, !invert, false), - ExprKind::MethodCall(method_name, receiver, [], _) - if let Some(local_id) = receiver.res_local_id() - && let ty = cx.typeck_results().expr_ty(receiver) - && let name = method_name.ident.name - && let Some((kind, unwrappable)) = option_or_result_call(cx, ty, name) => - { - let safe_to_unwrap = unwrappable != invert; + fn inner<'tcx>( + cx: &LateContext<'tcx>, + if_expr: &'tcx Expr<'_>, + expr: &'tcx Expr<'_>, + branch: &'tcx Expr<'_>, + invert: bool, + is_entire_condition: bool, + out: &mut Vec>, + ) { + match expr.kind { + ExprKind::Binary(op, left, right) + if matches!( + (invert, op.node), + (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) + ) => + { + inner(cx, if_expr, left, branch, invert, false, out); + inner(cx, if_expr, right, branch, invert, false, out); + }, + ExprKind::Unary(UnOp::Not, expr) => inner(cx, if_expr, expr, branch, !invert, false, out), + ExprKind::MethodCall(method_name, receiver, [], _) + if let Some(local) = extract_local(cx, receiver) + && let ty = cx.typeck_results().expr_ty(receiver) + && let name = method_name.ident.name + && let Some((kind, unwrappable)) = option_or_result_call(cx, ty, name) => + { + let safe_to_unwrap = unwrappable != invert; - vec![UnwrapInfo { + out.push(UnwrapInfo { + local, + if_expr, + check: expr, + check_name: name, + branch, + safe_to_unwrap, + kind, + is_entire_condition, + }); + }, + _ => {}, + } + } + + let mut out = vec![]; + inner(cx, if_expr, expr, branch, invert, is_entire_condition, &mut out); + out +} + +/// Extracts either a local used by itself ([`Local::Pure`]), or (one or more levels of) field +/// access to a local ([`Local::WithFieldAccess`]) +fn extract_local(cx: &LateContext<'_>, mut expr: &Expr<'_>) -> Option { + let span = expr.span; + let mut field_indices = vec![]; + while let ExprKind::Field(recv, _) = expr.kind + && let Some(field_idx) = cx.typeck_results().opt_field_index(expr.hir_id) + { + field_indices.push(field_idx); + expr = recv; + } + if let Some(local_id) = expr.res_local_id() { + if field_indices.is_empty() { + Some(Local::Pure { local_id }) + } else { + Some(Local::WithFieldAccess { local_id, - if_expr, - check: expr, - check_name: name, - branch, - safe_to_unwrap, - kind, - is_entire_condition, - }] - }, - _ => vec![], + field_indices, + span, + }) + } + } else { + None } } @@ -198,9 +323,9 @@ fn option_or_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) /// `is_some` + `unwrap` is equivalent to `if let Some(..) = ..`, which it would not be if /// the option is changed to None between `is_some` and `unwrap`, ditto for `Result`. /// (And also `.as_mut()` is a somewhat common method that is still worth linting on.) -struct MutationVisitor<'tcx> { +struct MutationVisitor<'tcx, 'lcl> { is_mutated: bool, - local_id: HirId, + local: &'lcl Local, tcx: TyCtxt<'tcx>, } @@ -221,10 +346,10 @@ fn is_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool { } } -impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> { +impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx, '_> { fn borrow(&mut self, cat: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) { if let ty::BorrowKind::Mutable = bk - && is_potentially_local_place(self.local_id, &cat.place) + && self.local.is_potentially_local_place(&cat.place) && !is_as_mut_use(self.tcx, diag_expr_id) { self.is_mutated = true; @@ -232,7 +357,7 @@ fn borrow(&mut self, cat: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::Bo } fn mutate(&mut self, cat: &PlaceWithHirId<'tcx>, _: HirId) { - if is_potentially_local_place(self.local_id, &cat.place) { + if self.local.is_potentially_local_place(&cat.place) { self.is_mutated = true; } } @@ -256,7 +381,7 @@ fn visit_branch( for unwrap_info in collect_unwrap_info(self.cx, if_expr, cond, branch, else_branch, true) { let mut delegate = MutationVisitor { is_mutated: false, - local_id: unwrap_info.local_id, + local: &unwrap_info.local, tcx: self.cx.tcx, }; @@ -318,24 +443,17 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { // find `unwrap[_err]()` or `expect("...")` calls: if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind && let (self_arg, as_ref_kind) = consume_option_as_ref(self_arg) - && let Some(id) = self_arg.res_local_id() + && let Some(local) = extract_local(self.cx, self_arg) && matches!(method_name.ident.name, sym::unwrap | sym::expect | sym::unwrap_err) && let call_to_unwrap = matches!(method_name.ident.name, sym::unwrap | sym::expect) - && let Some(unwrappable) = self.unwrappables.iter() - .find(|u| u.local_id == id) + && let Some(unwrappable) = self.unwrappables.iter().find(|u| u.local == local) // Span contexts should not differ with the conditional branch && let span_ctxt = expr.span.ctxt() && unwrappable.branch.span.ctxt() == span_ctxt && unwrappable.check.span.ctxt() == span_ctxt { if call_to_unwrap == unwrappable.safe_to_unwrap { - let is_entire_condition = unwrappable.is_entire_condition; - let unwrappable_variable_name = self.cx.tcx.hir_name(unwrappable.local_id); - let suggested_pattern = if call_to_unwrap { - unwrappable.kind.success_variant_pattern() - } else { - unwrappable.kind.error_variant_pattern() - }; + let unwrappable_variable_str = unwrappable.local.snippet(self.cx); span_lint_hir_and_then( self.cx, @@ -343,16 +461,21 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { expr.hir_id, expr.span, format!( - "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`", + "called `{}` on `{unwrappable_variable_str}` after checking its variant with `{}`", method_name.ident.name, unwrappable.check_name, ), |diag| { - if is_entire_condition { + if unwrappable.is_entire_condition { diag.span_suggestion( unwrappable.check.span.with_lo(unwrappable.if_expr.span.lo()), "try", format!( - "if let {suggested_pattern} = {borrow_prefix}{unwrappable_variable_name}", + "if let {suggested_pattern} = {borrow_prefix}{unwrappable_variable_str}", + suggested_pattern = if call_to_unwrap { + unwrappable.kind.success_variant_pattern() + } else { + unwrappable.kind.error_variant_pattern() + }, borrow_prefix = match as_ref_kind { Some(AsRefKind::AsRef) => "&", Some(AsRefKind::AsMut) => "&mut ", diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/useless_vec.rs similarity index 90% rename from clippy_lints/src/vec.rs rename to clippy_lints/src/useless_vec.rs index b87db836869d..28c339ce2b7d 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/useless_vec.rs @@ -10,7 +10,7 @@ use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; -use clippy_utils::{get_parent_expr, higher, is_in_test, span_contains_comment, sym}; +use clippy_utils::{VEC_METHODS_SHADOWING_SLICE_METHODS, get_parent_expr, higher, is_in_test, span_contains_comment}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -123,8 +123,16 @@ fn expr_usage_requires_vec(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) -> // allow indexing into a vec and some set of allowed method calls that exist on slices, too if let Some(parent) = get_parent_expr(cx, expr) && (adjusts_to_slice(cx, expr) - || matches!(parent.kind, ExprKind::Index(..)) - || is_allowed_vec_method(parent)) + || match parent.kind { + ExprKind::Index(..) => true, + ExprKind::MethodCall(path, _, [], _) => { + // If the given expression is a method call to a `Vec` method that also exists on + // slices, it means that this expression does not actually require a `Vec` and could + // just work with an array. + VEC_METHODS_SHADOWING_SLICE_METHODS.contains(&path.ident.name) + }, + _ => false, + }) { ControlFlow::Continue(()) } else { @@ -144,8 +152,9 @@ fn expr_usage_requires_vec(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) -> VecToArray::Impossible }, // search for `for _ in vec![...]` - Node::Expr(Expr { span, .. }) - if span.is_desugaring(DesugaringKind::ForLoop) && self.msrv.meets(cx, msrvs::ARRAY_INTO_ITERATOR) => + Node::Expr(expr) + if expr.span.is_desugaring(DesugaringKind::ForLoop) + && self.msrv.meets(cx, msrvs::ARRAY_INTO_ITERATOR) => { VecToArray::Possible }, @@ -276,9 +285,8 @@ fn snippet(self, cx: &LateContext<'_>, args_span: Option, len_span: Option assert!(args_span.is_none_or(|s| !s.from_expansion())); assert!(len_span.is_none_or(|s| !s.from_expansion())); - let maybe_args = args_span - .map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")) - .map_or(String::new(), |x| x.to_owned()); + let maybe_args = args_span.map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")); + let maybe_args = maybe_args.as_deref().unwrap_or_default(); let maybe_len = len_span .map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")) .map(|st| format!("; {st}")) @@ -301,17 +309,6 @@ fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { matches!(cx.typeck_results().expr_ty_adjusted(e).kind(), ty::Ref(_, ty, _) if ty.is_slice()) } -/// Checks if the given expression is a method call to a `Vec` method -/// that also exists on slices. If this returns true, it means that -/// this expression does not actually require a `Vec` and could just work with an array. -pub fn is_allowed_vec_method(e: &Expr<'_>) -> bool { - if let ExprKind::MethodCall(path, _, [], _) = e.kind { - matches!(path.ident.name, sym::as_ptr | sym::is_empty | sym::len) - } else { - false - } -} - fn suggest_type(expr: &Expr<'_>) -> SuggestedType { if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind { // `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.) diff --git a/clippy_utils/README.md b/clippy_utils/README.md index 6f976094fc2d..4b1a10a3d9cf 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-11-14 +nightly-2025-11-28 ``` diff --git a/clippy_utils/src/ast_utils/mod.rs b/clippy_utils/src/ast_utils/mod.rs index 4bdbfc885366..27b5a57c737d 100644 --- a/clippy_utils/src/ast_utils/mod.rs +++ b/clippy_utils/src/ast_utils/mod.rs @@ -43,7 +43,7 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool { (Range(lf, lt, le), Range(rf, rt, re)) => { eq_expr_opt(lf.as_deref(), rf.as_deref()) && eq_expr_opt(lt.as_deref(), rt.as_deref()) - && eq_range_end(&le.node, &re.node) + && eq_range_end(le.node, re.node) }, (Box(l), Box(r)) => eq_pat(l, r), (Ref(l, l_pin, l_mut), Ref(r, r_pin, r_mut)) => l_pin == r_pin && l_mut == r_mut && eq_pat(l, r), @@ -64,7 +64,7 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool { } } -pub fn eq_range_end(l: &RangeEnd, r: &RangeEnd) -> bool { +pub fn eq_range_end(l: RangeEnd, r: RangeEnd) -> bool { match (l, r) { (RangeEnd::Excluded, RangeEnd::Excluded) => true, (RangeEnd::Included(l), RangeEnd::Included(r)) => { diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 50d9136b8b4d..d9254fca9453 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -265,7 +265,14 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::Trait(_, IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")), ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")), - _ => return (Pat::Str(""), Pat::Str("")), + ItemKind::Mod(..) => (Pat::Str("mod"), Pat::Str("")), + ItemKind::Macro(_, def, _) => ( + Pat::Str(if def.macro_rules { "macro_rules" } else { "macro" }), + Pat::Str(""), + ), + ItemKind::TraitAlias(..) => (Pat::Str("trait"), Pat::Str(";")), + ItemKind::GlobalAsm { .. } => return (Pat::Str("global_asm"), Pat::Str("")), + ItemKind::Use(..) => return (Pat::Str(""), Pat::Str("")), }; if item.vis_span.is_empty() { (start_pat, end_pat) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index c9302b17eb7e..ed164fcf371b 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -136,6 +136,9 @@ use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; use crate::visitors::for_each_expr_without_closures; +/// Methods on `Vec` that also exists on slices. +pub const VEC_METHODS_SHADOWING_SLICE_METHODS: [Symbol; 3] = [sym::as_ptr, sym::is_empty, sym::len]; + #[macro_export] macro_rules! extract_msrv_attr { () => { diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 2593df103527..2ef2afb45071 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -8,7 +8,7 @@ use rustc_ast::{UnOp, ast}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{self as hir, Closure, ExprKind, HirId, MutTy, Node, TyKind}; +use rustc_hir::{self as hir, Closure, ExprKind, HirId, MatchSource, MutTy, Node, TyKind}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_lint::{EarlyContext, LateContext, LintContext}; use rustc_middle::hir::place::ProjectionKind; @@ -146,7 +146,9 @@ fn hir_from_snippet( | ExprKind::Let(..) | ExprKind::Closure { .. } | ExprKind::Unary(..) - | ExprKind::Match(..) => Sugg::MaybeParen(get_snippet(expr.span)), + | ExprKind::Match(_, _, + MatchSource::Normal | MatchSource::Postfix | MatchSource::ForLoopDesugar + ) => Sugg::MaybeParen(get_snippet(expr.span)), ExprKind::Continue(..) | ExprKind::Yield(..) | ExprKind::Array(..) @@ -169,7 +171,10 @@ fn hir_from_snippet( | ExprKind::Tup(..) | ExprKind::Use(..) | ExprKind::Err(_) - | ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)), + | ExprKind::UnsafeBinderCast(..) + | ExprKind::Match(_, _, + MatchSource::AwaitDesugar | MatchSource::TryDesugar(_) | MatchSource::FormatArgs + ) => Sugg::NonParen(get_snippet(expr.span)), ExprKind::DropTemps(inner) => Self::hir_from_snippet(cx, inner, get_snippet), ExprKind::Assign(lhs, rhs, _) => { Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span)) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index f6809da98f2b..5157b79832a3 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-11-14" +channel = "nightly-2025-11-28" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/driver.rs b/src/driver.rs index 2fc4abe48fe4..8693973ef78c 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -13,12 +13,12 @@ extern crate rustc_session; extern crate rustc_span; -/// See docs in https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc/src/main.rs -/// and https://github.com/rust-lang/rust/pull/146627 for why we need this. +/// See docs in +/// and for why we need this. /// /// FIXME(madsmtm): This is loaded from the sysroot that was built with the other `rustc` crates /// above, instead of via Cargo as you'd normally do. This is currently needed for LTO due to -/// https://github.com/rust-lang/cc-rs/issues/1613. +/// . #[cfg(feature = "jemalloc")] extern crate tikv_jemalloc_sys as _; @@ -191,7 +191,6 @@ fn display_help() { const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml"; -#[expect(clippy::too_many_lines)] pub fn main() { let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); diff --git a/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs b/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs deleted file mode 100644 index 155f680c7b13..000000000000 --- a/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Test file for missing_docs_in_private_items lint with allow_unused configuration -#![warn(clippy::missing_docs_in_private_items)] -#![allow(dead_code)] - -/// A struct with some documented and undocumented fields -struct Test { - /// This field is documented - field1: i32, - _unused: i32, // This should not trigger a warning because it starts with an underscore - field3: i32, //~ missing_docs_in_private_items -} - -struct Test2 { - //~^ missing_docs_in_private_items - _field1: i32, // This should not trigger a warning - _field2: i32, // This should not trigger a warning -} - -struct Test3 { - //~^ missing_docs_in_private_items - /// This field is documented although this is not mandatory - _unused: i32, // This should not trigger a warning because it starts with an underscore - field2: i32, //~ missing_docs_in_private_items -} - -fn main() {} diff --git a/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr b/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr deleted file mode 100644 index 8f511883e900..000000000000 --- a/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr +++ /dev/null @@ -1,38 +0,0 @@ -error: missing documentation for a struct field - --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:10:5 - | -LL | field3: i32, - | ^^^^^^^^^^^ - | - = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` - -error: missing documentation for a struct - --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:13:1 - | -LL | / struct Test2 { -LL | | -LL | | _field1: i32, // This should not trigger a warning -LL | | _field2: i32, // This should not trigger a warning -LL | | } - | |_^ - -error: missing documentation for a struct - --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:19:1 - | -LL | / struct Test3 { -LL | | -LL | | /// This field is documented although this is not mandatory -LL | | _unused: i32, // This should not trigger a warning because it starts with an underscore -LL | | field2: i32, -LL | | } - | |_^ - -error: missing documentation for a struct field - --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:23:5 - | -LL | field2: i32, - | ^^^^^^^^^^^ - -error: aborting due to 4 previous errors - diff --git a/tests/ui-toml/missing_docs_allow_unused/clippy.toml b/tests/ui-toml/missing_docs_in_private_items/allow_unused/clippy.toml similarity index 100% rename from tests/ui-toml/missing_docs_allow_unused/clippy.toml rename to tests/ui-toml/missing_docs_in_private_items/allow_unused/clippy.toml diff --git a/tests/ui-toml/pub_crate_missing_docs/clippy.toml b/tests/ui-toml/missing_docs_in_private_items/crate_root/clippy.toml similarity index 100% rename from tests/ui-toml/pub_crate_missing_docs/clippy.toml rename to tests/ui-toml/missing_docs_in_private_items/crate_root/clippy.toml diff --git a/tests/ui-toml/missing_docs_in_private_items/default/clippy.toml b/tests/ui-toml/missing_docs_in_private_items/default/clippy.toml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.allow_unused.stderr b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.allow_unused.stderr new file mode 100644 index 000000000000..b686288c7d27 --- /dev/null +++ b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.allow_unused.stderr @@ -0,0 +1,644 @@ +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:26:5 + | +LL | f3: u32, + | ^^ + | +note: the lint level is defined here + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:8:9 + | +LL | #![deny(clippy::missing_docs_in_private_items)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:60:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:77:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:78:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:117:4 + | +LL | fn fn_crate() {} + | ^^^^^^^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:118:7 + | +LL | const CONST_CRATE: u32 = 0; + | ^^^^^^^^^^^ + +error: missing documentation for a static + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:119:8 + | +LL | static STATIC_CRATE: u32 = 0; + | ^^^^^^^^^^^^ + +error: missing documentation for a type alias + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:120:6 + | +LL | type TyAliasCrate = u32; + | ^^^^^^^^^^^^ + +error: missing documentation for a trait alias + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:121:7 + | +LL | trait TraitAliasCrate = Iterator; + | ^^^^^^^^^^^^^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:122:8 + | +LL | struct StructCrate; + | ^^^^^^^^^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:124:8 + | +LL | struct StructFieldCrate { + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:125:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:128:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:138:8 + | +LL | struct StructTupleCrate(u32, pub u32); + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:140:6 + | +LL | enum EnumCrate { + | ^^^^^^^^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:141:5 + | +LL | V1, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:142:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:144:5 + | +LL | V3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:145:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:155:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a union + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:161:7 + | +LL | union UnionCrate { + | ^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:162:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:165:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:176:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:177:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:182:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:183:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a trait + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:190:7 + | +LL | trait TraitCrate { + | ^^^^^^^^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:191:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:192:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:193:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:194:11 + | +LL | const C2: u32 = 0; + | ^^ + +error: missing documentation for an associated type + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:195:10 + | +LL | type T1; + | ^^ + +error: missing documentation for a macro + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:216:14 + | +LL | macro_rules! mac_rules_crate { + | ^^^^^^^^^^^^^^^ + +error: missing documentation for a macro + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:220:7 + | +LL | macro mac_crate { + | ^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:238:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:241:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:255:5 + | +LL | V1, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:256:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:258:5 + | +LL | V3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:259:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:269:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:276:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:279:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:290:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:291:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:296:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:297:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:305:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:306:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:307:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:308:11 + | +LL | const C2: u32 = 0; + | ^^ + +error: missing documentation for an associated type + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:309:10 + | +LL | type T1; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:541:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:567:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:588:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:591:12 + | +LL | struct S3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:592:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:595:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:600:10 + | +LL | enum E3 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:602:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:603:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:609:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:614:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:620:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:623:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:630:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:631:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:637:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a module + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:647:5 + | +LL | mod mod_crate { + | ^^^^^^^^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:648:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:651:16 + | +LL | pub struct S1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:652:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:655:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:660:14 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:662:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:663:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:669:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:674:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:680:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:683:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:690:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:691:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:697:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:705:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:708:12 + | +LL | struct S3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:709:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:712:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:717:10 + | +LL | enum E3 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:719:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:720:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:726:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:731:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:737:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:740:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:747:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:748:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:754:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1061:9 + | +LL | f2: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1062:20 + | +LL | pub(crate) f3: u32, + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1069:23 + | +LL | pub(crate) fn f2() {} + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1072:18 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1074:13 + | +LL | V2, + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1077:20 + | +LL | pub struct S2; + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1096:18 + | +LL | $(pub fn f2() {}) + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1165:20 + | +LL | pub struct VisFromOutside; + | ^^^^^^^^^^^^^^ + +error: aborting due to 106 previous errors + diff --git a/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.crate_root.stderr b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.crate_root.stderr new file mode 100644 index 000000000000..e95ce5615cce --- /dev/null +++ b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.crate_root.stderr @@ -0,0 +1,500 @@ +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:26:5 + | +LL | f3: u32, + | ^^ + | +note: the lint level is defined here + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:8:9 + | +LL | #![deny(clippy::missing_docs_in_private_items)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:32:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:60:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:66:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:77:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:78:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:117:4 + | +LL | fn fn_crate() {} + | ^^^^^^^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:118:7 + | +LL | const CONST_CRATE: u32 = 0; + | ^^^^^^^^^^^ + +error: missing documentation for a static + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:119:8 + | +LL | static STATIC_CRATE: u32 = 0; + | ^^^^^^^^^^^^ + +error: missing documentation for a type alias + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:120:6 + | +LL | type TyAliasCrate = u32; + | ^^^^^^^^^^^^ + +error: missing documentation for a trait alias + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:121:7 + | +LL | trait TraitAliasCrate = Iterator; + | ^^^^^^^^^^^^^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:122:8 + | +LL | struct StructCrate; + | ^^^^^^^^^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:124:8 + | +LL | struct StructFieldCrate { + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:125:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:128:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:131:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:134:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:138:8 + | +LL | struct StructTupleCrate(u32, pub u32); + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:140:6 + | +LL | enum EnumCrate { + | ^^^^^^^^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:141:5 + | +LL | V1, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:142:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:144:5 + | +LL | V3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:145:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:155:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a union + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:161:7 + | +LL | union UnionCrate { + | ^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:162:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:165:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:168:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:171:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:176:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:177:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:182:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:183:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a trait + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:190:7 + | +LL | trait TraitCrate { + | ^^^^^^^^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:191:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:192:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:193:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:194:11 + | +LL | const C2: u32 = 0; + | ^^ + +error: missing documentation for an associated type + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:195:10 + | +LL | type T1; + | ^^ + +error: missing documentation for a macro + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:216:14 + | +LL | macro_rules! mac_rules_crate { + | ^^^^^^^^^^^^^^^ + +error: missing documentation for a macro + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:220:7 + | +LL | macro mac_crate { + | ^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:238:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:241:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:244:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:247:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:255:5 + | +LL | V1, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:256:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:258:5 + | +LL | V3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:259:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:269:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:276:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:279:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:282:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:285:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:290:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:291:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:296:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:297:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:305:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:306:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:307:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:308:11 + | +LL | const C2: u32 = 0; + | ^^ + +error: missing documentation for an associated type + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:309:10 + | +LL | type T1; + | ^^ + +error: missing documentation for a module + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:647:5 + | +LL | mod mod_crate { + | ^^^^^^^^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:648:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:651:16 + | +LL | pub struct S1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:652:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:660:14 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:662:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:663:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:669:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:674:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:680:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:690:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:691:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:697:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1062:20 + | +LL | pub(crate) f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1072:18 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1074:13 + | +LL | V2, + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1077:20 + | +LL | pub struct S2; + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1096:18 + | +LL | $(pub fn f2() {}) + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1165:20 + | +LL | pub struct VisFromOutside; + | ^^^^^^^^^^^^^^ + +error: aborting due to 82 previous errors + diff --git a/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.default.stderr b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.default.stderr new file mode 100644 index 000000000000..44a3d29580ad --- /dev/null +++ b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.default.stderr @@ -0,0 +1,704 @@ +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:26:5 + | +LL | f3: u32, + | ^^ + | +note: the lint level is defined here + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:8:9 + | +LL | #![deny(clippy::missing_docs_in_private_items)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:32:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:60:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:66:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:77:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:78:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:117:4 + | +LL | fn fn_crate() {} + | ^^^^^^^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:118:7 + | +LL | const CONST_CRATE: u32 = 0; + | ^^^^^^^^^^^ + +error: missing documentation for a static + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:119:8 + | +LL | static STATIC_CRATE: u32 = 0; + | ^^^^^^^^^^^^ + +error: missing documentation for a type alias + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:120:6 + | +LL | type TyAliasCrate = u32; + | ^^^^^^^^^^^^ + +error: missing documentation for a trait alias + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:121:7 + | +LL | trait TraitAliasCrate = Iterator; + | ^^^^^^^^^^^^^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:122:8 + | +LL | struct StructCrate; + | ^^^^^^^^^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:124:8 + | +LL | struct StructFieldCrate { + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:125:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:128:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:131:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:134:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:138:8 + | +LL | struct StructTupleCrate(u32, pub u32); + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:140:6 + | +LL | enum EnumCrate { + | ^^^^^^^^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:141:5 + | +LL | V1, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:142:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:144:5 + | +LL | V3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:145:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:155:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a union + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:161:7 + | +LL | union UnionCrate { + | ^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:162:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:165:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:168:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:171:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:176:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:177:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:182:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:183:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a trait + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:190:7 + | +LL | trait TraitCrate { + | ^^^^^^^^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:191:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:192:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:193:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:194:11 + | +LL | const C2: u32 = 0; + | ^^ + +error: missing documentation for an associated type + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:195:10 + | +LL | type T1; + | ^^ + +error: missing documentation for a macro + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:216:14 + | +LL | macro_rules! mac_rules_crate { + | ^^^^^^^^^^^^^^^ + +error: missing documentation for a macro + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:220:7 + | +LL | macro mac_crate { + | ^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:238:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:241:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:244:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:247:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:255:5 + | +LL | V1, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:256:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:258:5 + | +LL | V3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:259:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:269:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:276:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:279:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:282:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:285:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:290:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:291:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:296:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:297:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:305:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:306:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:307:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:308:11 + | +LL | const C2: u32 = 0; + | ^^ + +error: missing documentation for an associated type + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:309:10 + | +LL | type T1; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:541:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:567:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:588:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:591:12 + | +LL | struct S3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:592:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:595:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:600:10 + | +LL | enum E3 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:602:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:603:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:609:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:614:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:620:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:623:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:630:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:631:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:637:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a module + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:647:5 + | +LL | mod mod_crate { + | ^^^^^^^^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:648:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:651:16 + | +LL | pub struct S1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:652:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:655:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:660:14 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:662:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:663:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:669:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:674:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:680:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:683:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:690:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:691:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:697:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:705:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:708:12 + | +LL | struct S3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:709:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:712:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:717:10 + | +LL | enum E3 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:719:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:720:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:726:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:731:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:737:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:740:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:747:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:748:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:754:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1061:9 + | +LL | f2: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1062:20 + | +LL | pub(crate) f3: u32, + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1069:23 + | +LL | pub(crate) fn f2() {} + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1072:18 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1074:13 + | +LL | V2, + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1077:20 + | +LL | pub struct S2; + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1096:18 + | +LL | $(pub fn f2() {}) + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1165:20 + | +LL | pub struct VisFromOutside; + | ^^^^^^^^^^^^^^ + +error: aborting due to 116 previous errors + diff --git a/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs new file mode 100644 index 000000000000..0a7730a4ee7f --- /dev/null +++ b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs @@ -0,0 +1,1167 @@ +//@aux-build:../../ui/auxiliary/proc_macros.rs +//@revisions: default crate_root allow_unused +//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/missing_docs_in_private_items/default +//@[crate_root] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/missing_docs_in_private_items/crate_root +//@[allow_unused] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/missing_docs_in_private_items/allow_unused + +#![feature(decl_macro, trait_alias)] +#![deny(clippy::missing_docs_in_private_items)] +#![allow(non_local_definitions)] + +extern crate proc_macros; +use proc_macros::{external, with_span}; + +fn main() {} + +pub fn fn_pub() {} +pub const CONST_PUB: u32 = 0; +pub static STATIC_PUB: u32 = 0; +pub type TyAliasPub = u32; +pub trait TraitAliasPub = Iterator; +pub struct StructPub; +pub struct StructFieldPub { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + pub _f5: u32, + /// docs + pub _f6: u32, + _f7: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + _f8: u32, +} +pub struct StructTuplePub(u32, pub u32); +pub enum EnumPub { + V1, + V2(u32), + V3 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V4, + /// docs + V5(u32), + /// docs + V6 { + f1: u32, + /// docs + f2: u32, + }, +} +pub union UnionPub { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + pub _f5: u32, + /// docs + pub _f6: u32, + _f7: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + _f8: u32, +} +impl StructFieldPub { + pub fn f1() {} + pub const C1: u32 = 0; + /// docs + pub fn f2() {} + /// docs + pub const C2: u32 = 0; + fn f3() {} //~ missing_docs_in_private_items + const C3: u32 = 0; //~ missing_docs_in_private_items + /// docs + fn f4() {} + /// docs + const C4: u32 = 0; +} +pub trait TraitPub { + fn f1(); + fn f2() {} + const C1: u32; + const C2: u32 = 0; + type T1; + /// docs + fn f3(); + /// docs + fn f4() {} + /// docs + const C3: u32; + /// docs + const C4: u32 = 0; + /// docs + type T2; +} +impl TraitPub for StructPub { + fn f1() {} + const C1: u32 = 0; + type T1 = u32; + fn f3() {} + const C3: u32 = 0; + type T2 = u32; +} +#[macro_export] +macro_rules! mac_rules_pub { + () => {}; +} +pub macro mac_pub { + () => {}, +} + +fn fn_crate() {} //~ missing_docs_in_private_items +const CONST_CRATE: u32 = 0; //~ missing_docs_in_private_items +static STATIC_CRATE: u32 = 0; //~ missing_docs_in_private_items +type TyAliasCrate = u32; //~ missing_docs_in_private_items +trait TraitAliasCrate = Iterator; //~ missing_docs_in_private_items +struct StructCrate; //~ missing_docs_in_private_items +//~v missing_docs_in_private_items +struct StructFieldCrate { + pub f1: u32, //~ missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + pub _f5: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + pub _f6: u32, + _f7: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + _f8: u32, +} +struct StructTupleCrate(u32, pub u32); //~ missing_docs_in_private_items +//~v missing_docs_in_private_items +enum EnumCrate { + V1, //~ missing_docs_in_private_items + V2(u32), //~ missing_docs_in_private_items + //~v missing_docs_in_private_items + V3 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V4, + /// docs + V5(u32), + /// docs + V6 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, +} +//~v missing_docs_in_private_items +union UnionCrate { + pub f1: u32, //~ missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + pub _f5: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + pub _f6: u32, + _f7: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + _f8: u32, +} +impl StructFieldCrate { + pub fn f1() {} //~ missing_docs_in_private_items + pub const C1: u32 = 0; //~ missing_docs_in_private_items + /// docs + pub fn f2() {} + /// docs + pub const C2: u32 = 0; + fn f3() {} //~ missing_docs_in_private_items + const C3: u32 = 0; //~ missing_docs_in_private_items + /// docs + fn f4() {} + /// docs + const C4: u32 = 0; +} +//~v missing_docs_in_private_items +trait TraitCrate { + fn f1(); //~ missing_docs_in_private_items + fn f2() {} //~ missing_docs_in_private_items + const C1: u32; //~ missing_docs_in_private_items + const C2: u32 = 0; //~ missing_docs_in_private_items + type T1; //~ missing_docs_in_private_items + /// docs + fn f3(); + /// docs + fn f4() {} + /// docs + const C3: u32; + /// docs + const C4: u32 = 0; + /// docs + type T2; +} +impl TraitCrate for StructCrate { + fn f1() {} + const C1: u32 = 0; + type T1 = u32; + fn f3() {} + const C3: u32 = 0; + type T2 = u32; +} +//~v missing_docs_in_private_items +macro_rules! mac_rules_crate { + () => {}; +} +//~v missing_docs_in_private_items +macro mac_crate { + () => {}, +} + +/// docs +fn fn_crate_doc() {} +/// docs +const CONST_CRATE_DOC: u32 = 0; +/// docs +static STATIC_CRATE_DOC: u32 = 0; +/// docs +type TyAliasCrateDoc = u32; +/// docs +trait TraitAliasCrateDoc = Iterator; +/// docs +struct StructCrateDoc; +/// docs +struct StructFieldCrateDoc { + pub f1: u32, //~ missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + pub _f5: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + pub _f6: u32, + _f7: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + _f8: u32, +} +/// docs +struct StructTupleCrateDoc(u32, pub u32); +/// docs +enum EnumCrateDoc { + V1, //~ missing_docs_in_private_items + V2(u32), //~ missing_docs_in_private_items + //~v missing_docs_in_private_items + V3 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V4, + /// docs + V5(u32), + /// docs + V6 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, +} +/// docs +union UnionCrateDoc { + pub f1: u32, //~ missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + pub _f5: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + pub _f6: u32, + _f7: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + _f8: u32, +} +impl StructFieldCrateDoc { + pub fn f1() {} //~ missing_docs_in_private_items + pub const C1: u32 = 0; //~ missing_docs_in_private_items + /// docs + pub fn f2() {} + /// docs + pub const C2: u32 = 0; + fn f3() {} //~ missing_docs_in_private_items + const C3: u32 = 0; //~ missing_docs_in_private_items + /// docs + fn f4() {} + /// docs + const C4: u32 = 0; +} +/// docs +trait TraitCrateDoc { + fn f1(); //~ missing_docs_in_private_items + fn f2() {} //~ missing_docs_in_private_items + const C1: u32; //~ missing_docs_in_private_items + const C2: u32 = 0; //~ missing_docs_in_private_items + type T1; //~ missing_docs_in_private_items + /// docs + fn f3(); + /// docs + fn f4() {} + /// docs + const C3: u32; + /// docs + const C4: u32 = 0; + /// docs + type T2; +} +impl TraitCrate for StructCrateDoc { + fn f1() {} + const C1: u32 = 0; + type T1 = u32; + fn f3() {} + const C3: u32 = 0; + type T2 = u32; +} +/// docs +macro_rules! mac_rules_crate_doc { + () => {}; +} +/// docs +macro mac_crate_doc { + () => {}, +} + +#[doc(hidden)] +fn fn_crate_hidden() {} +#[doc(hidden)] +const CONST_CRATE_HIDDEN: u32 = 0; +#[doc(hidden)] +static STATIC_CRATE_HIDDEN: u32 = 0; +#[doc(hidden)] +type TyAliasCrateHidden = u32; +#[doc(hidden)] +trait TraitAliasCrateHidden = Iterator; +#[doc(hidden)] +struct StructCrateHidden; +#[doc(hidden)] +struct StructFieldCrateHidden { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, + /// docs + f4: u32, + pub _f5: u32, + /// docs + pub _f6: u32, + _f7: u32, + /// docs + _f8: u32, +} +#[doc(hidden)] +struct StructTupleCrateHidden(u32, pub u32); +#[doc(hidden)] +enum EnumCrateHidden { + V1, + V2(u32), + V3 { + f1: u32, + /// docs + f2: u32, + }, + V4, + V5(u32), + /// docs + V6 { + f1: u32, + /// docs + f2: u32, + }, +} +#[doc(hidden)] +union UnionCrateHidden { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, + /// docs + f4: u32, + pub _f5: u32, + /// docs + pub _f6: u32, + _f7: u32, + /// docs + _f8: u32, +} +#[doc(hidden)] +impl StructFieldCrateHidden { + pub fn f1() {} + pub const C1: u32 = 0; + /// docs + pub fn f2() {} + /// docs + pub const C2: u32 = 0; + fn f3() {} + const C3: u32 = 0; + /// docs + fn f4() {} + /// docs + const C4: u32 = 0; +} +#[doc(hidden)] +trait TraitCrateHidden { + fn f1(); + fn f2() {} + const C1: u32; + const C2: u32 = 0; + type T1; + /// docs + fn f3(); + /// docs + fn f4() {} + /// docs + const C3: u32; + /// docs + const C4: u32 = 0; + /// docs + type T2; +} +#[doc(hidden)] +macro_rules! mac_rules_crate_hidden { + () => {}; +} +#[doc(hidden)] +macro mac_crate_hidden { + () => {}, +} + +#[expect(clippy::missing_docs_in_private_items)] +fn fn_crate_expect() {} +#[expect(clippy::missing_docs_in_private_items)] +const CONST_CRATE_EXPECT: u32 = 0; +#[expect(clippy::missing_docs_in_private_items)] +static STATIC_CRATE_EXPECT: u32 = 0; +#[expect(clippy::missing_docs_in_private_items)] +type TyAliasCrateExpect = u32; +#[expect(clippy::missing_docs_in_private_items)] +trait TraitAliasCrateExpect = Iterator; +#[expect(clippy::missing_docs_in_private_items)] +struct StructCrateExpect; +#[expect(clippy::missing_docs_in_private_items)] +struct StructFieldCrateExpect { + #[expect(clippy::missing_docs_in_private_items)] + pub f1: u32, + /// docs + pub f2: u32, + #[expect(clippy::missing_docs_in_private_items)] + f3: u32, + /// docs + f4: u32, +} +#[expect(clippy::missing_docs_in_private_items)] +struct StructTupleCrateExpect(u32, pub u32); +#[expect(clippy::missing_docs_in_private_items)] +enum EnumCrateExpect { + #[expect(clippy::missing_docs_in_private_items)] + V1, + #[expect(clippy::missing_docs_in_private_items)] + V2(u32), + #[expect(clippy::missing_docs_in_private_items)] + V3 { + #[expect(clippy::missing_docs_in_private_items)] + f1: u32, + /// docs + f2: u32, + }, + /// docs + V4, + /// docs + V5(u32), + /// docs + V6 { + #[expect(clippy::missing_docs_in_private_items)] + f1: u32, + /// docs + f2: u32, + }, +} +#[expect(clippy::missing_docs_in_private_items)] +union UnionCrateExpect { + #[expect(clippy::missing_docs_in_private_items)] + pub f1: u32, + /// docs + pub f2: u32, + #[expect(clippy::missing_docs_in_private_items)] + f3: u32, + /// docs + f4: u32, +} +impl StructFieldCrateExpect { + #[expect(clippy::missing_docs_in_private_items)] + pub fn f1() {} + #[expect(clippy::missing_docs_in_private_items)] + pub const C1: u32 = 0; + #[expect(clippy::missing_docs_in_private_items)] + fn f2() {} + #[expect(clippy::missing_docs_in_private_items)] + const C2: u32 = 0; +} +#[expect(clippy::missing_docs_in_private_items)] +trait TraitCrateExpect { + #[expect(clippy::missing_docs_in_private_items)] + fn f1(); + #[expect(clippy::missing_docs_in_private_items)] + fn f2() {} + #[expect(clippy::missing_docs_in_private_items)] + const C1: u32; + #[expect(clippy::missing_docs_in_private_items)] + const C2: u32 = 0; + #[expect(clippy::missing_docs_in_private_items)] + type T1; +} +#[expect(clippy::missing_docs_in_private_items)] +macro_rules! mac_rules_crate_expect { + () => {}; +} +#[expect(clippy::missing_docs_in_private_items)] +macro mac_crate_expect { + () => {}, +} + +pub mod mod_pub { + pub fn f1() {} + pub struct S1 { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + pub enum E1 { + V1 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, + /// docs + f2: u32, + }, + } + pub const C1: u32 = 0; + + /// docs + pub fn f2() {} + /// docs + pub struct S2 { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + /// docs + pub enum E2 { + V1 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, + /// docs + f2: u32, + }, + } + /// docs + pub const C2: u32 = 0; + + fn f3() {} //~[default,allow_unused] missing_docs_in_private_items + // + //~[default,allow_unused]v missing_docs_in_private_items + struct S3 { + pub f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + //~[default,allow_unused]v missing_docs_in_private_items + enum E3 { + //~[default,allow_unused]v missing_docs_in_private_items + V1 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + } + const C3: u32 = 0; //~[default,allow_unused] missing_docs_in_private_items + + /// docs + fn f4() {} + /// docs + struct S4 { + pub f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + /// docs + enum E4 { + //~[default,allow_unused]v missing_docs_in_private_items + V1 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + } + /// docs + const C4: u32 = 0; +} + +//~v missing_docs_in_private_items +mod mod_crate { + pub fn f1() {} //~ missing_docs_in_private_items + // + //~v missing_docs_in_private_items + pub struct S1 { + pub f1: u32, //~ missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + //~v missing_docs_in_private_items + pub enum E1 { + //~v missing_docs_in_private_items + V1 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, + } + pub const C1: u32 = 0; //~ missing_docs_in_private_items + + /// docs + pub fn f2() {} + /// docs + pub struct S2 { + pub f1: u32, //~ missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + /// docs + pub enum E2 { + //~v missing_docs_in_private_items + V1 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, + } + /// docs + pub const C2: u32 = 0; + + fn f3() {} //~[default,allow_unused] missing_docs_in_private_items + // + //~[default,allow_unused]v missing_docs_in_private_items + struct S3 { + pub f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + //~[default,allow_unused]v missing_docs_in_private_items + enum E3 { + //~[default,allow_unused]v missing_docs_in_private_items + V1 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + } + const C3: u32 = 0; //~[default,allow_unused] missing_docs_in_private_items + + /// docs + fn f4() {} + /// docs + struct S4 { + pub f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + /// docs + enum E4 { + //~[default,allow_unused]v missing_docs_in_private_items + V1 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + } + /// docs + const C4: u32 = 0; +} + +/// docs +mod mod_crate_doc {} + +#[doc(hidden)] +mod mod_crate_hidden { + pub fn f1() {} + pub struct S1 { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, + /// docs + f4: u32, + } + pub enum E1 { + V1 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, + /// docs + f2: u32, + }, + } + pub const C1: u32 = 0; + + /// docs + pub fn f2() {} + /// docs + pub struct S2 { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, + /// docs + f4: u32, + } + /// docs + pub enum E2 { + V1 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, + /// docs + f2: u32, + }, + } + /// docs + pub const C2: u32 = 0; + + fn f3() {} + struct S3 { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, + /// docs + f4: u32, + } + enum E3 { + V1 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, + /// docs + f2: u32, + }, + } + const C3: u32 = 0; + + /// docs + fn f4() {} + /// docs + struct S4 { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, + /// docs + f4: u32, + } + /// docs + enum E4 { + V1 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, + /// docs + f2: u32, + }, + } + /// docs + const C4: u32 = 0; +} + +#[expect(clippy::missing_docs_in_private_items)] +mod mod_crate_expect {} + +#[doc = "docs"] +mod explicit_doc_attr {} + +with_span! { + sp + fn fn_pm() {} + const CONST_PM: u32 = 0; + static STATIC_PM: u32 = 0; + type TyAliasPm = u32; + trait TraitAliasPm = Iterator; + struct StructPm; + struct StructFieldPm { + pub f1: u32, + f2: u32, + pub _f3: u32, + _f4: u32, + } + struct StructTuplePm(u32, pub u32); + enum EnumPm { + V1, + V2(u32), + V3 { f1: u32, }, + } + union UnionPm { + pub f1: u32, + f2: u32, + pub _f3: u32, + _f4: u32, + } + impl StructFieldPm { + pub fn f1() {} + pub const C1: u32 = 0; + fn f2() {} + const C2: u32 = 0; + } + trait TraitPm { + fn f1(); + fn f2() {} + const C1: u32; + const C2: u32 = 0; + type T1; + } + impl TraitPm for StructPm { + fn f1() {} + const C1: u32 = 0; + type T1 = u32; + } + macro_rules! mac_rules_pm { + () => {}; + } + macro mac_pm { + () => {}, + } + mod mod_pm {} +} + +external! { + fn fn_external() {} + const CONST_EXTERNAL: u32 = 0; + static STATIC_EXTERNAL: u32 = 0; + type TyAliasExternal = u32; + trait TraitAliasExternal = Iterator; + struct StructExternal; + struct StructFieldExternal { + pub f1: u32, + f2: u32, + pub _f3: u32, + _f4: u32, + } + struct StructTupleExternal(u32, pub u32); + enum EnumExternal { + V1, + V2(u32), + V3 { f1: u32, }, + } + union UnionExternal { + pub f1: u32, + f2: u32, + pub _f3: u32, + _f4: u32, + } + impl StructFieldExternal { + pub fn f1() {} + pub const C1: u32 = 0; + fn f2() {} + const C2: u32 = 0; + } + trait TraitExternal { + fn f1(); + fn f2() {} + const C1: u32; + const C2: u32 = 0; + type T1; + } + impl TraitExternal for StructExternal { + fn f1() {} + const C1: u32 = 0; + type T1 = u32; + } + macro_rules! mac_rules_external { + () => {}; + } + macro mac_external { + () => {}, + } + mod mod_external {} +} + +pub const _: () = {}; +const _: () = {}; + +/// docs +fn fn_with_items() { + fn f() {} + type T = u32; + struct S { + f1: u32, + f2: u32, + } + enum E { + V { f: u32 }, + } + impl S { + fn f() {} + const C: u32 = 0; + } + const C: u32 = 0; + static ST: u32 = 0; + trait Tr { + fn f(); + type T; + const C: u32; + } + trait Tr2 = Tr; + mod m {} + macro_rules! m2 { + () => {}; + } + macro m3 { () => {}, } + union U { + f: u32, + } +} +/// docs +const CONST_WITH_ITEMS: () = { + fn f() {} +}; +/// docs +static STATIC_WITH_ITEMS: () = { + fn f() {} +}; +/// docs +trait TraitWithItems { + /// docs + fn f() { + fn f() {} + } + /// docs + const C: () = { + fn f() {} + }; +} +/// docs +struct StructWithItems; +impl StructWithItems { + /// docs + fn f() { + fn f() {} + } + /// docs + const C: () = { + fn f() {} + }; +} +/// docs +type TypeAliasWithItems = [u32; { + fn f() {} + 1 +}]; + +/// docs +mod with_reexports { + pub fn f1_reexport() {} + pub struct S1Reexport { + pub f1: u32, + f2: u32, //~[default,allow_unused] missing_docs_in_private_items + pub(crate) f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + } + + /// docs + mod m1 { + pub(crate) fn f2() {} //~[default,allow_unused] missing_docs_in_private_items + + //~v missing_docs_in_private_items + pub enum E1 { + V1Reexport, + V2, //~ missing_docs_in_private_items + } + + pub struct S2; //~ missing_docs_in_private_items + pub fn f3_reexport() -> S2 { + S2 + } + } + pub use m1::E1::{V1Reexport, V2}; + use m1::f2; + pub use m1::f3_reexport; +} +pub use with_reexports::{S1Reexport, V1Reexport, f1_reexport, f3_reexport}; + +external! { + mod mod_generated { + $(type T = u32;) + struct S { + $(f1: u32,) + f2: u32, + } + pub fn f() {} + $(pub fn f2() {}) //~ missing_docs_in_private_items + #[doc(hidden)] + $(pub fn f3() {}) + } +} + +/// docs +mod mod_with_hidden { + #[doc(hidden)] + pub mod m { + pub struct S { + #[doc(hidden)] + pub f: u32, + } + #[automatically_derived] + impl S { + #[doc(hidden)] + pub fn f() {} + pub const C: () = { + #[automatically_derived] + impl S { + #[doc(hidden)] + pub fn f2() { + mod m { + pub(crate) union U { + pub f: u32, + } + } + } + } + }; + } + } + #[doc(hidden)] + pub(crate) fn f() {} +} + +/// docs +struct WithProject { + /// docs + a: u32, + /// docs + b: u32, +} +with_span! { + span + const _: () = { + // Similar output to pin_project + struct Project<'a> { + $(a: &'a u32), + $(b: &'a u32), + } + impl $(WithProject) { + fn project(&self) -> Project<'_> { + Project { + a: &self.a, + b: &self.b, + } + } + } + }; +} + +external! { + mod mod_mac_with_pub {$( + struct DerivedFromInput; + impl DerivedFromInput { + pub fn foo() {} + } + pub struct VisFromOutside; //~ missing_docs_in_private_items + )} +} diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs deleted file mode 100644 index 6a1d2b51abc8..000000000000 --- a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! this is crate -#![allow(missing_docs)] -#![allow(clippy::struct_field_names)] -#![warn(clippy::missing_docs_in_private_items)] - -/// this is mod -mod my_mod { - /// some docs - fn priv_with_docs() {} - fn priv_no_docs() {} - /// some docs - pub(crate) fn crate_with_docs() {} - pub(crate) fn crate_no_docs() {} - //~^ missing_docs_in_private_items - /// some docs - pub(super) fn super_with_docs() {} - pub(super) fn super_no_docs() {} - //~^ missing_docs_in_private_items - - mod my_sub { - /// some docs - fn sub_priv_with_docs() {} - fn sub_priv_no_docs() {} - /// some docs - pub(crate) fn sub_crate_with_docs() {} - pub(crate) fn sub_crate_no_docs() {} - //~^ missing_docs_in_private_items - /// some docs - pub(super) fn sub_super_with_docs() {} - pub(super) fn sub_super_no_docs() {} - } - - /// some docs - pub(crate) struct CrateStructWithDocs { - /// some docs - pub(crate) crate_field_with_docs: (), - pub(crate) crate_field_no_docs: (), - //~^ missing_docs_in_private_items - /// some docs - priv_field_with_docs: (), - priv_field_no_docs: (), - } - - pub(crate) struct CrateStructNoDocs { - //~^ missing_docs_in_private_items - /// some docs - pub(crate) crate_field_with_docs: (), - pub(crate) crate_field_no_docs: (), - //~^ missing_docs_in_private_items - /// some docs - priv_field_with_docs: (), - priv_field_no_docs: (), - } -} - -/// some docs -type CrateTypedefWithDocs = String; -type CrateTypedefNoDocs = String; -//~^ missing_docs_in_private_items -/// some docs -pub type PubTypedefWithDocs = String; -pub type PubTypedefNoDocs = String; - -fn main() { - my_mod::crate_with_docs(); - my_mod::crate_no_docs(); -} diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr deleted file mode 100644 index 0d70276de42d..000000000000 --- a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error: missing documentation for a function - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:13:5 - | -LL | pub(crate) fn crate_no_docs() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` - -error: missing documentation for a function - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:17:5 - | -LL | pub(super) fn super_no_docs() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a function - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:26:9 - | -LL | pub(crate) fn sub_crate_no_docs() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a struct field - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:37:9 - | -LL | pub(crate) crate_field_no_docs: (), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a struct - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:44:5 - | -LL | / pub(crate) struct CrateStructNoDocs { -LL | | -LL | | /// some docs -LL | | pub(crate) crate_field_with_docs: (), -... | -LL | | priv_field_no_docs: (), -LL | | } - | |_____^ - -error: missing documentation for a struct field - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:48:9 - | -LL | pub(crate) crate_field_no_docs: (), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a type alias - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:58:1 - | -LL | type CrateTypedefNoDocs = String; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 7 previous errors - diff --git a/tests/ui-toml/result_large_err/clippy.toml b/tests/ui-toml/result_large_err/clippy.toml index df505ed9672a..80eeac0f9870 100644 --- a/tests/ui-toml/result_large_err/clippy.toml +++ b/tests/ui-toml/result_large_err/clippy.toml @@ -1 +1,2 @@ large-error-threshold = 512 +large-error-ignored = ["result_large_err::IgnoredError", "result_large_err::IgnoredErrorEnum"] diff --git a/tests/ui-toml/result_large_err/result_large_err.rs b/tests/ui-toml/result_large_err/result_large_err.rs index dea4d61a96bf..170f37db7593 100644 --- a/tests/ui-toml/result_large_err/result_large_err.rs +++ b/tests/ui-toml/result_large_err/result_large_err.rs @@ -1,4 +1,6 @@ +//@compile-flags: --crate-name result_large_err #![warn(clippy::result_large_err)] +#![allow(clippy::large_enum_variant)] fn f() -> Result<(), [u8; 511]> { todo!() @@ -7,4 +9,22 @@ //~^ ERROR: the `Err`-variant returned from this function is very large todo!() } + +struct IgnoredError { + inner: [u8; 512], +} + +fn f3() -> Result<(), IgnoredError> { + todo!() +} + +enum IgnoredErrorEnum { + V1, + V2 { inner: [u8; 512] }, +} + +fn f4() -> Result<(), IgnoredErrorEnum> { + todo!() +} + fn main() {} diff --git a/tests/ui-toml/result_large_err/result_large_err.stderr b/tests/ui-toml/result_large_err/result_large_err.stderr index 656ce7ab7f2f..7e5954f885b8 100644 --- a/tests/ui-toml/result_large_err/result_large_err.stderr +++ b/tests/ui-toml/result_large_err/result_large_err.stderr @@ -1,5 +1,5 @@ error: the `Err`-variant returned from this function is very large - --> tests/ui-toml/result_large_err/result_large_err.rs:6:12 + --> tests/ui-toml/result_large_err/result_large_err.rs:8:12 | LL | fn f2() -> Result<(), [u8; 512]> { | ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 2d9503c5ac53..d5040f4a39bf 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -50,6 +50,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect future-size-threshold ignore-interior-mutability inherent-impl-lint-scope + large-error-ignored large-error-threshold lint-commented-code literal-representation-threshold @@ -147,6 +148,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect future-size-threshold ignore-interior-mutability inherent-impl-lint-scope + large-error-ignored large-error-threshold lint-commented-code literal-representation-threshold @@ -244,6 +246,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni future-size-threshold ignore-interior-mutability inherent-impl-lint-scope + large-error-ignored large-error-threshold lint-commented-code literal-representation-threshold diff --git a/tests/ui/blanket_clippy_restriction_lints.rs b/tests/ui/blanket_clippy_restriction_lints.rs index de699309b16d..1cd45685609f 100644 --- a/tests/ui/blanket_clippy_restriction_lints.rs +++ b/tests/ui/blanket_clippy_restriction_lints.rs @@ -3,7 +3,7 @@ #![warn(clippy::blanket_clippy_restriction_lints)] -//! Test that the whole restriction group is not enabled +//! Test that the whole restriction group is not enabled. #![warn(clippy::restriction)] //~^ blanket_clippy_restriction_lints #![deny(clippy::restriction)] diff --git a/tests/ui/byte_char_slices.fixed b/tests/ui/byte_char_slices.fixed index b0c1b1f034b4..87934d6362f7 100644 --- a/tests/ui/byte_char_slices.fixed +++ b/tests/ui/byte_char_slices.fixed @@ -1,4 +1,3 @@ -#![allow(unused)] #![warn(clippy::byte_char_slices)] fn main() { diff --git a/tests/ui/byte_char_slices.rs b/tests/ui/byte_char_slices.rs index 0d6953dda97e..0de7cf66fda8 100644 --- a/tests/ui/byte_char_slices.rs +++ b/tests/ui/byte_char_slices.rs @@ -1,4 +1,3 @@ -#![allow(unused)] #![warn(clippy::byte_char_slices)] fn main() { diff --git a/tests/ui/byte_char_slices.stderr b/tests/ui/byte_char_slices.stderr index 2556aa9c0f76..c1b7e4ca2f17 100644 --- a/tests/ui/byte_char_slices.stderr +++ b/tests/ui/byte_char_slices.stderr @@ -1,5 +1,5 @@ error: can be more succinctly written as a byte str - --> tests/ui/byte_char_slices.rs:5:15 + --> tests/ui/byte_char_slices.rs:4:15 | LL | let bad = &[b'a', b'b', b'c']; | ^^^^^^^^^^^^^^^^^^^ help: try: `b"abc"` @@ -8,25 +8,25 @@ LL | let bad = &[b'a', b'b', b'c']; = help: to override `-D warnings` add `#[allow(clippy::byte_char_slices)]` error: can be more succinctly written as a byte str - --> tests/ui/byte_char_slices.rs:7:18 + --> tests/ui/byte_char_slices.rs:6:18 | LL | let quotes = &[b'"', b'H', b'i']; | ^^^^^^^^^^^^^^^^^^^ help: try: `b"\"Hi"` error: can be more succinctly written as a byte str - --> tests/ui/byte_char_slices.rs:9:18 + --> tests/ui/byte_char_slices.rs:8:18 | LL | let quotes = &[b'\'', b'S', b'u', b'p']; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"'Sup"` error: can be more succinctly written as a byte str - --> tests/ui/byte_char_slices.rs:11:19 + --> tests/ui/byte_char_slices.rs:10:19 | LL | let escapes = &[b'\x42', b'E', b's', b'c']; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"\x42Esc"` error: useless use of `vec!` - --> tests/ui/byte_char_slices.rs:15:16 + --> tests/ui/byte_char_slices.rs:14:16 | LL | let good = vec![b'a', b'a']; | ^^^^^^^^^^^^^^^^ help: you can use an array directly: `[b'a', b'a']` diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index fab02bf7b24e..ff2791c45730 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -582,3 +582,13 @@ fn msrv_doesnt_supports_cast_signed() { //~^ cast_possible_wrap } } + +fn issue16045() { + fn f() -> Result<(), ()> { + let val = Ok::<_, ()>(0u8); + _ = val? as i8; + //~^ cast_possible_wrap + + Ok(()) + } +} diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 8c48855123f9..0ff1dc11c3ac 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -764,5 +764,11 @@ error: casting `u8` to `i8` may wrap around the value LL | _ = 1u8 as i8; | ^^^^^^^^^ -error: aborting due to 94 previous errors +error: casting `u8` to `i8` may wrap around the value + --> tests/ui/cast.rs:589:13 + | +LL | _ = val? as i8; + | ^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `val?.cast_signed()` + +error: aborting due to 95 previous errors diff --git a/tests/ui/checked_unwrap/complex_conditionals.rs b/tests/ui/checked_unwrap/complex_conditionals.rs index 7d0bcc547a42..d1db2e67e269 100644 --- a/tests/ui/checked_unwrap/complex_conditionals.rs +++ b/tests/ui/checked_unwrap/complex_conditionals.rs @@ -1,27 +1,19 @@ -#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] -#![allow( - clippy::if_same_then_else, - clippy::branches_sharing_code, - clippy::unnecessary_literal_unwrap -)] +#![warn(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] +#![expect(clippy::branches_sharing_code, clippy::unnecessary_literal_unwrap)] fn test_complex_conditions() { let x: Result<(), ()> = Ok(()); let y: Result<(), ()> = Ok(()); if x.is_ok() && y.is_err() { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap - // will panic x.unwrap_err(); //~^ panicking_unwrap - // will panic y.unwrap(); //~^ panicking_unwrap - // unnecessary y.unwrap_err(); //~^ unnecessary_unwrap } else { @@ -37,45 +29,35 @@ fn test_complex_conditions() { x.unwrap(); y.unwrap(); } else { - // will panic x.unwrap(); //~^ panicking_unwrap - // unnecessary x.unwrap_err(); //~^ unnecessary_unwrap - // will panic y.unwrap(); //~^ panicking_unwrap - // unnecessary y.unwrap_err(); //~^ unnecessary_unwrap } let z: Result<(), ()> = Ok(()); if x.is_ok() && !(y.is_ok() || z.is_err()) { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap - // will panic x.unwrap_err(); //~^ panicking_unwrap - // will panic y.unwrap(); //~^ panicking_unwrap - // unnecessary y.unwrap_err(); //~^ unnecessary_unwrap - // unnecessary z.unwrap(); //~^ unnecessary_unwrap - // will panic z.unwrap_err(); //~^ panicking_unwrap } @@ -85,27 +67,21 @@ fn test_complex_conditions() { y.unwrap(); z.unwrap(); } else { - // will panic x.unwrap(); //~^ panicking_unwrap - // unnecessary x.unwrap_err(); //~^ unnecessary_unwrap - // unnecessary y.unwrap(); //~^ unnecessary_unwrap - // will panic y.unwrap_err(); //~^ panicking_unwrap - // will panic z.unwrap(); //~^ panicking_unwrap - // unnecessary z.unwrap_err(); //~^ unnecessary_unwrap } diff --git a/tests/ui/checked_unwrap/complex_conditionals.stderr b/tests/ui/checked_unwrap/complex_conditionals.stderr index d3905850c970..e154e3c35dc9 100644 --- a/tests/ui/checked_unwrap/complex_conditionals.stderr +++ b/tests/ui/checked_unwrap/complex_conditionals.stderr @@ -1,21 +1,17 @@ error: called `unwrap` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:13:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:8:9 | LL | if x.is_ok() && y.is_err() { | --------- the check is happening here -LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ | = help: try using `if let` or `match` -note: the lint level is defined here - --> tests/ui/checked_unwrap/complex_conditionals.rs:1:35 - | -LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::unnecessary-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap)]` error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:17:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:11:9 | LL | if x.is_ok() && y.is_err() { | --------- because of this check @@ -23,14 +19,11 @@ LL | if x.is_ok() && y.is_err() { LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ | -note: the lint level is defined here - --> tests/ui/checked_unwrap/complex_conditionals.rs:1:9 - | -LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::panicking-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::panicking_unwrap)]` error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:21:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:14:9 | LL | if x.is_ok() && y.is_err() { | ---------- because of this check @@ -39,7 +32,7 @@ LL | y.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `y` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/complex_conditionals.rs:25:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:17:9 | LL | if x.is_ok() && y.is_err() { | ---------- the check is happening here @@ -50,7 +43,7 @@ LL | y.unwrap_err(); = help: try using `if let` or `match` error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:41:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:32:9 | LL | if x.is_ok() || y.is_ok() { | --------- because of this check @@ -59,7 +52,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:45:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:35:9 | LL | if x.is_ok() || y.is_ok() { | --------- the check is happening here @@ -70,7 +63,7 @@ LL | x.unwrap_err(); = help: try using `if let` or `match` error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:49:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:38:9 | LL | if x.is_ok() || y.is_ok() { | --------- because of this check @@ -79,7 +72,7 @@ LL | y.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `y` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:53:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:41:9 | LL | if x.is_ok() || y.is_ok() { | --------- the check is happening here @@ -90,18 +83,17 @@ LL | y.unwrap_err(); = help: try using `if let` or `match` error: called `unwrap` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:59:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:46:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- the check is happening here -LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ | = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:63:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:49:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- because of this check @@ -110,7 +102,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:67:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:52:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- because of this check @@ -119,7 +111,7 @@ LL | y.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `y` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:71:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:55:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- the check is happening here @@ -130,7 +122,7 @@ LL | y.unwrap_err(); = help: try using `if let` or `match` error: called `unwrap` on `z` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/complex_conditionals.rs:75:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:58:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | ---------- the check is happening here @@ -141,7 +133,7 @@ LL | z.unwrap(); = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:79:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:61:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | ---------- because of this check @@ -150,7 +142,7 @@ LL | z.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:89:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:70:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- because of this check @@ -159,7 +151,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:93:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:73:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- the check is happening here @@ -170,7 +162,7 @@ LL | x.unwrap_err(); = help: try using `if let` or `match` error: called `unwrap` on `y` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:97:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:76:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- the check is happening here @@ -181,7 +173,7 @@ LL | y.unwrap(); = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:101:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:79:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- because of this check @@ -190,7 +182,7 @@ LL | y.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:105:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:82:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | ---------- because of this check @@ -199,7 +191,7 @@ LL | z.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `z` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/complex_conditionals.rs:109:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:85:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | ---------- the check is happening here diff --git a/tests/ui/checked_unwrap/complex_conditionals_nested.rs b/tests/ui/checked_unwrap/complex_conditionals_nested.rs index 7635f848cb34..6789e7c262b3 100644 --- a/tests/ui/checked_unwrap/complex_conditionals_nested.rs +++ b/tests/ui/checked_unwrap/complex_conditionals_nested.rs @@ -1,19 +1,14 @@ -#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] -#![allow( - clippy::if_same_then_else, - clippy::branches_sharing_code, - clippy::unnecessary_literal_unwrap -)] //@no-rustfix: has placeholders +#![warn(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] +#![expect(clippy::branches_sharing_code, clippy::unnecessary_literal_unwrap)] + fn test_nested() { fn nested() { let x = Some(()); if x.is_some() { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap } else { - // will panic x.unwrap(); //~^ panicking_unwrap } diff --git a/tests/ui/checked_unwrap/complex_conditionals_nested.stderr b/tests/ui/checked_unwrap/complex_conditionals_nested.stderr index 329be4d36621..7e4ef049f4a5 100644 --- a/tests/ui/checked_unwrap/complex_conditionals_nested.stderr +++ b/tests/ui/checked_unwrap/complex_conditionals_nested.stderr @@ -1,20 +1,16 @@ error: called `unwrap` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:13:13 + --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:9:13 | LL | if x.is_some() { | -------------- help: try: `if let Some() = x` -LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ | -note: the lint level is defined here - --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:1:35 - | -LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::unnecessary-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap)]` error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:17:13 + --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:12:13 | LL | if x.is_some() { | ----------- because of this check @@ -22,11 +18,8 @@ LL | if x.is_some() { LL | x.unwrap(); | ^^^^^^^^^^ | -note: the lint level is defined here - --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:1:9 - | -LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::panicking-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::panicking_unwrap)]` error: aborting due to 2 previous errors diff --git a/tests/ui/checked_unwrap/if_let_chains.rs b/tests/ui/checked_unwrap/if_let_chains.rs index cfa7715965cd..5c20ebb80024 100644 --- a/tests/ui/checked_unwrap/if_let_chains.rs +++ b/tests/ui/checked_unwrap/if_let_chains.rs @@ -1,5 +1,5 @@ //@require-annotations-for-level: ERROR -#![deny(clippy::unnecessary_unwrap)] +#![warn(clippy::unnecessary_unwrap)] #[clippy::msrv = "1.85"] fn if_let_chains_unsupported(a: Option, b: Option) { diff --git a/tests/ui/checked_unwrap/if_let_chains.stderr b/tests/ui/checked_unwrap/if_let_chains.stderr index 8a4137de37a3..801b074fc277 100644 --- a/tests/ui/checked_unwrap/if_let_chains.stderr +++ b/tests/ui/checked_unwrap/if_let_chains.stderr @@ -8,11 +8,8 @@ LL | println!("the value of a is {}", a.unwrap()); | ^^^^^^^^^^ | = help: try using `match` -note: the lint level is defined here - --> tests/ui/checked_unwrap/if_let_chains.rs:2:9 - | -LL | #![deny(clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::unnecessary-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap)]` error: called `unwrap` on `a` after checking its variant with `is_none` --> tests/ui/checked_unwrap/if_let_chains.rs:20:42 diff --git a/tests/ui/checked_unwrap/simple_conditionals.rs b/tests/ui/checked_unwrap/simple_conditionals.rs index bba264080b40..c6476a7507a1 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.rs +++ b/tests/ui/checked_unwrap/simple_conditionals.rs @@ -1,15 +1,15 @@ //@no-rustfix: has placeholders -#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] -#![allow( +#![warn(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] +#![expect( clippy::if_same_then_else, clippy::branches_sharing_code, - clippy::unnecessary_literal_unwrap + clippy::unnecessary_literal_unwrap, + clippy::self_assignment )] macro_rules! m { ($a:expr) => { if $a.is_some() { - // unnecessary $a.unwrap(); //~^ unnecessary_unwrap } @@ -43,90 +43,71 @@ macro_rules! checks_some { fn main() { let x = Some(()); if x.is_some() { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap - // unnecessary x.expect("an error message"); //~^ unnecessary_unwrap } else { - // will panic x.unwrap(); //~^ panicking_unwrap - // will panic x.expect("an error message"); //~^ panicking_unwrap } if x.is_none() { - // will panic x.unwrap(); //~^ panicking_unwrap } else { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap } m!(x); - // ok checks_in_param!(x.is_some(), x.unwrap()); - // ok checks_unwrap!(x, x.unwrap()); - // ok checks_some!(x.is_some(), x); let mut x: Result<(), ()> = Ok(()); if x.is_ok() { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap - // unnecessary x.expect("an error message"); //~^ unnecessary_unwrap - // will panic x.unwrap_err(); //~^ panicking_unwrap } else { - // will panic x.unwrap(); //~^ panicking_unwrap - // will panic x.expect("an error message"); //~^ panicking_unwrap - // unnecessary x.unwrap_err(); //~^ unnecessary_unwrap } if x.is_err() { - // will panic x.unwrap(); //~^ panicking_unwrap - // unnecessary x.unwrap_err(); //~^ unnecessary_unwrap } else { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap - // will panic x.unwrap_err(); //~^ panicking_unwrap } if x.is_ok() { x = Err(()); - // not unnecessary because of mutation of x + // not unnecessary because of mutation of `x` // it will always panic but the lint is not smart enough to see this (it only // checks if conditions). x.unwrap(); } else { x = Ok(()); - // not unnecessary because of mutation of x + // not unnecessary because of mutation of `x` // it will always panic but the lint is not smart enough to see this (it // only checks if conditions). x.unwrap_err(); @@ -175,13 +156,11 @@ fn issue11371() { //~^ panicking_unwrap } - // This should not lint. Statics are, at the time of writing, not linted on anyway, - // but if at some point they are supported by this lint, it should correctly see that - // `X` is being mutated and not suggest `if let Some(..) = X {}` + // This should not lint and suggest `if let Some(..) = X {}`, as `X` is being mutated static mut X: Option = Some(123); unsafe { + #[expect(static_mut_refs)] if X.is_some() { - //~^ ERROR: creating a shared reference X = None; X.unwrap(); } @@ -299,17 +278,197 @@ fn check_expect() { let x = Some(()); if x.is_some() { #[expect(clippy::unnecessary_unwrap)] - // unnecessary x.unwrap(); #[expect(clippy::unnecessary_unwrap)] - // unnecessary x.expect("an error message"); } else { #[expect(clippy::panicking_unwrap)] - // will panic x.unwrap(); #[expect(clippy::panicking_unwrap)] - // will panic x.expect("an error message"); } } + +fn partial_moves() { + fn borrow_option(_: &Option<()>) {} + + let x = Some(()); + // Using `if let Some(o) = x` won't work here, as `borrow_option` will try to borrow a moved value + if x.is_some() { + borrow_option(&x); + x.unwrap(); + //~^ unnecessary_unwrap + } + // This is fine though, as `if let Some(o) = &x` won't move `x` + if x.is_some() { + borrow_option(&x); + x.as_ref().unwrap(); + //~^ unnecessary_unwrap + } +} + +fn issue15321() { + struct Soption { + option: Option, + other: bool, + } + let mut sopt = Soption { + option: Some(true), + other: true, + }; + // Lint: nothing was mutated + let _res = if sopt.option.is_some() { + sopt.option.unwrap() + //~^ unnecessary_unwrap + } else { + sopt.option.unwrap() + //~^ panicking_unwrap + }; + // Lint: an unrelated field was mutated + let _res = if sopt.option.is_some() { + sopt.other = false; + sopt.option.unwrap() + //~^ unnecessary_unwrap + } else { + sopt.other = false; + sopt.option.unwrap() + //~^ panicking_unwrap + }; + // No lint: the whole local was mutated + let _res = if sopt.option.is_some() { + sopt = sopt; + sopt.option.unwrap() + } else { + sopt.option = None; + sopt.option.unwrap() + }; + // No lint: the field we're looking at was mutated + let _res = if sopt.option.is_some() { + sopt = sopt; + sopt.option.unwrap() + } else { + sopt.option = None; + sopt.option.unwrap() + }; + + struct Toption(Option, bool); + let mut topt = Toption(Some(true), true); + // Lint: nothing was mutated + let _res = if topt.0.is_some() { + topt.0.unwrap() + //~^ unnecessary_unwrap + } else { + topt.0.unwrap() + //~^ panicking_unwrap + }; + // Lint: an unrelated field was mutated + let _res = if topt.0.is_some() { + topt.1 = false; + topt.0.unwrap() + //~^ unnecessary_unwrap + } else { + topt.1 = false; + topt.0.unwrap() + //~^ panicking_unwrap + }; + // No lint: the whole local was mutated + let _res = if topt.0.is_some() { + topt = topt; + topt.0.unwrap() + } else { + topt = topt; + topt.0.unwrap() + }; + // No lint: the field we're looking at was mutated + let _res = if topt.0.is_some() { + topt.0 = None; + topt.0.unwrap() + } else { + topt.0 = None; + topt.0.unwrap() + }; + + // Nested field accesses get linted as well + struct Soption2 { + other: bool, + option: Soption, + } + let mut sopt2 = Soption2 { + other: true, + option: Soption { + option: Some(true), + other: true, + }, + }; + // Lint: no fields were mutated + let _res = if sopt2.option.option.is_some() { + sopt2.option.option.unwrap() + //~^ unnecessary_unwrap + } else { + sopt2.option.option.unwrap() + //~^ panicking_unwrap + }; + // Lint: an unrelated outer field was mutated -- don't get confused by `Soption2.other` having the + // same `FieldIdx` of 1 as `Soption.option` + let _res = if sopt2.option.option.is_some() { + sopt2.other = false; + sopt2.option.option.unwrap() + //~^ unnecessary_unwrap + } else { + sopt2.other = false; + sopt2.option.option.unwrap() + //~^ panicking_unwrap + }; + // Lint: an unrelated inner field was mutated + let _res = if sopt2.option.option.is_some() { + sopt2.option.other = false; + sopt2.option.option.unwrap() + //~^ unnecessary_unwrap + } else { + sopt2.option.other = false; + sopt2.option.option.unwrap() + //~^ panicking_unwrap + }; + // Don't lint: the whole local was mutated + let _res = if sopt2.option.option.is_some() { + sopt2 = sopt2; + sopt2.option.option.unwrap() + } else { + sopt2 = sopt2; + sopt2.option.option.unwrap() + }; + // Don't lint: a parent field of the field we're looking at was mutated, and with that the + // field we're looking at + let _res = if sopt2.option.option.is_some() { + sopt2.option = sopt; + sopt2.option.option.unwrap() + } else { + sopt2.option = sopt; + sopt2.option.option.unwrap() + }; + // Don't lint: the field we're looking at was mutated directly + let _res = if sopt2.option.option.is_some() { + sopt2.option.option = None; + sopt2.option.option.unwrap() + } else { + sopt2.option.option = None; + sopt2.option.option.unwrap() + }; + + // Partial moves + fn borrow_toption(_: &Toption) {} + + // Using `if let Some(o) = topt.0` won't work here, as `borrow_toption` will try to borrow a + // partially moved value + if topt.0.is_some() { + borrow_toption(&topt); + topt.0.unwrap(); + //~^ unnecessary_unwrap + } + // This is fine though, as `if let Some(o) = &topt.0` won't (partially) move `topt` + if topt.0.is_some() { + borrow_toption(&topt); + topt.0.as_ref().unwrap(); + //~^ unnecessary_unwrap + } +} diff --git a/tests/ui/checked_unwrap/simple_conditionals.stderr b/tests/ui/checked_unwrap/simple_conditionals.stderr index 2007a8595413..be979baa9fe4 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -1,20 +1,16 @@ error: called `unwrap` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:47:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:46:9 | LL | if x.is_some() { | -------------- help: try: `if let Some() = x` -LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ | -note: the lint level is defined here - --> tests/ui/checked_unwrap/simple_conditionals.rs:2:35 - | -LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::unnecessary-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap)]` error: called `expect` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:51:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:49:9 | LL | if x.is_some() { | -------------- help: try: `if let Some() = x` @@ -23,40 +19,36 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:52:9 + | +LL | if x.is_some() { + | ----------- because of this check +... +LL | x.unwrap(); + | ^^^^^^^^^^ + | + = note: `-D clippy::panicking-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::panicking_unwrap)]` + +error: this call to `expect()` will always panic --> tests/ui/checked_unwrap/simple_conditionals.rs:55:9 | LL | if x.is_some() { | ----------- because of this check ... -LL | x.unwrap(); - | ^^^^^^^^^^ - | -note: the lint level is defined here - --> tests/ui/checked_unwrap/simple_conditionals.rs:2:9 - | -LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: this call to `expect()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:59:9 - | -LL | if x.is_some() { - | ----------- because of this check -... LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:64:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:59:9 | LL | if x.is_none() { | ----------- because of this check -LL | // will panic LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_none` - --> tests/ui/checked_unwrap/simple_conditionals.rs:68:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:62:9 | LL | if x.is_none() { | -------------- help: try: `if let Some() = x` @@ -69,7 +61,6 @@ error: called `unwrap` on `x` after checking its variant with `is_some` | LL | if $a.is_some() { | --------------- help: try: `if let Some() = x` -LL | // unnecessary LL | $a.unwrap(); | ^^^^^^^^^^^ ... @@ -79,16 +70,15 @@ LL | m!(x); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: called `unwrap` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:81:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:71:9 | LL | if x.is_ok() { | ------------ help: try: `if let Ok() = x` -LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ error: called `expect` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:85:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:74:9 | LL | if x.is_ok() { | ------------ help: try: `if let Ok() = x` @@ -97,7 +87,7 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:89:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:77:9 | LL | if x.is_ok() { | --------- because of this check @@ -106,7 +96,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:93:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:80:9 | LL | if x.is_ok() { | --------- because of this check @@ -115,7 +105,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: this call to `expect()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:97:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:83:9 | LL | if x.is_ok() { | --------- because of this check @@ -124,7 +114,7 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:101:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:86:9 | LL | if x.is_ok() { | ------------ help: try: `if let Err() = x` @@ -133,16 +123,15 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:106:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:90:9 | LL | if x.is_err() { | ---------- because of this check -LL | // will panic LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/simple_conditionals.rs:110:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:93:9 | LL | if x.is_err() { | ------------- help: try: `if let Err() = x` @@ -151,7 +140,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/simple_conditionals.rs:114:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:96:9 | LL | if x.is_err() { | ------------- help: try: `if let Ok() = x` @@ -160,7 +149,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:118:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:99:9 | LL | if x.is_err() { | ---------- because of this check @@ -169,58 +158,58 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: called `unwrap` on `option` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:143:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:124:9 | LL | if option.is_some() { | ------------------- help: try: `if let Some() = &option` LL | option.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:127:9 + | +LL | if option.is_some() { + | ---------------- because of this check +... +LL | option.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `result` after checking its variant with `is_ok` + --> tests/ui/checked_unwrap/simple_conditionals.rs:134:9 + | +LL | if result.is_ok() { + | ----------------- help: try: `if let Ok() = &result` +LL | result.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:137:9 + | +LL | if result.is_ok() { + | -------------- because of this check +... +LL | result.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `option` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:143:9 + | +LL | if option.is_some() { + | ------------------- help: try: `if let Some() = &mut option` +LL | option.as_mut().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + error: this call to `unwrap()` will always panic --> tests/ui/checked_unwrap/simple_conditionals.rs:146:9 | LL | if option.is_some() { | ---------------- because of this check ... -LL | option.as_ref().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: called `unwrap` on `result` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:153:9 - | -LL | if result.is_ok() { - | ----------------- help: try: `if let Ok() = &result` -LL | result.as_ref().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:156:9 - | -LL | if result.is_ok() { - | -------------- because of this check -... -LL | result.as_ref().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: called `unwrap` on `option` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:162:9 - | -LL | if option.is_some() { - | ------------------- help: try: `if let Some() = &mut option` -LL | option.as_mut().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:165:9 - | -LL | if option.is_some() { - | ---------------- because of this check -... LL | option.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `result` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:171:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:152:9 | LL | if result.is_ok() { | ----------------- help: try: `if let Ok() = &mut result` @@ -228,7 +217,7 @@ LL | result.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:174:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:155:9 | LL | if result.is_ok() { | -------------- because of this check @@ -237,7 +226,7 @@ LL | result.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `option` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:205:17 + --> tests/ui/checked_unwrap/simple_conditionals.rs:184:17 | LL | if option.is_some() { | ------------------- help: try: `if let Some() = &option` @@ -245,7 +234,7 @@ LL | let _ = option.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:208:17 + --> tests/ui/checked_unwrap/simple_conditionals.rs:187:17 | LL | if option.is_some() { | ---------------- because of this check @@ -254,7 +243,7 @@ LL | let _ = option.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `result` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:216:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:195:9 | LL | if result.is_ok() { | ----------------- help: try: `if let Ok() = &result` @@ -263,7 +252,7 @@ LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:220:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:199:9 | LL | if result.is_ok() { | -------------- because of this check @@ -271,6 +260,40 @@ LL | if result.is_ok() { LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ +error: called `unwrap` on `x` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:225:17 + | +LL | if x.is_some() { + | -------------- help: try: `if let Some() = x` +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:228:17 + | +LL | if x.is_some() { + | ----------- because of this check +... +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + +error: called `unwrap` on `r` after checking its variant with `is_ok` + --> tests/ui/checked_unwrap/simple_conditionals.rs:234:17 + | +LL | if r.is_ok() { + | ------------ help: try: `if let Ok() = &r` +LL | _ = r.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:237:17 + | +LL | if r.is_ok() { + | --------- because of this check +... +LL | _ = r.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^ + error: called `unwrap` on `x` after checking its variant with `is_some` --> tests/ui/checked_unwrap/simple_conditionals.rs:246:17 | @@ -288,42 +311,8 @@ LL | if x.is_some() { LL | _ = x.unwrap(); | ^^^^^^^^^^ -error: called `unwrap` on `r` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:255:17 - | -LL | if r.is_ok() { - | ------------ help: try: `if let Ok() = &r` -LL | _ = r.as_ref().unwrap(); - | ^^^^^^^^^^^^^^^^^^^ - -error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:258:17 - | -LL | if r.is_ok() { - | --------- because of this check -... -LL | _ = r.as_ref().unwrap(); - | ^^^^^^^^^^^^^^^^^^^ - -error: called `unwrap` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:267:17 - | -LL | if x.is_some() { - | -------------- help: try: `if let Some() = x` -LL | _ = x.unwrap(); - | ^^^^^^^^^^ - -error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:270:17 - | -LL | if x.is_some() { - | ----------- because of this check -... -LL | _ = x.unwrap(); - | ^^^^^^^^^^ - error: called `unwrap` on `option` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:280:26 + --> tests/ui/checked_unwrap/simple_conditionals.rs:259:26 | LL | if option.is_some() { | ------------------- help: try: `if let Some() = option` @@ -331,7 +320,7 @@ LL | println!("{:?}", option.unwrap()); | ^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:283:26 + --> tests/ui/checked_unwrap/simple_conditionals.rs:262:26 | LL | if option.is_some() { | ---------------- because of this check @@ -340,7 +329,7 @@ LL | println!("{:?}", option.unwrap()); | ^^^^^^^^^^^^^^^ error: called `unwrap` on `result` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:290:26 + --> tests/ui/checked_unwrap/simple_conditionals.rs:269:26 | LL | if result.is_ok() { | ----------------- help: try: `if let Ok() = result` @@ -348,7 +337,7 @@ LL | println!("{:?}", result.unwrap()); | ^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:293:26 + --> tests/ui/checked_unwrap/simple_conditionals.rs:272:26 | LL | if result.is_ok() { | -------------- because of this check @@ -356,15 +345,164 @@ LL | if result.is_ok() { LL | println!("{:?}", result.unwrap()); | ^^^^^^^^^^^^^^^ -error: creating a shared reference to mutable static - --> tests/ui/checked_unwrap/simple_conditionals.rs:183:12 +error: called `unwrap` on `x` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:299:9 | -LL | if X.is_some() { - | ^^^^^^^^^^^ shared reference to mutable static +LL | if x.is_some() { + | -------------- help: try: `if let Some() = x` +LL | borrow_option(&x); +LL | x.unwrap(); + | ^^^^^^^^^^ + +error: called `unwrap` on `x` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:305:9 | - = note: for more information, see - = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives - = note: `#[deny(static_mut_refs)]` (part of `#[deny(rust_2024_compatibility)]`) on by default +LL | if x.is_some() { + | -------------- help: try: `if let Some() = &x` +LL | borrow_option(&x); +LL | x.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 40 previous errors +error: called `unwrap` on `sopt.option` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:321:9 + | +LL | let _res = if sopt.option.is_some() { + | ------------------------ help: try: `if let Some() = sopt.option` +LL | sopt.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:324:9 + | +LL | let _res = if sopt.option.is_some() { + | --------------------- because of this check +... +LL | sopt.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `sopt.option` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:330:9 + | +LL | let _res = if sopt.option.is_some() { + | ------------------------ help: try: `if let Some() = sopt.option` +LL | sopt.other = false; +LL | sopt.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:334:9 + | +LL | let _res = if sopt.option.is_some() { + | --------------------- because of this check +... +LL | sopt.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `topt.0` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:358:9 + | +LL | let _res = if topt.0.is_some() { + | ------------------- help: try: `if let Some() = topt.0` +LL | topt.0.unwrap() + | ^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:361:9 + | +LL | let _res = if topt.0.is_some() { + | ---------------- because of this check +... +LL | topt.0.unwrap() + | ^^^^^^^^^^^^^^^ + +error: called `unwrap` on `topt.0` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:367:9 + | +LL | let _res = if topt.0.is_some() { + | ------------------- help: try: `if let Some() = topt.0` +LL | topt.1 = false; +LL | topt.0.unwrap() + | ^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:371:9 + | +LL | let _res = if topt.0.is_some() { + | ---------------- because of this check +... +LL | topt.0.unwrap() + | ^^^^^^^^^^^^^^^ + +error: called `unwrap` on `sopt2.option.option` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:405:9 + | +LL | let _res = if sopt2.option.option.is_some() { + | -------------------------------- help: try: `if let Some() = sopt2.option.option` +LL | sopt2.option.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:408:9 + | +LL | let _res = if sopt2.option.option.is_some() { + | ----------------------------- because of this check +... +LL | sopt2.option.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `sopt2.option.option` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:415:9 + | +LL | let _res = if sopt2.option.option.is_some() { + | -------------------------------- help: try: `if let Some() = sopt2.option.option` +LL | sopt2.other = false; +LL | sopt2.option.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:419:9 + | +LL | let _res = if sopt2.option.option.is_some() { + | ----------------------------- because of this check +... +LL | sopt2.option.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `sopt2.option.option` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:425:9 + | +LL | let _res = if sopt2.option.option.is_some() { + | -------------------------------- help: try: `if let Some() = sopt2.option.option` +LL | sopt2.option.other = false; +LL | sopt2.option.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:429:9 + | +LL | let _res = if sopt2.option.option.is_some() { + | ----------------------------- because of this check +... +LL | sopt2.option.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `topt.0` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:465:9 + | +LL | if topt.0.is_some() { + | ------------------- help: try: `if let Some() = topt.0` +LL | borrow_toption(&topt); +LL | topt.0.unwrap(); + | ^^^^^^^^^^^^^^^ + +error: called `unwrap` on `topt.0` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:471:9 + | +LL | if topt.0.is_some() { + | ------------------- help: try: `if let Some() = &topt.0` +LL | borrow_toption(&topt); +LL | topt.0.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 57 previous errors diff --git a/tests/ui/doc/doc_paragraphs_missing_punctuation.fixed b/tests/ui/doc/doc_paragraphs_missing_punctuation.fixed new file mode 100644 index 000000000000..95d65039440b --- /dev/null +++ b/tests/ui/doc/doc_paragraphs_missing_punctuation.fixed @@ -0,0 +1,172 @@ +#![feature(custom_inner_attributes)] +#![rustfmt::skip] +#![warn(clippy::doc_paragraphs_missing_punctuation)] + +/// Returns the Answer to the Ultimate Question of Life, the Universe, and Everything. +//~^ doc_paragraphs_missing_punctuation +fn answer() -> i32 { + 42 +} + +/// The `Option` type. +//~^ doc_paragraphs_missing_punctuation +// Triggers even in the presence of another attribute. +#[derive(Debug)] +enum MyOption { + /// No value. + //~^ doc_paragraphs_missing_punctuation + None, + /// Some value of type `T`. + Some(T), +} + +// Triggers correctly even when interleaved with other attributes. +/// A multiline +#[derive(Debug)] +/// doc comment: +/// only the last line triggers the lint. +//~^ doc_paragraphs_missing_punctuation +enum Exceptions { + /// Question marks are fine? + QuestionMark, + /// Exclamation marks are fine! + ExclamationMark, + /// Ellipses are ok too… + Ellipsis, + /// HTML content is however not checked: + /// Raw HTML is allowed as well + RawHtml, + /// The raw HTML exception actually does the right thing to autolinks: + /// . + //~^ doc_paragraphs_missing_punctuation + MarkdownAutolink, + /// This table introduction ends with a colon: + /// + /// | Exception | Note | + /// | -------------- | ----- | + /// | Markdown table | A-ok | + MarkdownTable, + /// Here is a snippet. + //~^ doc_paragraphs_missing_punctuation + /// + /// ``` + /// // Code blocks are no issues. + /// ``` + CodeBlock, +} + +// Check the lint can be expected on a whole enum at once. +#[expect(clippy::doc_paragraphs_missing_punctuation)] +enum Char { + /// U+0000 + Null, + /// U+0001 + StartOfHeading, +} + +// Check the lint can be expected on a single variant without affecting others. +enum Char2 { + #[expect(clippy::doc_paragraphs_missing_punctuation)] + /// U+0000 + Null, + /// U+0001. + //~^ doc_paragraphs_missing_punctuation + StartOfHeading, +} + +mod module { + //! Works on + //! inner attributes too. + //~^ doc_paragraphs_missing_punctuation +} + +enum Trailers { + /// Sometimes the last sentence ends with parentheses (and that's ok). + ParensPassing, + /// (Sometimes the last sentence is in parentheses.) + SentenceInParensPassing, + /// **Sometimes the last sentence is in bold, and that's ok.** + DoubleStarPassing, + /// **But sometimes it is missing a period.** + //~^ doc_paragraphs_missing_punctuation + DoubleStarFailing, + /// _Sometimes the last sentence is in italics, and that's ok._ + UnderscorePassing, + /// _But sometimes it is missing a period._ + //~^ doc_paragraphs_missing_punctuation + UnderscoreFailing, + /// This comment ends with "a quote." + AmericanStyleQuotePassing, + /// This comment ends with "a quote". + BritishStyleQuotePassing, +} + +/// Doc comments can end with an [inline link](#anchor). +//~^ doc_paragraphs_missing_punctuation +struct InlineLink; + +/// Some doc comments contain [link reference definitions][spec]. +//~^ doc_paragraphs_missing_punctuation +/// +/// [spec]: https://spec.commonmark.org/0.31.2/#link-reference-definitions +struct LinkRefDefinition; + +// List items do not always need to end with a period. +enum UnorderedLists { + /// This list has an introductory sentence: + /// + /// - A list item + Dash, + /// + A list item + Plus, + /// * A list item + Star, +} + +enum OrderedLists { + /// 1. A list item + Dot, + /// 42) A list item + Paren, +} + +/// Doc comments with trailing blank lines are supported. +//~^ doc_paragraphs_missing_punctuation +/// +struct TrailingBlankLine; + +/// This doc comment has multiple paragraph. +/// This first paragraph is missing punctuation. +//~^ doc_paragraphs_missing_punctuation +/// +/// The second one as well +/// And it has multiple sentences. +//~^ doc_paragraphs_missing_punctuation +/// +/// Same for this third and last one. +//~^ doc_paragraphs_missing_punctuation +struct MultiParagraphDocComment; + +/// ``` +struct IncompleteBlockCode; + +/// This ends with a code `span`. +//~^ doc_paragraphs_missing_punctuation +struct CodeSpan; + +#[expect(clippy::empty_docs)] +/// +struct EmptyDocComment; + +/** + * Block doc comments work. + * + */ +//~^^^ doc_paragraphs_missing_punctuation +struct BlockDocComment; + +/// Sometimes a doc attribute is used for concatenation +/// ``` +#[doc = ""] +/// ``` +struct DocAttribute; diff --git a/tests/ui/doc/doc_paragraphs_missing_punctuation.rs b/tests/ui/doc/doc_paragraphs_missing_punctuation.rs new file mode 100644 index 000000000000..35b74d7d13b9 --- /dev/null +++ b/tests/ui/doc/doc_paragraphs_missing_punctuation.rs @@ -0,0 +1,172 @@ +#![feature(custom_inner_attributes)] +#![rustfmt::skip] +#![warn(clippy::doc_paragraphs_missing_punctuation)] + +/// Returns the Answer to the Ultimate Question of Life, the Universe, and Everything +//~^ doc_paragraphs_missing_punctuation +fn answer() -> i32 { + 42 +} + +/// The `Option` type +//~^ doc_paragraphs_missing_punctuation +// Triggers even in the presence of another attribute. +#[derive(Debug)] +enum MyOption { + /// No value + //~^ doc_paragraphs_missing_punctuation + None, + /// Some value of type `T`. + Some(T), +} + +// Triggers correctly even when interleaved with other attributes. +/// A multiline +#[derive(Debug)] +/// doc comment: +/// only the last line triggers the lint +//~^ doc_paragraphs_missing_punctuation +enum Exceptions { + /// Question marks are fine? + QuestionMark, + /// Exclamation marks are fine! + ExclamationMark, + /// Ellipses are ok too… + Ellipsis, + /// HTML content is however not checked: + /// Raw HTML is allowed as well + RawHtml, + /// The raw HTML exception actually does the right thing to autolinks: + /// + //~^ doc_paragraphs_missing_punctuation + MarkdownAutolink, + /// This table introduction ends with a colon: + /// + /// | Exception | Note | + /// | -------------- | ----- | + /// | Markdown table | A-ok | + MarkdownTable, + /// Here is a snippet + //~^ doc_paragraphs_missing_punctuation + /// + /// ``` + /// // Code blocks are no issues. + /// ``` + CodeBlock, +} + +// Check the lint can be expected on a whole enum at once. +#[expect(clippy::doc_paragraphs_missing_punctuation)] +enum Char { + /// U+0000 + Null, + /// U+0001 + StartOfHeading, +} + +// Check the lint can be expected on a single variant without affecting others. +enum Char2 { + #[expect(clippy::doc_paragraphs_missing_punctuation)] + /// U+0000 + Null, + /// U+0001 + //~^ doc_paragraphs_missing_punctuation + StartOfHeading, +} + +mod module { + //! Works on + //! inner attributes too + //~^ doc_paragraphs_missing_punctuation +} + +enum Trailers { + /// Sometimes the last sentence ends with parentheses (and that's ok). + ParensPassing, + /// (Sometimes the last sentence is in parentheses.) + SentenceInParensPassing, + /// **Sometimes the last sentence is in bold, and that's ok.** + DoubleStarPassing, + /// **But sometimes it is missing a period** + //~^ doc_paragraphs_missing_punctuation + DoubleStarFailing, + /// _Sometimes the last sentence is in italics, and that's ok._ + UnderscorePassing, + /// _But sometimes it is missing a period_ + //~^ doc_paragraphs_missing_punctuation + UnderscoreFailing, + /// This comment ends with "a quote." + AmericanStyleQuotePassing, + /// This comment ends with "a quote". + BritishStyleQuotePassing, +} + +/// Doc comments can end with an [inline link](#anchor) +//~^ doc_paragraphs_missing_punctuation +struct InlineLink; + +/// Some doc comments contain [link reference definitions][spec] +//~^ doc_paragraphs_missing_punctuation +/// +/// [spec]: https://spec.commonmark.org/0.31.2/#link-reference-definitions +struct LinkRefDefinition; + +// List items do not always need to end with a period. +enum UnorderedLists { + /// This list has an introductory sentence: + /// + /// - A list item + Dash, + /// + A list item + Plus, + /// * A list item + Star, +} + +enum OrderedLists { + /// 1. A list item + Dot, + /// 42) A list item + Paren, +} + +/// Doc comments with trailing blank lines are supported +//~^ doc_paragraphs_missing_punctuation +/// +struct TrailingBlankLine; + +/// This doc comment has multiple paragraph. +/// This first paragraph is missing punctuation +//~^ doc_paragraphs_missing_punctuation +/// +/// The second one as well +/// And it has multiple sentences +//~^ doc_paragraphs_missing_punctuation +/// +/// Same for this third and last one +//~^ doc_paragraphs_missing_punctuation +struct MultiParagraphDocComment; + +/// ``` +struct IncompleteBlockCode; + +/// This ends with a code `span` +//~^ doc_paragraphs_missing_punctuation +struct CodeSpan; + +#[expect(clippy::empty_docs)] +/// +struct EmptyDocComment; + +/** + * Block doc comments work + * + */ +//~^^^ doc_paragraphs_missing_punctuation +struct BlockDocComment; + +/// Sometimes a doc attribute is used for concatenation +/// ``` +#[doc = ""] +/// ``` +struct DocAttribute; diff --git a/tests/ui/doc/doc_paragraphs_missing_punctuation.stderr b/tests/ui/doc/doc_paragraphs_missing_punctuation.stderr new file mode 100644 index 000000000000..49aa4e8aeb88 --- /dev/null +++ b/tests/ui/doc/doc_paragraphs_missing_punctuation.stderr @@ -0,0 +1,113 @@ +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:5:86 + | +LL | /// Returns the Answer to the Ultimate Question of Life, the Universe, and Everything + | ^ help: end the paragraph with some punctuation: `.` + | + = note: `-D clippy::doc-paragraphs-missing-punctuation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_paragraphs_missing_punctuation)]` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:11:22 + | +LL | /// The `Option` type + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:16:17 + | +LL | /// No value + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:27:41 + | +LL | /// only the last line triggers the lint + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:40:56 + | +LL | /// + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:49:26 + | +LL | /// Here is a snippet + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:72:15 + | +LL | /// U+0001 + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:79:29 + | +LL | //! inner attributes too + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:90:47 + | +LL | /// **But sometimes it is missing a period** + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:95:46 + | +LL | /// _But sometimes it is missing a period_ + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:104:56 + | +LL | /// Doc comments can end with an [inline link](#anchor) + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:108:65 + | +LL | /// Some doc comments contain [link reference definitions][spec] + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:133:57 + | +LL | /// Doc comments with trailing blank lines are supported + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:139:48 + | +LL | /// This first paragraph is missing punctuation + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:143:34 + | +LL | /// And it has multiple sentences + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:146:37 + | +LL | /// Same for this third and last one + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:153:33 + | +LL | /// This ends with a code `span` + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:162:27 + | +LL | * Block doc comments work + | ^ help: end the paragraph with some punctuation: `.` + +error: aborting due to 18 previous errors + diff --git a/tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.rs b/tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.rs new file mode 100644 index 000000000000..3873f1d1edcf --- /dev/null +++ b/tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.rs @@ -0,0 +1,13 @@ +#![feature(custom_inner_attributes)] +#![rustfmt::skip] +#![warn(clippy::doc_paragraphs_missing_punctuation)] +//@no-rustfix + +enum UnfixableTrailers { + /// Sometimes the doc comment ends with parentheses (like this) + //~^ doc_paragraphs_missing_punctuation + EndsWithParens, + /// This comment ends with "a quote" + //~^ doc_paragraphs_missing_punctuation + QuoteFailing, +} diff --git a/tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.stderr b/tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.stderr new file mode 100644 index 000000000000..e8587eace2d6 --- /dev/null +++ b/tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.stderr @@ -0,0 +1,20 @@ +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.rs:7:68 + | +LL | /// Sometimes the doc comment ends with parentheses (like this) + | ^ + | + = help: end the paragraph with some punctuation + = note: `-D clippy::doc-paragraphs-missing-punctuation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_paragraphs_missing_punctuation)]` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.rs:10:41 + | +LL | /// This comment ends with "a quote" + | ^ + | + = help: end the paragraph with some punctuation + +error: aborting due to 2 previous errors + diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed index 58fbad64a78d..2cf69cf7b2fd 100644 --- a/tests/ui/equatable_if_let.fixed +++ b/tests/ui/equatable_if_let.fixed @@ -1,14 +1,6 @@ //@aux-build:proc_macros.rs - -#![allow( - unused_variables, - dead_code, - clippy::derive_partial_eq_without_eq, - clippy::needless_ifs -)] +#![allow(clippy::derive_partial_eq_without_eq, clippy::needless_ifs)] #![warn(clippy::equatable_if_let)] - -extern crate proc_macros; use proc_macros::{external, inline_macros}; use std::cmp::Ordering; @@ -48,7 +40,6 @@ impl PartialEq for NotStructuralEq { } } -#[inline_macros] fn main() { let a = 2; let b = 3; @@ -95,13 +86,6 @@ fn main() { //~^ equatable_if_let if matches!(h, NoPartialEqStruct { a: 2, b: false }) {} //~^ equatable_if_let - - if "abc" == inline!("abc") { - //~^ equatable_if_let - println!("OK"); - } - - external!({ if let 2 = $a {} }); } mod issue8710 { @@ -139,3 +123,92 @@ mod issue8710 { } } } + +#[inline_macros] +fn issue14548() { + if let inline!("abc") = "abc" { + println!("OK"); + } + + let a = 2; + external!({ if let 2 = $a {} }); + + // Don't lint: `==`/`matches!` might be correct for a particular `$($font)|*`, but not in general + macro_rules! m1 { + ($($font:pat_param)|*) => { + if let $($font)|* = "from_expansion" {} + } + } + m1!("foo"); + m1!("Sans" | "Serif" | "Sans Mono"); + m1!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general + macro_rules! m2 { + ($from_root_ctxt:pat) => { + if let $from_root_ctxt = "from_expansion" {} + }; + } + m2!("foo"); + m2!("Sans" | "Serif" | "Sans Mono"); + m2!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general + macro_rules! m3 { + ($from_root_ctxt:expr) => { + if let "from_expansion" = $from_root_ctxt {} + }; + } + m3!("foo"); + m3!("foo"); + m3!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general. Don't get confused by the scrutinee coming from macro invocation + macro_rules! m4 { + ($from_root_ctxt:pat) => { + if let $from_root_ctxt = inline!("from_expansion") {} + }; + } + m4!("foo"); + m4!("Sans" | "Serif" | "Sans Mono"); + m4!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general. Don't get confused by the scrutinee coming from macro invocation + macro_rules! m5 { + ($from_root_ctxt:expr) => { + if let inline!("from_expansion") = $from_root_ctxt {} + }; + } + m5!("foo"); + m5!("foo"); + m5!(inline!("foo")); + + // Would be nice to lint: both sides are macro _invocations_, so the suggestion is correct in + // general + if let inline!("foo") = inline!("bar") {} +} + +// PartialEq is not stable in consts yet +fn issue15376() { + enum NonConstEq { + A, + B, + } + impl PartialEq for NonConstEq { + fn eq(&self, _other: &Self) -> bool { + true + } + } + + const N: NonConstEq = NonConstEq::A; + + // `impl PartialEq` is not const, suggest `matches!` + const _: u32 = if matches!(N, NonConstEq::A) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` + const _: u32 = if matches!(Some(N), Some(NonConstEq::A)) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` +} diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs index cca97c76b509..94302b3dfa65 100644 --- a/tests/ui/equatable_if_let.rs +++ b/tests/ui/equatable_if_let.rs @@ -1,14 +1,6 @@ //@aux-build:proc_macros.rs - -#![allow( - unused_variables, - dead_code, - clippy::derive_partial_eq_without_eq, - clippy::needless_ifs -)] +#![allow(clippy::derive_partial_eq_without_eq, clippy::needless_ifs)] #![warn(clippy::equatable_if_let)] - -extern crate proc_macros; use proc_macros::{external, inline_macros}; use std::cmp::Ordering; @@ -48,7 +40,6 @@ fn eq(&self, _: &NotStructuralEq) -> bool { } } -#[inline_macros] fn main() { let a = 2; let b = 3; @@ -95,13 +86,6 @@ fn main() { //~^ equatable_if_let if let NoPartialEqStruct { a: 2, b: false } = h {} //~^ equatable_if_let - - if let inline!("abc") = "abc" { - //~^ equatable_if_let - println!("OK"); - } - - external!({ if let 2 = $a {} }); } mod issue8710 { @@ -139,3 +123,92 @@ fn get_enum() -> Option<&'static MyEnum> { } } } + +#[inline_macros] +fn issue14548() { + if let inline!("abc") = "abc" { + println!("OK"); + } + + let a = 2; + external!({ if let 2 = $a {} }); + + // Don't lint: `==`/`matches!` might be correct for a particular `$($font)|*`, but not in general + macro_rules! m1 { + ($($font:pat_param)|*) => { + if let $($font)|* = "from_expansion" {} + } + } + m1!("foo"); + m1!("Sans" | "Serif" | "Sans Mono"); + m1!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general + macro_rules! m2 { + ($from_root_ctxt:pat) => { + if let $from_root_ctxt = "from_expansion" {} + }; + } + m2!("foo"); + m2!("Sans" | "Serif" | "Sans Mono"); + m2!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general + macro_rules! m3 { + ($from_root_ctxt:expr) => { + if let "from_expansion" = $from_root_ctxt {} + }; + } + m3!("foo"); + m3!("foo"); + m3!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general. Don't get confused by the scrutinee coming from macro invocation + macro_rules! m4 { + ($from_root_ctxt:pat) => { + if let $from_root_ctxt = inline!("from_expansion") {} + }; + } + m4!("foo"); + m4!("Sans" | "Serif" | "Sans Mono"); + m4!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general. Don't get confused by the scrutinee coming from macro invocation + macro_rules! m5 { + ($from_root_ctxt:expr) => { + if let inline!("from_expansion") = $from_root_ctxt {} + }; + } + m5!("foo"); + m5!("foo"); + m5!(inline!("foo")); + + // Would be nice to lint: both sides are macro _invocations_, so the suggestion is correct in + // general + if let inline!("foo") = inline!("bar") {} +} + +// PartialEq is not stable in consts yet +fn issue15376() { + enum NonConstEq { + A, + B, + } + impl PartialEq for NonConstEq { + fn eq(&self, _other: &Self) -> bool { + true + } + } + + const N: NonConstEq = NonConstEq::A; + + // `impl PartialEq` is not const, suggest `matches!` + const _: u32 = if let NonConstEq::A = N { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` + const _: u32 = if let Some(NonConstEq::A) = Some(N) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` +} diff --git a/tests/ui/equatable_if_let.stderr b/tests/ui/equatable_if_let.stderr index dd1832ad68b2..8cc78daa2535 100644 --- a/tests/ui/equatable_if_let.stderr +++ b/tests/ui/equatable_if_let.stderr @@ -1,5 +1,5 @@ error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:64:8 + --> tests/ui/equatable_if_let.rs:55:8 | LL | if let 2 = a {} | ^^^^^^^^^ help: try: `a == 2` @@ -8,100 +8,106 @@ LL | if let 2 = a {} = help: to override `-D warnings` add `#[allow(clippy::equatable_if_let)]` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:66:8 + --> tests/ui/equatable_if_let.rs:57:8 | LL | if let Ordering::Greater = a.cmp(&b) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:68:8 + --> tests/ui/equatable_if_let.rs:59:8 | LL | if let Some(2) = c {} | ^^^^^^^^^^^^^^^ help: try: `c == Some(2)` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:70:8 + --> tests/ui/equatable_if_let.rs:61:8 | LL | if let Struct { a: 2, b: false } = d {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:72:8 + --> tests/ui/equatable_if_let.rs:63:8 | LL | if let Enum::TupleVariant(32, 64) = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:74:8 + --> tests/ui/equatable_if_let.rs:65:8 | LL | if let Enum::RecordVariant { a: 64, b: 32 } = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:76:8 + --> tests/ui/equatable_if_let.rs:67:8 | LL | if let Enum::UnitVariant = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:78:8 + --> tests/ui/equatable_if_let.rs:69:8 | LL | if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })` error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:88:8 + --> tests/ui/equatable_if_let.rs:79:8 | LL | if let NotPartialEq::A = f {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(f, NotPartialEq::A)` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:90:8 + --> tests/ui/equatable_if_let.rs:81:8 | LL | if let NotStructuralEq::A = g {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A` error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:92:8 + --> tests/ui/equatable_if_let.rs:83:8 | LL | if let Some(NotPartialEq::A) = Some(f) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(f), Some(NotPartialEq::A))` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:94:8 + --> tests/ui/equatable_if_let.rs:85:8 | LL | if let Some(NotStructuralEq::A) = Some(g) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)` error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:96:8 + --> tests/ui/equatable_if_let.rs:87:8 | LL | if let NoPartialEqStruct { a: 2, b: false } = h {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(h, NoPartialEqStruct { a: 2, b: false })` -error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:99:8 - | -LL | if let inline!("abc") = "abc" { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")` - error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:109:12 + --> tests/ui/equatable_if_let.rs:93:12 | LL | if let Some('i') = cs.iter().next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some('i'))` error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:117:12 + --> tests/ui/equatable_if_let.rs:101:12 | LL | if let Some(1) = cs.iter().next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some(1))` error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:135:12 + --> tests/ui/equatable_if_let.rs:119:12 | LL | if let Some(MyEnum::B) = get_enum() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(get_enum(), Some(MyEnum::B))` -error: aborting due to 17 previous errors +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:210:23 + | +LL | const _: u32 = if let NonConstEq::A = N { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(N, NonConstEq::A)` + +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:212:23 + | +LL | const _: u32 = if let Some(NonConstEq::A) = Some(N) { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(N), Some(NonConstEq::A))` + +error: aborting due to 18 previous errors diff --git a/tests/ui/equatable_if_let_const_cmp.fixed b/tests/ui/equatable_if_let_const_cmp.fixed new file mode 100644 index 000000000000..51dab25ed6d8 --- /dev/null +++ b/tests/ui/equatable_if_let_const_cmp.fixed @@ -0,0 +1,24 @@ +#![warn(clippy::equatable_if_let)] +#![allow(clippy::eq_op)] +#![feature(const_trait_impl, const_cmp)] + +fn issue15376() { + enum ConstEq { + A, + B, + } + impl const PartialEq for ConstEq { + fn eq(&self, _other: &Self) -> bool { + true + } + } + + const C: ConstEq = ConstEq::A; + + // `impl PartialEq` is const... but we still suggest `matches!` for now + // TODO: detect this and suggest `=` + const _: u32 = if matches!(C, ConstEq::A) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` + const _: u32 = if matches!(Some(C), Some(ConstEq::A)) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` +} diff --git a/tests/ui/equatable_if_let_const_cmp.rs b/tests/ui/equatable_if_let_const_cmp.rs new file mode 100644 index 000000000000..b402e05c53de --- /dev/null +++ b/tests/ui/equatable_if_let_const_cmp.rs @@ -0,0 +1,24 @@ +#![warn(clippy::equatable_if_let)] +#![allow(clippy::eq_op)] +#![feature(const_trait_impl, const_cmp)] + +fn issue15376() { + enum ConstEq { + A, + B, + } + impl const PartialEq for ConstEq { + fn eq(&self, _other: &Self) -> bool { + true + } + } + + const C: ConstEq = ConstEq::A; + + // `impl PartialEq` is const... but we still suggest `matches!` for now + // TODO: detect this and suggest `=` + const _: u32 = if let ConstEq::A = C { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` + const _: u32 = if let Some(ConstEq::A) = Some(C) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` +} diff --git a/tests/ui/equatable_if_let_const_cmp.stderr b/tests/ui/equatable_if_let_const_cmp.stderr new file mode 100644 index 000000000000..ec72e42d6430 --- /dev/null +++ b/tests/ui/equatable_if_let_const_cmp.stderr @@ -0,0 +1,17 @@ +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let_const_cmp.rs:20:23 + | +LL | const _: u32 = if let ConstEq::A = C { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^ help: try: `matches!(C, ConstEq::A)` + | + = note: `-D clippy::equatable-if-let` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::equatable_if_let)]` + +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let_const_cmp.rs:22:23 + | +LL | const _: u32 = if let Some(ConstEq::A) = Some(C) { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(C), Some(ConstEq::A))` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/explicit_deref_methods.fixed b/tests/ui/explicit_deref_methods.fixed index 97e8e0bafe4f..6c29630dc3a5 100644 --- a/tests/ui/explicit_deref_methods.fixed +++ b/tests/ui/explicit_deref_methods.fixed @@ -156,3 +156,116 @@ fn main() { let _ = &&mut **&mut x; //~ explicit_deref_methods let _ = &&mut ***(&mut &mut x); //~ explicit_deref_methods } + +mod issue_15392 { + use std::ops::{Deref, DerefMut}; + + struct Wrapper(String); + + impl Deref for Wrapper { + type Target = str; + fn deref(&self) -> &Self::Target { + // forwarding is ok + let res = Deref::deref(&self.0); + // we let `deref_mut` pass as well + let _ = DerefMut::deref_mut(&mut String::new()); + res + } + } + + impl DerefMut for Wrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + // forwarding is ok + let res = DerefMut::deref_mut(&mut self.0); + // we let `deref` pass as well + let _ = Deref::deref(&String::new()); + res + } + } + + struct A(String); + struct AA(String); + struct AB(String); + + impl Deref for A { + type Target = str; + + fn deref(&self) -> &Self::Target { + // in a top-level `Deref` impl, ok + let _ = self.0.deref(); + // in a top-level `Deref` impl, acceptable + let _ = String::new().deref_mut(); + + #[allow(non_local_definitions)] + impl Deref for AA { + type Target = str; + fn deref(&self) -> &Self::Target { + // in a nested `Deref` impl, acceptable + let _ = String::new().deref_mut(); + // in a nested `Deref` impl, ok + self.0.deref() + } + } + + // still in a top-level `Deref` impl, ok + let _ = self.0.deref(); + // still in a top-level `Deref` impl, acceptable + let _ = String::new().deref_mut(); + + #[allow(non_local_definitions)] + impl DerefMut for AA { + fn deref_mut(&mut self) -> &mut Self::Target { + // in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // in a top-level `DerefMut` impl, ok + self.0.deref_mut() + } + } + + // still in a top-level `Deref` impl, acceptable + let _ = String::new().deref_mut(); + // still in a top-level `Deref` impl, ok + self.0.deref() + } + } + + impl DerefMut for A { + fn deref_mut(&mut self) -> &mut Self::Target { + // in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // in a top-level `DerefMut` impl, ok + let _ = self.0.deref_mut(); + + #[allow(non_local_definitions)] + impl Deref for AB { + type Target = str; + fn deref(&self) -> &Self::Target { + // in a nested `Deref` impl, acceptable + let _ = String::new().deref_mut(); + // in a nested `Deref` impl, ok + Deref::deref(&self.0) + } + } + + // still in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // still in a top-level `DerefMut` impl, ok + let _ = self.0.deref_mut(); + + #[allow(non_local_definitions)] + impl DerefMut for AB { + fn deref_mut(&mut self) -> &mut Self::Target { + // in a nested `DerefMut` impl, acceptable + self.0.deref(); + // in a nested `DerefMut` impl, ok + self.0.deref_mut() + } + } + + // still in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // still in a top-level `DerefMut` impl, ok + self.0.deref_mut() + } + } +} diff --git a/tests/ui/explicit_deref_methods.rs b/tests/ui/explicit_deref_methods.rs index b689649d49dd..f6309cd404b8 100644 --- a/tests/ui/explicit_deref_methods.rs +++ b/tests/ui/explicit_deref_methods.rs @@ -156,3 +156,116 @@ pub fn deref_mut(self) -> u32 { let _ = &DerefMut::deref_mut(&mut x); //~ explicit_deref_methods let _ = &DerefMut::deref_mut((&mut &mut x).deref_mut()); //~ explicit_deref_methods } + +mod issue_15392 { + use std::ops::{Deref, DerefMut}; + + struct Wrapper(String); + + impl Deref for Wrapper { + type Target = str; + fn deref(&self) -> &Self::Target { + // forwarding is ok + let res = Deref::deref(&self.0); + // we let `deref_mut` pass as well + let _ = DerefMut::deref_mut(&mut String::new()); + res + } + } + + impl DerefMut for Wrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + // forwarding is ok + let res = DerefMut::deref_mut(&mut self.0); + // we let `deref` pass as well + let _ = Deref::deref(&String::new()); + res + } + } + + struct A(String); + struct AA(String); + struct AB(String); + + impl Deref for A { + type Target = str; + + fn deref(&self) -> &Self::Target { + // in a top-level `Deref` impl, ok + let _ = self.0.deref(); + // in a top-level `Deref` impl, acceptable + let _ = String::new().deref_mut(); + + #[allow(non_local_definitions)] + impl Deref for AA { + type Target = str; + fn deref(&self) -> &Self::Target { + // in a nested `Deref` impl, acceptable + let _ = String::new().deref_mut(); + // in a nested `Deref` impl, ok + self.0.deref() + } + } + + // still in a top-level `Deref` impl, ok + let _ = self.0.deref(); + // still in a top-level `Deref` impl, acceptable + let _ = String::new().deref_mut(); + + #[allow(non_local_definitions)] + impl DerefMut for AA { + fn deref_mut(&mut self) -> &mut Self::Target { + // in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // in a top-level `DerefMut` impl, ok + self.0.deref_mut() + } + } + + // still in a top-level `Deref` impl, acceptable + let _ = String::new().deref_mut(); + // still in a top-level `Deref` impl, ok + self.0.deref() + } + } + + impl DerefMut for A { + fn deref_mut(&mut self) -> &mut Self::Target { + // in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // in a top-level `DerefMut` impl, ok + let _ = self.0.deref_mut(); + + #[allow(non_local_definitions)] + impl Deref for AB { + type Target = str; + fn deref(&self) -> &Self::Target { + // in a nested `Deref` impl, acceptable + let _ = String::new().deref_mut(); + // in a nested `Deref` impl, ok + Deref::deref(&self.0) + } + } + + // still in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // still in a top-level `DerefMut` impl, ok + let _ = self.0.deref_mut(); + + #[allow(non_local_definitions)] + impl DerefMut for AB { + fn deref_mut(&mut self) -> &mut Self::Target { + // in a nested `DerefMut` impl, acceptable + self.0.deref(); + // in a nested `DerefMut` impl, ok + self.0.deref_mut() + } + } + + // still in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // still in a top-level `DerefMut` impl, ok + self.0.deref_mut() + } + } +} diff --git a/tests/ui/implicit_hasher.fixed b/tests/ui/implicit_hasher.fixed index bea5b9afc43a..882a545963b4 100644 --- a/tests/ui/implicit_hasher.fixed +++ b/tests/ui/implicit_hasher.fixed @@ -109,3 +109,27 @@ pub async fn election_vote(_data: HashMap { + $num * 10 + }; + } + + impl Foo for HashMap { + //~^ implicit_hasher + fn make() -> (Self, Self) { + (HashMap::default(), HashMap::with_capacity_and_hasher(times_ten!(5), Default::default())) + } + } + + impl Foo for HashSet { + //~^ implicit_hasher + fn make() -> (Self, Self) { + (HashSet::default(), HashSet::with_capacity_and_hasher(times_ten!(5), Default::default())) + } + } +} diff --git a/tests/ui/implicit_hasher.rs b/tests/ui/implicit_hasher.rs index afdf4da61650..186f9e9978e5 100644 --- a/tests/ui/implicit_hasher.rs +++ b/tests/ui/implicit_hasher.rs @@ -109,3 +109,27 @@ pub async fn election_vote(_data: HashMap) {} //~^ implicit_hasher fn main() {} + +mod issue16128 { + use super::*; + + macro_rules! times_ten { + ($num:expr) => { + $num * 10 + }; + } + + impl Foo for HashMap { + //~^ implicit_hasher + fn make() -> (Self, Self) { + (HashMap::new(), HashMap::with_capacity(times_ten!(5))) + } + } + + impl Foo for HashSet { + //~^ implicit_hasher + fn make() -> (Self, Self) { + (HashSet::new(), HashSet::with_capacity(times_ten!(5))) + } + } +} diff --git a/tests/ui/implicit_hasher.stderr b/tests/ui/implicit_hasher.stderr index 6735998ed654..326115c8e9a3 100644 --- a/tests/ui/implicit_hasher.stderr +++ b/tests/ui/implicit_hasher.stderr @@ -122,5 +122,33 @@ help: add a type parameter for `BuildHasher` LL | pub async fn election_vote(_data: HashMap) {} | +++++++++++++++++++++++++++++ +++ -error: aborting due to 9 previous errors +error: impl for `HashMap` should be generalized over different hashers + --> tests/ui/implicit_hasher.rs:122:40 + | +LL | impl Foo for HashMap { + | ^^^^^^^^^^^^^ + | +help: add a type parameter for `BuildHasher` + | +LL ~ impl Foo for HashMap { +LL | +LL | fn make() -> (Self, Self) { +LL ~ (HashMap::default(), HashMap::with_capacity_and_hasher(times_ten!(5), Default::default())) + | + +error: impl for `HashSet` should be generalized over different hashers + --> tests/ui/implicit_hasher.rs:129:37 + | +LL | impl Foo for HashSet { + | ^^^^^^^^^^ + | +help: add a type parameter for `BuildHasher` + | +LL ~ impl Foo for HashSet { +LL | +LL | fn make() -> (Self, Self) { +LL ~ (HashSet::default(), HashSet::with_capacity_and_hasher(times_ten!(5), Default::default())) + | + +error: aborting due to 11 previous errors diff --git a/tests/ui/missing_doc.rs b/tests/ui/missing_doc.rs deleted file mode 100644 index 705de959cb7d..000000000000 --- a/tests/ui/missing_doc.rs +++ /dev/null @@ -1,148 +0,0 @@ -//@needs-asm-support -//@aux-build: proc_macros.rs -//@aux-build: proc_macro_attr.rs - -#![warn(clippy::missing_docs_in_private_items)] -// When denying at the crate level, be sure to not get random warnings from the -// injected intrinsics by the compiler. -#![allow(dead_code)] -//! Some garbage docs for the crate here -#![doc = "More garbage"] - -#[macro_use] -extern crate proc_macro_attr; -extern crate proc_macros; - -use proc_macros::with_span; -use std::arch::global_asm; - -type Typedef = String; -//~^ missing_docs_in_private_items -pub type PubTypedef = String; - -mod module_no_dox {} -//~^ missing_docs_in_private_items -pub mod pub_module_no_dox {} - -/// dox -pub fn foo() {} -pub fn foo2() {} -fn foo3() {} -//~^ missing_docs_in_private_items -#[allow(clippy::missing_docs_in_private_items)] -pub fn foo4() {} - -// It sure is nice if doc(hidden) implies allow(missing_docs), and that it -// applies recursively -#[doc(hidden)] -mod a { - pub fn baz() {} - pub mod b { - pub fn baz() {} - } -} - -enum Baz { - //~^ missing_docs_in_private_items - BazA { a: isize, b: isize }, - //~^ missing_docs_in_private_items - //~| missing_docs_in_private_items - //~| missing_docs_in_private_items - BarB, - //~^ missing_docs_in_private_items -} - -pub enum PubBaz { - PubBazA { a: isize }, -} - -/// dox -pub enum PubBaz2 { - /// dox - PubBaz2A { - /// dox - a: isize, - }, -} - -#[allow(clippy::missing_docs_in_private_items)] -pub enum PubBaz3 { - PubBaz3A { b: isize }, -} - -#[doc(hidden)] -pub fn baz() {} - -const FOO: u32 = 0; -//~^ missing_docs_in_private_items -/// dox -pub const FOO1: u32 = 0; -#[allow(clippy::missing_docs_in_private_items)] -pub const FOO2: u32 = 0; -#[doc(hidden)] -pub const FOO3: u32 = 0; -pub const FOO4: u32 = 0; - -static BAR: u32 = 0; -//~^ missing_docs_in_private_items -/// dox -pub static BAR1: u32 = 0; -#[allow(clippy::missing_docs_in_private_items)] -pub static BAR2: u32 = 0; -#[doc(hidden)] -pub static BAR3: u32 = 0; -pub static BAR4: u32 = 0; - -mod internal_impl { - //~^ missing_docs_in_private_items - /// dox - pub fn documented() {} - pub fn undocumented1() {} - pub fn undocumented2() {} - fn undocumented3() {} - //~^ missing_docs_in_private_items - /// dox - pub mod globbed { - /// dox - pub fn also_documented() {} - pub fn also_undocumented1() {} - fn also_undocumented2() {} - //~^ missing_docs_in_private_items - } -} -/// dox -pub mod public_interface { - pub use crate::internal_impl::globbed::*; - pub use crate::internal_impl::{documented as foo, documented, undocumented1 as bar, undocumented2}; -} - -fn main() {} - -// Ensure global asm doesn't require documentation. -global_asm! { "" } - -// Don't lint proc macro output with an unexpected span. -with_span!(span pub struct FooPm { pub field: u32}); -with_span!(span pub struct FooPm2;); -with_span!(span pub enum FooPm3 { A, B(u32), C { field: u32 }}); -with_span!(span pub fn foo_pm() {}); -with_span!(span pub static FOO_PM: u32 = 0;); -with_span!(span pub const FOO2_PM: u32 = 0;); - -// Don't lint unnamed constants -const _: () = (); - -fn issue13298() { - //~^ missing_docs_in_private_items - // Rustdoc doesn't generate documentation for items within other items like fns or consts - const MSG: &str = "Hello, world!"; -} - -// issue #12197 -// Undocumented field originated inside of spanned proc-macro attribute -/// Some dox for struct. -#[rewrite_struct] -pub struct Test { - /// Dox - a: u8, -} diff --git a/tests/ui/missing_doc.stderr b/tests/ui/missing_doc.stderr deleted file mode 100644 index 63e440b82d14..000000000000 --- a/tests/ui/missing_doc.stderr +++ /dev/null @@ -1,102 +0,0 @@ -error: missing documentation for a type alias - --> tests/ui/missing_doc.rs:19:1 - | -LL | type Typedef = String; - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` - -error: missing documentation for a module - --> tests/ui/missing_doc.rs:23:1 - | -LL | mod module_no_dox {} - | ^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a function - --> tests/ui/missing_doc.rs:30:1 - | -LL | fn foo3() {} - | ^^^^^^^^^^^^ - -error: missing documentation for an enum - --> tests/ui/missing_doc.rs:45:1 - | -LL | / enum Baz { -LL | | -LL | | BazA { a: isize, b: isize }, -... | -LL | | } - | |_^ - -error: missing documentation for a variant - --> tests/ui/missing_doc.rs:47:5 - | -LL | BazA { a: isize, b: isize }, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a struct field - --> tests/ui/missing_doc.rs:47:12 - | -LL | BazA { a: isize, b: isize }, - | ^^^^^^^^ - -error: missing documentation for a struct field - --> tests/ui/missing_doc.rs:47:22 - | -LL | BazA { a: isize, b: isize }, - | ^^^^^^^^ - -error: missing documentation for a variant - --> tests/ui/missing_doc.rs:51:5 - | -LL | BarB, - | ^^^^ - -error: missing documentation for a constant - --> tests/ui/missing_doc.rs:76:1 - | -LL | const FOO: u32 = 0; - | ^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a static - --> tests/ui/missing_doc.rs:86:1 - | -LL | static BAR: u32 = 0; - | ^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a module - --> tests/ui/missing_doc.rs:96:1 - | -LL | / mod internal_impl { -LL | | -LL | | /// dox -LL | | pub fn documented() {} -... | -LL | | } - | |_^ - -error: missing documentation for a function - --> tests/ui/missing_doc.rs:102:5 - | -LL | fn undocumented3() {} - | ^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a function - --> tests/ui/missing_doc.rs:109:9 - | -LL | fn also_undocumented2() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a function - --> tests/ui/missing_doc.rs:135:1 - | -LL | / fn issue13298() { -LL | | -LL | | // Rustdoc doesn't generate documentation for items within other items like fns or consts -LL | | const MSG: &str = "Hello, world!"; -LL | | } - | |_^ - -error: aborting due to 14 previous errors - diff --git a/tests/ui/missing_doc_crate.rs b/tests/ui/missing_doc_crate.rs deleted file mode 100644 index e6e783a2bb40..000000000000 --- a/tests/ui/missing_doc_crate.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ check-pass - -#![warn(clippy::missing_docs_in_private_items)] -#![allow(clippy::doc_include_without_cfg)] -#![doc = include_str!("../../README.md")] - -fn main() {} diff --git a/tests/ui/missing_doc_crate_missing.rs b/tests/ui/missing_doc_crate_missing.rs deleted file mode 100644 index f55d8b67cb84..000000000000 --- a/tests/ui/missing_doc_crate_missing.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![warn(clippy::missing_docs_in_private_items)] -//~^ missing_docs_in_private_items - -fn main() {} diff --git a/tests/ui/missing_doc_crate_missing.stderr b/tests/ui/missing_doc_crate_missing.stderr deleted file mode 100644 index d6a4342c5031..000000000000 --- a/tests/ui/missing_doc_crate_missing.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: missing documentation for the crate - --> tests/ui/missing_doc_crate_missing.rs:1:1 - | -LL | / #![warn(clippy::missing_docs_in_private_items)] -... | -LL | | fn main() {} - | |____________^ - | - = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` - -error: aborting due to 1 previous error - diff --git a/tests/ui/missing_doc_impl.rs b/tests/ui/missing_doc_impl.rs deleted file mode 100644 index 034ce31dfe76..000000000000 --- a/tests/ui/missing_doc_impl.rs +++ /dev/null @@ -1,114 +0,0 @@ -//@aux-build: proc_macros.rs - -#![warn(clippy::missing_docs_in_private_items)] -#![allow(dead_code)] -#![feature(associated_type_defaults)] - -//! Some garbage docs for the crate here -#![doc = "More garbage"] - -extern crate proc_macros; -use proc_macros::with_span; - -struct Foo { - //~^ missing_docs_in_private_items - a: isize, - //~^ missing_docs_in_private_items - b: isize, - //~^ missing_docs_in_private_items -} - -pub struct PubFoo { - pub a: isize, - b: isize, - //~^ missing_docs_in_private_items -} - -#[allow(clippy::missing_docs_in_private_items)] -pub struct PubFoo2 { - pub a: isize, - pub c: isize, -} - -/// dox -pub trait A { - /// dox - fn foo(&self); - /// dox - fn foo_with_impl(&self) {} -} - -#[allow(clippy::missing_docs_in_private_items)] -trait B { - fn foo(&self); - fn foo_with_impl(&self) {} -} - -pub trait C { - fn foo(&self); - fn foo_with_impl(&self) {} -} - -#[allow(clippy::missing_docs_in_private_items)] -pub trait D { - fn dummy(&self) {} -} - -/// dox -pub trait E: Sized { - type AssociatedType; - type AssociatedTypeDef = Self; - - /// dox - type DocumentedType; - /// dox - type DocumentedTypeDef = Self; - /// dox - fn dummy(&self) {} -} - -impl Foo { - pub fn new() -> Self { - //~^ missing_docs_in_private_items - Foo { a: 0, b: 0 } - } - fn bar() {} - //~^ missing_docs_in_private_items -} - -impl PubFoo { - pub fn foo() {} - /// dox - pub fn foo1() {} - #[must_use = "yep"] - fn foo2() -> u32 { - //~^ missing_docs_in_private_items - 1 - } - #[allow(clippy::missing_docs_in_private_items)] - pub fn foo3() {} -} - -#[allow(clippy::missing_docs_in_private_items)] -trait F { - fn a(); - fn b(&self); -} - -// should need to redefine documentation for implementations of traits -impl F for Foo { - fn a() {} - fn b(&self) {} -} - -fn main() {} - -// don't lint proc macro output -with_span!(span - pub struct FooPm; - impl FooPm { - pub fn foo() {} - pub const fn bar() {} - pub const X: u32 = 0; - } -); diff --git a/tests/ui/missing_doc_impl.stderr b/tests/ui/missing_doc_impl.stderr deleted file mode 100644 index 999ff06f593e..000000000000 --- a/tests/ui/missing_doc_impl.stderr +++ /dev/null @@ -1,57 +0,0 @@ -error: missing documentation for a struct - --> tests/ui/missing_doc_impl.rs:13:1 - | -LL | / struct Foo { -LL | | -LL | | a: isize, -... | -LL | | } - | |_^ - | - = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` - -error: missing documentation for a struct field - --> tests/ui/missing_doc_impl.rs:15:5 - | -LL | a: isize, - | ^^^^^^^^ - -error: missing documentation for a struct field - --> tests/ui/missing_doc_impl.rs:17:5 - | -LL | b: isize, - | ^^^^^^^^ - -error: missing documentation for a struct field - --> tests/ui/missing_doc_impl.rs:23:5 - | -LL | b: isize, - | ^^^^^^^^ - -error: missing documentation for an associated function - --> tests/ui/missing_doc_impl.rs:71:5 - | -LL | / pub fn new() -> Self { -LL | | -LL | | Foo { a: 0, b: 0 } -LL | | } - | |_____^ - -error: missing documentation for an associated function - --> tests/ui/missing_doc_impl.rs:75:5 - | -LL | fn bar() {} - | ^^^^^^^^^^^ - -error: missing documentation for an associated function - --> tests/ui/missing_doc_impl.rs:84:5 - | -LL | / fn foo2() -> u32 { -LL | | -LL | | 1 -LL | | } - | |_____^ - -error: aborting due to 7 previous errors - diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index 132673d5164a..c1512ba3e269 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -105,6 +105,14 @@ fn correct3() { } } +fn with_adjustment(f: &unsafe fn()) { + unsafe { + //~^ multiple_unsafe_ops_per_block + f(); + f(); + } +} + fn issue10064() { unsafe fn read_char_bad(ptr: *const u8) -> char { unsafe { char::from_u32_unchecked(*ptr.cast::()) } @@ -209,4 +217,99 @@ async fn foo() {} } } +fn issue16076() { + #[derive(Clone, Copy)] + union U { + i: u32, + f: f32, + } + + let u = U { i: 0 }; + + // Taking a raw pointer to a place is safe since Rust 1.92 + unsafe { + _ = &raw const u.i; + _ = &raw const u.i; + } + + // Taking a reference to a union field is not safe + unsafe { + //~^ multiple_unsafe_ops_per_block + _ = &u.i; + _ = &u.i; + } + + // Check that we still check and lint the prefix of the raw pointer to a field access + #[expect(clippy::deref_addrof)] + unsafe { + //~^ multiple_unsafe_ops_per_block + _ = &raw const (*&raw const u).i; + _ = &raw const (*&raw const u).i; + } + + union V { + u: U, + } + + // Taking a raw pointer to a union field of an union field (etc.) is safe + let v = V { u }; + unsafe { + _ = &raw const v.u.i; + _ = &raw const v.u.i; + } + + // Check that unions in structs work properly as well + struct T { + u: U, + } + let t = T { u }; + unsafe { + _ = &raw const t.u.i; + _ = &raw const t.u.i; + } + + // As well as structs in unions + #[derive(Clone, Copy)] + struct X { + i: i32, + } + union Z { + x: X, + } + let z = Z { x: X { i: 0 } }; + unsafe { + _ = &raw const z.x.i; + _ = &raw const z.x.i; + } + + // If a field needs to be adjusted then it is accessed + struct S { + i: i32, + } + union W<'a> { + s: &'a S, + } + let s = S { i: 0 }; + let w = W { s: &s }; + unsafe { + //~^ multiple_unsafe_ops_per_block + _ = &raw const w.s.i; + _ = &raw const w.s.i; + } +} + +fn check_closures() { + unsafe fn apply(f: impl Fn()) { + todo!() + } + unsafe fn f(_x: i32) { + todo!() + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + apply(|| f(0)); + } +} + fn main() {} diff --git a/tests/ui/multiple_unsafe_ops_per_block.stderr b/tests/ui/multiple_unsafe_ops_per_block.stderr index 922a464c6b6e..63f7742b734b 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -113,24 +113,45 @@ LL | asm!("nop"); | ^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:110:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:109:5 + | +LL | / unsafe { +LL | | +LL | | f(); +LL | | f(); +LL | | } + | |_____^ + | +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:111:9 + | +LL | f(); + | ^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:112:9 + | +LL | f(); + | ^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:118:9 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:110:18 + --> tests/ui/multiple_unsafe_ops_per_block.rs:118:18 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:110:43 + --> tests/ui/multiple_unsafe_ops_per_block.rs:118:43 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:131:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:139:9 | LL | / unsafe { LL | | @@ -140,18 +161,18 @@ LL | | } | |_________^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:133:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:141:13 | LL | x(); | ^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:134:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:142:13 | LL | x(); | ^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:143:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:151:13 | LL | / unsafe { LL | | @@ -161,18 +182,18 @@ LL | | } | |_____________^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:145:17 + --> tests/ui/multiple_unsafe_ops_per_block.rs:153:17 | LL | T::X(); | ^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:146:17 + --> tests/ui/multiple_unsafe_ops_per_block.rs:154:17 | LL | T::X(); | ^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:154:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:162:9 | LL | / unsafe { LL | | @@ -182,18 +203,18 @@ LL | | } | |_________^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:156:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:164:13 | LL | x.0(); | ^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:157:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:165:13 | LL | x.0(); | ^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:184:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:192:5 | LL | / unsafe { LL | | @@ -204,18 +225,18 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:186:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:194:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ note: modification of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:187:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:195:9 | LL | STATIC += 1; | ^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:199:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:207:5 | LL | / unsafe { LL | | @@ -225,18 +246,18 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:201:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:209:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:202:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:210:9 | LL | foo_unchecked().await; | ^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:206:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:214:5 | LL | / unsafe { LL | | @@ -245,15 +266,98 @@ LL | | } | |_____^ | note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:208:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:216:9 | LL | Some(foo_unchecked()).unwrap_unchecked().await; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:208:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:216:14 | LL | Some(foo_unchecked()).unwrap_unchecked().await; | ^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:236:5 + | +LL | / unsafe { +LL | | +LL | | _ = &u.i; +LL | | _ = &u.i; +LL | | } + | |_____^ + | +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:238:14 + | +LL | _ = &u.i; + | ^^^ +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:239:14 + | +LL | _ = &u.i; + | ^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:244:5 + | +LL | / unsafe { +LL | | +LL | | _ = &raw const (*&raw const u).i; +LL | | _ = &raw const (*&raw const u).i; +LL | | } + | |_____^ + | +note: raw pointer dereference occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:246:24 + | +LL | _ = &raw const (*&raw const u).i; + | ^^^^^^^^^^^^^^^ +note: raw pointer dereference occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:247:24 + | +LL | _ = &raw const (*&raw const u).i; + | ^^^^^^^^^^^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:294:5 + | +LL | / unsafe { +LL | | +LL | | _ = &raw const w.s.i; +LL | | _ = &raw const w.s.i; +LL | | } + | |_____^ + | +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:296:24 + | +LL | _ = &raw const w.s.i; + | ^^^ +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:297:24 + | +LL | _ = &raw const w.s.i; + | ^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:309:5 + | +LL | / unsafe { +LL | | +LL | | apply(|| f(0)); +LL | | } + | |_____^ + | +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:311:9 + | +LL | apply(|| f(0)); + | ^^^^^^^^^^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:311:18 + | +LL | apply(|| f(0)); + | ^^^^ + +error: aborting due to 16 previous errors diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index a54a4ce13d53..08903ef7fdda 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -166,3 +166,32 @@ fn issue13902() { //~^ redundant_pattern_matching } } + +fn issue16045() { + fn f() -> Result<(), ()> { + let x = Ok::<_, ()>(Some(123)); + if x?.is_some() { + //~^ redundant_pattern_matching + } + + Ok(()) + } + + async fn g() { + struct F { + x: Option, + } + + impl Future for F { + type Output = Option; + + fn poll(self: std::pin::Pin<&mut Self>, _: &mut std::task::Context<'_>) -> std::task::Poll { + std::task::Poll::Ready(self.x) + } + } + let x = F { x: Some(123) }; + if x.await.is_some() { + //~^ redundant_pattern_matching + } + } +} diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index 7252fce8cce6..95eff3f9ebf9 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -202,3 +202,32 @@ fn issue13902() { //~^ redundant_pattern_matching } } + +fn issue16045() { + fn f() -> Result<(), ()> { + let x = Ok::<_, ()>(Some(123)); + if let Some(_) = x? { + //~^ redundant_pattern_matching + } + + Ok(()) + } + + async fn g() { + struct F { + x: Option, + } + + impl Future for F { + type Output = Option; + + fn poll(self: std::pin::Pin<&mut Self>, _: &mut std::task::Context<'_>) -> std::task::Poll { + std::task::Poll::Ready(self.x) + } + } + let x = F { x: Some(123) }; + if let Some(_) = x.await { + //~^ redundant_pattern_matching + } + } +} diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index e5a6598898aa..6fd0c5a6f859 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -224,5 +224,17 @@ error: redundant pattern matching, consider using `is_none()` LL | let _ = matches!(*p, None); | ^^^^^^^^^^^^^^^^^^ help: try: `(*p).is_none()` -error: aborting due to 31 previous errors +error: redundant pattern matching, consider using `is_some()` + --> tests/ui/redundant_pattern_matching_option.rs:209:16 + | +LL | if let Some(_) = x? { + | -------^^^^^^^----- help: try: `if x?.is_some()` + +error: redundant pattern matching, consider using `is_some()` + --> tests/ui/redundant_pattern_matching_option.rs:229:16 + | +LL | if let Some(_) = x.await { + | -------^^^^^^^---------- help: try: `if x.await.is_some()` + +error: aborting due to 33 previous errors diff --git a/tests/ui/sliced_string_as_bytes.fixed b/tests/ui/sliced_string_as_bytes.fixed index 16c0daff78fd..b5576188b83f 100644 --- a/tests/ui/sliced_string_as_bytes.fixed +++ b/tests/ui/sliced_string_as_bytes.fixed @@ -32,6 +32,12 @@ fn main() { let bytes = &"consectetur adipiscing".as_bytes()[..=5]; //~^ sliced_string_as_bytes + // this lint is a perf lint meant to catch utf-8 alignment checks. + // while the slicing here *is* redundant, it's more like a needless borrow, and shouldn't affect + // perf + let bytes = s[..].as_bytes(); + let bytes = string[..].as_bytes(); + let f = Foo; let bytes = f[0..4].as_bytes(); } diff --git a/tests/ui/sliced_string_as_bytes.rs b/tests/ui/sliced_string_as_bytes.rs index 67985ae5b984..58b8d9290294 100644 --- a/tests/ui/sliced_string_as_bytes.rs +++ b/tests/ui/sliced_string_as_bytes.rs @@ -32,6 +32,12 @@ fn main() { let bytes = "consectetur adipiscing"[..=5].as_bytes(); //~^ sliced_string_as_bytes + // this lint is a perf lint meant to catch utf-8 alignment checks. + // while the slicing here *is* redundant, it's more like a needless borrow, and shouldn't affect + // perf + let bytes = s[..].as_bytes(); + let bytes = string[..].as_bytes(); + let f = Foo; let bytes = f[0..4].as_bytes(); } diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index e7099104f942..afb79deac20f 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -128,4 +128,17 @@ fn bytes_to_str(mb: &mut [u8]) { //~^ transmute_bytes_to_str } +fn issue16104() { + let b = vec![1_u8, 2_u8]; + macro_rules! take_ref { + ($x:expr) => { + $x.as_slice() + }; + } + unsafe { + let _: &str = std::mem::transmute(take_ref!(b)); + //~^ transmute_bytes_to_str + } +} + fn main() {} diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index 9478db09481a..6f9a0b717fc9 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -106,5 +106,11 @@ error: transmute from a `&[u8]` to a `&str` LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 16 previous errors +error: transmute from a `&[u8]` to a `&str` + --> tests/ui/transmute.rs:139:23 + | +LL | let _: &str = std::mem::transmute(take_ref!(b)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(take_ref!(b)).unwrap()` + +error: aborting due to 17 previous errors diff --git a/tests/ui/transmute_ref_to_ref.rs b/tests/ui/transmute_ref_to_ref.rs index 8bdf07b4a428..ed8fb8083291 100644 --- a/tests/ui/transmute_ref_to_ref.rs +++ b/tests/ui/transmute_ref_to_ref.rs @@ -18,3 +18,23 @@ fn main() { //~^ transmute_ptr_to_ptr } } + +fn issue16104(make_ptr: fn() -> *const u32) { + macro_rules! call { + ($x:expr) => { + $x() + }; + } + macro_rules! take_ref { + ($x:expr) => { + &$x + }; + } + + unsafe { + let _: *const f32 = std::mem::transmute(call!(make_ptr)); + //~^ transmute_ptr_to_ptr + let _: &f32 = std::mem::transmute(take_ref!(1u32)); + //~^ transmute_ptr_to_ptr + } +} diff --git a/tests/ui/transmute_ref_to_ref.stderr b/tests/ui/transmute_ref_to_ref.stderr index e8d659f9c5d8..1b845ef859d8 100644 --- a/tests/ui/transmute_ref_to_ref.stderr +++ b/tests/ui/transmute_ref_to_ref.stderr @@ -22,5 +22,23 @@ error: transmute from a reference to a reference LL | let alt_slice: &[u32] = unsafe { std::mem::transmute(bytes) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` -error: aborting due to 3 previous errors +error: transmute from a pointer to a pointer + --> tests/ui/transmute_ref_to_ref.rs:35:29 + | +LL | let _: *const f32 = std::mem::transmute(call!(make_ptr)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `pointer::cast` instead + | +LL - let _: *const f32 = std::mem::transmute(call!(make_ptr)); +LL + let _: *const f32 = call!(make_ptr).cast::(); + | + +error: transmute from a reference to a reference + --> tests/ui/transmute_ref_to_ref.rs:37:23 + | +LL | let _: &f32 = std::mem::transmute(take_ref!(1u32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(take_ref!(1u32) as *const u32 as *const f32)` + +error: aborting due to 5 previous errors diff --git a/tests/ui/unchecked_time_subtraction.stderr b/tests/ui/unchecked_time_subtraction.stderr index 7a39712269cf..c129497447fc 100644 --- a/tests/ui/unchecked_time_subtraction.stderr +++ b/tests/ui/unchecked_time_subtraction.stderr @@ -1,4 +1,4 @@ -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:9:13 | LL | let _ = _first - second; @@ -7,43 +7,43 @@ LL | let _ = _first - second; = note: `-D clippy::unchecked-time-subtraction` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unchecked_time_subtraction)]` -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:12:13 | LL | let _ = Instant::now() - Duration::from_secs(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(Duration::from_secs(5)).unwrap()` -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:15:13 | LL | let _ = _first - Duration::from_secs(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `_first.checked_sub(Duration::from_secs(5)).unwrap()` -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:18:13 | LL | let _ = Instant::now() - second; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(second).unwrap()` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:25:13 | LL | let _ = dur1 - dur2; | ^^^^^^^^^^^ help: try: `dur1.checked_sub(dur2).unwrap()` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:28:13 | LL | let _ = Duration::from_secs(10) - Duration::from_secs(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::from_secs(10).checked_sub(Duration::from_secs(5)).unwrap()` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:31:13 | LL | let _ = second - dur1; | ^^^^^^^^^^^^^ help: try: `second.checked_sub(dur1).unwrap()` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:35:13 | LL | let _ = 2 * dur1 - dur2; diff --git a/tests/ui/unchecked_time_subtraction_unfixable.stderr b/tests/ui/unchecked_time_subtraction_unfixable.stderr index c25c112b06ce..017e5b1c7c11 100644 --- a/tests/ui/unchecked_time_subtraction_unfixable.stderr +++ b/tests/ui/unchecked_time_subtraction_unfixable.stderr @@ -1,4 +1,4 @@ -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction_unfixable.rs:12:13 | LL | let _ = dur1 - dur2 - dur3; @@ -7,19 +7,19 @@ LL | let _ = dur1 - dur2 - dur3; = note: `-D clippy::unchecked-time-subtraction` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unchecked_time_subtraction)]` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction_unfixable.rs:12:13 | LL | let _ = dur1 - dur2 - dur3; | ^^^^^^^^^^^ help: try: `dur1.checked_sub(dur2).unwrap()` -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction_unfixable.rs:19:13 | LL | let _ = instant1 - dur2 - dur3; | ^^^^^^^^^^^^^^^^^^^^^^ -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction_unfixable.rs:19:13 | LL | let _ = instant1 - dur2 - dur3; diff --git a/tests/ui/useless_asref.fixed b/tests/ui/useless_asref.fixed index 3c3ea5a736d4..54a7c0a8c080 100644 --- a/tests/ui/useless_asref.fixed +++ b/tests/ui/useless_asref.fixed @@ -258,6 +258,41 @@ fn issue_14828() { ().as_ref(); } +fn issue16098(exts: Vec<&str>) { + use std::borrow::Cow; + + let v: Vec> = exts.iter().map(|s| Cow::Borrowed(*s)).collect(); + //~^ useless_asref + + trait Identity { + fn id(self) -> Self + where + Self: Sized, + { + self + } + } + impl Identity for &str {} + + let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.id())).collect(); + //~^ useless_asref + + let v: Vec> = exts + .iter() + .map(|s| Cow::Borrowed(*std::convert::identity(s))) + //~^ useless_asref + .collect(); + + struct Wrapper<'a>(&'a str); + let exts_field: Vec = exts.iter().map(|s| Wrapper(s)).collect(); + let v: Vec> = exts_field.iter().map(|w| Cow::Borrowed(w.0)).collect(); + //~^ useless_asref + + let exts_index: Vec<&[&str]> = exts.iter().map(|s| std::slice::from_ref(s)).collect(); + let v: Vec> = exts_index.iter().map(|arr| Cow::Borrowed(arr[0])).collect(); + //~^ useless_asref +} + fn main() { not_ok(); ok(); diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs index c173dd677152..1b9ce1d46233 100644 --- a/tests/ui/useless_asref.rs +++ b/tests/ui/useless_asref.rs @@ -258,6 +258,41 @@ impl T for () {} ().as_ref(); } +fn issue16098(exts: Vec<&str>) { + use std::borrow::Cow; + + let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.as_ref())).collect(); + //~^ useless_asref + + trait Identity { + fn id(self) -> Self + where + Self: Sized, + { + self + } + } + impl Identity for &str {} + + let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.id().as_ref())).collect(); + //~^ useless_asref + + let v: Vec> = exts + .iter() + .map(|s| Cow::Borrowed(std::convert::identity(s).as_ref())) + //~^ useless_asref + .collect(); + + struct Wrapper<'a>(&'a str); + let exts_field: Vec = exts.iter().map(|s| Wrapper(s)).collect(); + let v: Vec> = exts_field.iter().map(|w| Cow::Borrowed(w.0.as_ref())).collect(); + //~^ useless_asref + + let exts_index: Vec<&[&str]> = exts.iter().map(|s| std::slice::from_ref(s)).collect(); + let v: Vec> = exts_index.iter().map(|arr| Cow::Borrowed(arr[0].as_ref())).collect(); + //~^ useless_asref +} + fn main() { not_ok(); ok(); diff --git a/tests/ui/useless_asref.stderr b/tests/ui/useless_asref.stderr index 8255f5d9d2ab..861472b4419e 100644 --- a/tests/ui/useless_asref.stderr +++ b/tests/ui/useless_asref.stderr @@ -112,5 +112,35 @@ error: this call to `as_ref.map(...)` does nothing LL | Some(1).as_ref().map(|&x| x.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(1).clone()` -error: aborting due to 18 previous errors +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:264:66 + | +LL | let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.as_ref())).collect(); + | ^^^^^^^^^^ help: try: `*s` + +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:277:66 + | +LL | let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.id().as_ref())).collect(); + | ^^^^^^^^^^^^^^^ help: try: `s.id()` + +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:282:32 + | +LL | .map(|s| Cow::Borrowed(std::convert::identity(s).as_ref())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `*std::convert::identity(s)` + +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:288:72 + | +LL | let v: Vec> = exts_field.iter().map(|w| Cow::Borrowed(w.0.as_ref())).collect(); + | ^^^^^^^^^^^^ help: try: `w.0` + +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:292:74 + | +LL | let v: Vec> = exts_index.iter().map(|arr| Cow::Borrowed(arr[0].as_ref())).collect(); + | ^^^^^^^^^^^^^^^ help: try: `arr[0]` + +error: aborting due to 23 previous errors diff --git a/tests/ui/vec.fixed b/tests/ui/useless_vec.fixed similarity index 90% rename from tests/ui/vec.fixed rename to tests/ui/useless_vec.fixed index 55742459c92c..3cea4862611d 100644 --- a/tests/ui/vec.fixed +++ b/tests/ui/useless_vec.fixed @@ -1,5 +1,4 @@ #![warn(clippy::useless_vec)] -#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args, unused)] use std::rc::Rc; @@ -39,17 +38,14 @@ fn main() { on_mut_slice(&mut [1, 2]); //~^ useless_vec - on_slice(&[1, 2]); - //~^ useless_vec - on_slice(&[1, 2]); - on_mut_slice(&mut [1, 2]); - //~^ useless_vec #[rustfmt::skip] - on_slice(&[1, 2]); - //~^ useless_vec - on_slice(&[1, 2]); - on_mut_slice(&mut [1, 2]); - //~^ useless_vec + #[allow(clippy::nonstandard_macro_braces)] // not an `expect` as it will only lint _before_ the fix + { + on_slice(&[1, 2]); + //~^ useless_vec + on_mut_slice(&mut [1, 2]); + //~^ useless_vec + }; on_slice(&[1; 2]); //~^ useless_vec @@ -75,22 +71,24 @@ fn main() { on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` on_mut_vec(&mut vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` - // Ok + // Ok, size of `vec` higher than `too_large_for_stack` for a in vec![1; 201] { - println!("{:?}", a); + println!("{a:?}"); } // https://github.com/rust-lang/rust-clippy/issues/2262#issuecomment-783979246 let _x: i32 = [1, 2, 3].iter().sum(); //~^ useless_vec - // Do lint - let mut x = [1, 2, 3]; - //~^ useless_vec - x.fill(123); - dbg!(x[0]); - dbg!(x.len()); - dbg!(x.iter().sum::()); + // Do lint, only used as slice + { + let mut x = [1, 2, 3]; + //~^ useless_vec + x.fill(123); + dbg!(x[0]); + dbg!(x.len()); + dbg!(x.iter().sum::()); + } let _x: &[i32] = &[1, 2, 3]; //~^ useless_vec diff --git a/tests/ui/useless_vec.rs b/tests/ui/useless_vec.rs index 880809f81d7a..2b5d71ae7fa4 100644 --- a/tests/ui/useless_vec.rs +++ b/tests/ui/useless_vec.rs @@ -1,15 +1,251 @@ -//@no-rustfix: no suggestions - #![warn(clippy::useless_vec)] -// Regression test for . -fn foo() { - // There should be no suggestion in this case. - let _some_variable = vec![ - //~^ useless_vec - 1, 2, // i'm here to stay - 3, 4, // but this one going away ;-; - ]; // that is life anyways +use std::rc::Rc; + +struct StructWithVec { + _x: Vec, } -fn main() {} +fn on_slice(_: &[u8]) {} + +fn on_mut_slice(_: &mut [u8]) {} + +#[allow(clippy::ptr_arg)] +fn on_vec(_: &Vec) {} + +fn on_mut_vec(_: &mut Vec) {} + +struct Line { + length: usize, +} + +impl Line { + fn length(&self) -> usize { + self.length + } +} + +fn main() { + on_slice(&vec![]); + //~^ useless_vec + on_slice(&[]); + on_mut_slice(&mut vec![]); + //~^ useless_vec + + on_slice(&vec![1, 2]); + //~^ useless_vec + on_slice(&[1, 2]); + on_mut_slice(&mut vec![1, 2]); + //~^ useless_vec + + #[rustfmt::skip] + #[allow(clippy::nonstandard_macro_braces)] // not an `expect` as it will only lint _before_ the fix + { + on_slice(&vec!(1, 2)); + //~^ useless_vec + on_mut_slice(&mut vec!(1, 2)); + //~^ useless_vec + }; + + on_slice(&vec![1; 2]); + //~^ useless_vec + on_slice(&[1; 2]); + on_mut_slice(&mut vec![1; 2]); + //~^ useless_vec + + on_vec(&vec![]); + on_vec(&vec![1, 2]); + on_vec(&vec![1; 2]); + on_mut_vec(&mut vec![]); + on_mut_vec(&mut vec![1, 2]); + on_mut_vec(&mut vec![1; 2]); + + // Now with non-constant expressions + let line = Line { length: 2 }; + + on_slice(&vec![2; line.length]); + on_slice(&vec![2; line.length()]); + on_mut_slice(&mut vec![2; line.length]); + on_mut_slice(&mut vec![2; line.length()]); + + on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` + on_mut_vec(&mut vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` + + // Ok, size of `vec` higher than `too_large_for_stack` + for a in vec![1; 201] { + println!("{a:?}"); + } + + // https://github.com/rust-lang/rust-clippy/issues/2262#issuecomment-783979246 + let _x: i32 = vec![1, 2, 3].iter().sum(); + //~^ useless_vec + + // Do lint, only used as slice + { + let mut x = vec![1, 2, 3]; + //~^ useless_vec + x.fill(123); + dbg!(x[0]); + dbg!(x.len()); + dbg!(x.iter().sum::()); + } + + let _x: &[i32] = &vec![1, 2, 3]; + //~^ useless_vec + + for _ in vec![1, 2, 3] {} + //~^ useless_vec + + // Don't lint + let x = vec![1, 2, 3]; + let _v: Vec = x; + + let x = vec![1, 2, 3]; + let _s = StructWithVec { _x: x }; + + // Explicit type annotation would make the change to [1, 2, 3] + // a compile error. + let _x: Vec = vec![1, 2, 3]; + + // Calling a Vec method through a mutable reference + let mut x = vec![1, 2, 3]; + let re = &mut x; + re.push(4); + + // Comparing arrays whose length is not equal is a compile error + let x = vec![1, 2, 3]; + let y = vec![1, 2, 3, 4]; + dbg!(x == y); + + // Non-copy types + let _x = vec![String::new(); 10]; + #[allow(clippy::rc_clone_in_vec_init)] + let _x = vec![Rc::new(1); 10]; + + // Too large + let _x = vec![1; 201]; +} + +fn issue11075() { + macro_rules! repro { + ($e:expr) => { + stringify!($e) + }; + } + #[allow(clippy::never_loop)] + for _string in vec![repro!(true), repro!(null)] { + //~^ useless_vec + unimplemented!(); + } + + macro_rules! in_macro { + ($e:expr, $vec:expr, $vec2:expr) => {{ + vec![1; 2].fill(3); + vec![1, 2].fill(3); + for _ in vec![1, 2] {} + for _ in vec![1; 2] {} + for _ in vec![$e, $e] {} + for _ in vec![$e; 2] {} + for _ in $vec {} + for _ in $vec2 {} + }}; + } + + in_macro!(1, vec![1, 2], vec![1; 2]); + //~^ useless_vec + //~| useless_vec + + macro_rules! from_macro { + () => { + vec![1, 2, 3] + }; + } + macro_rules! from_macro_repeat { + () => { + vec![1; 3] + }; + } + + for _ in from_macro!() {} + for _ in from_macro_repeat!() {} +} + +#[clippy::msrv = "1.53"] +fn above() { + for a in vec![1, 2, 3] { + //~^ useless_vec + let _: usize = a; + } + + for a in vec![String::new(), String::new()] { + //~^ useless_vec + let _: String = a; + } +} + +#[clippy::msrv = "1.52"] +fn below() { + for a in vec![1, 2, 3] { + let _: usize = a; + } + + for a in vec![String::new(), String::new()] { + let _: String = a; + } +} + +fn func_needing_vec(_bar: usize, _baz: Vec) {} +fn func_not_needing_vec(_bar: usize, _baz: usize) {} + +fn issue11861() { + macro_rules! this_macro_needs_vec { + ($x:expr) => {{ + func_needing_vec($x.iter().sum(), $x); + for _ in $x {} + }}; + } + macro_rules! this_macro_doesnt_need_vec { + ($x:expr) => {{ func_not_needing_vec($x.iter().sum(), $x.iter().sum()) }}; + } + + // Do not lint the next line + this_macro_needs_vec!(vec![1]); + this_macro_doesnt_need_vec!(vec![1]); + //~^ useless_vec + + macro_rules! m { + ($x:expr) => { + fn f2() { + let _x: Vec = $x; + } + fn f() { + let _x = $x; + $x.starts_with(&[]); + } + }; + } + + // should not lint + m!(vec![1]); +} + +fn issue_11958() { + fn f(_s: &[String]) {} + + // should not lint, `String` is not `Copy` + f(&vec!["test".to_owned(); 2]); +} + +fn issue_12101() { + for a in &(vec![1, 2]) {} + //~^ useless_vec +} + +fn issue_14531() { + // The lint used to suggest using an array rather than a reference to a slice. + + fn requires_ref_slice(v: &[()]) {} + let v = &vec![]; + //~^ useless_vec + requires_ref_slice(v); +} diff --git a/tests/ui/useless_vec.stderr b/tests/ui/useless_vec.stderr index e47364fb06d3..65120d8b338f 100644 --- a/tests/ui/useless_vec.stderr +++ b/tests/ui/useless_vec.stderr @@ -1,21 +1,125 @@ error: useless use of `vec!` - --> tests/ui/useless_vec.rs:8:26 + --> tests/ui/useless_vec.rs:29:14 | -LL | let _some_variable = vec![ - | __________________________^ -LL | | -LL | | 1, 2, // i'm here to stay -LL | | 3, 4, // but this one going away ;-; -LL | | ]; // that is life anyways - | |_____^ +LL | on_slice(&vec![]); + | ^^^^^^^ help: you can use a slice directly: `&[]` | = note: `-D clippy::useless-vec` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` -help: you can use an array directly - | -LL ~ let _some_variable = [1, 2, // i'm here to stay -LL ~ 3, 4]; // that is life anyways - | -error: aborting due to 1 previous error +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:32:18 + | +LL | on_mut_slice(&mut vec![]); + | ^^^^^^^^^^^ help: you can use a slice directly: `&mut []` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:35:14 + | +LL | on_slice(&vec![1, 2]); + | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:38:18 + | +LL | on_mut_slice(&mut vec![1, 2]); + | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:44:18 + | +LL | on_slice(&vec!(1, 2)); + | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:46:22 + | +LL | on_mut_slice(&mut vec!(1, 2)); + | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:50:14 + | +LL | on_slice(&vec![1; 2]); + | ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:53:18 + | +LL | on_mut_slice(&mut vec![1; 2]); + | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1; 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:80:19 + | +LL | let _x: i32 = vec![1, 2, 3].iter().sum(); + | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:85:21 + | +LL | let mut x = vec![1, 2, 3]; + | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:93:22 + | +LL | let _x: &[i32] = &vec![1, 2, 3]; + | ^^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:96:14 + | +LL | for _ in vec![1, 2, 3] {} + | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:136:20 + | +LL | for _string in vec![repro!(true), repro!(null)] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[repro!(true), repro!(null)]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:154:18 + | +LL | in_macro!(1, vec![1, 2], vec![1; 2]); + | ^^^^^^^^^^ help: you can use an array directly: `[1, 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:154:30 + | +LL | in_macro!(1, vec![1, 2], vec![1; 2]); + | ^^^^^^^^^^ help: you can use an array directly: `[1; 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:175:14 + | +LL | for a in vec![1, 2, 3] { + | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:180:14 + | +LL | for a in vec![String::new(), String::new()] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:213:33 + | +LL | this_macro_doesnt_need_vec!(vec![1]); + | ^^^^^^^ help: you can use an array directly: `[1]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:240:14 + | +LL | for a in &(vec![1, 2]) {} + | ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:248:13 + | +LL | let v = &vec![]; + | ^^^^^^^ help: you can use a slice directly: `&[]` + +error: aborting due to 20 previous errors diff --git a/tests/ui/useless_vec_unfixable.rs b/tests/ui/useless_vec_unfixable.rs new file mode 100644 index 000000000000..7f45f4df5ee6 --- /dev/null +++ b/tests/ui/useless_vec_unfixable.rs @@ -0,0 +1,14 @@ +//@no-rustfix: no suggestions +#![warn(clippy::useless_vec)] + +// Regression test for . +fn foo() { + // There should be no suggestion in this case. + let _some_variable = vec![ + //~^ useless_vec + 1, 2, // i'm here to stay + 3, 4, // but this one going away ;-; + ]; // that is life anyways +} + +fn main() {} diff --git a/tests/ui/useless_vec_unfixable.stderr b/tests/ui/useless_vec_unfixable.stderr new file mode 100644 index 000000000000..980194ac7191 --- /dev/null +++ b/tests/ui/useless_vec_unfixable.stderr @@ -0,0 +1,21 @@ +error: useless use of `vec!` + --> tests/ui/useless_vec_unfixable.rs:7:26 + | +LL | let _some_variable = vec![ + | __________________________^ +LL | | +LL | | 1, 2, // i'm here to stay +LL | | 3, 4, // but this one going away ;-; +LL | | ]; // that is life anyways + | |_____^ + | + = note: `-D clippy::useless-vec` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` +help: you can use an array directly + | +LL ~ let _some_variable = [1, 2, // i'm here to stay +LL ~ 3, 4]; // that is life anyways + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs deleted file mode 100644 index fbf7131323c3..000000000000 --- a/tests/ui/vec.rs +++ /dev/null @@ -1,253 +0,0 @@ -#![warn(clippy::useless_vec)] -#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args, unused)] - -use std::rc::Rc; - -struct StructWithVec { - _x: Vec, -} - -fn on_slice(_: &[u8]) {} - -fn on_mut_slice(_: &mut [u8]) {} - -#[allow(clippy::ptr_arg)] -fn on_vec(_: &Vec) {} - -fn on_mut_vec(_: &mut Vec) {} - -struct Line { - length: usize, -} - -impl Line { - fn length(&self) -> usize { - self.length - } -} - -fn main() { - on_slice(&vec![]); - //~^ useless_vec - on_slice(&[]); - on_mut_slice(&mut vec![]); - //~^ useless_vec - - on_slice(&vec![1, 2]); - //~^ useless_vec - on_slice(&[1, 2]); - on_mut_slice(&mut vec![1, 2]); - //~^ useless_vec - - on_slice(&vec![1, 2]); - //~^ useless_vec - on_slice(&[1, 2]); - on_mut_slice(&mut vec![1, 2]); - //~^ useless_vec - #[rustfmt::skip] - on_slice(&vec!(1, 2)); - //~^ useless_vec - on_slice(&[1, 2]); - on_mut_slice(&mut vec![1, 2]); - //~^ useless_vec - - on_slice(&vec![1; 2]); - //~^ useless_vec - on_slice(&[1; 2]); - on_mut_slice(&mut vec![1; 2]); - //~^ useless_vec - - on_vec(&vec![]); - on_vec(&vec![1, 2]); - on_vec(&vec![1; 2]); - on_mut_vec(&mut vec![]); - on_mut_vec(&mut vec![1, 2]); - on_mut_vec(&mut vec![1; 2]); - - // Now with non-constant expressions - let line = Line { length: 2 }; - - on_slice(&vec![2; line.length]); - on_slice(&vec![2; line.length()]); - on_mut_slice(&mut vec![2; line.length]); - on_mut_slice(&mut vec![2; line.length()]); - - on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` - on_mut_vec(&mut vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` - - // Ok - for a in vec![1; 201] { - println!("{:?}", a); - } - - // https://github.com/rust-lang/rust-clippy/issues/2262#issuecomment-783979246 - let _x: i32 = vec![1, 2, 3].iter().sum(); - //~^ useless_vec - - // Do lint - let mut x = vec![1, 2, 3]; - //~^ useless_vec - x.fill(123); - dbg!(x[0]); - dbg!(x.len()); - dbg!(x.iter().sum::()); - - let _x: &[i32] = &vec![1, 2, 3]; - //~^ useless_vec - - for _ in vec![1, 2, 3] {} - //~^ useless_vec - - // Don't lint - let x = vec![1, 2, 3]; - let _v: Vec = x; - - let x = vec![1, 2, 3]; - let _s = StructWithVec { _x: x }; - - // Explicit type annotation would make the change to [1, 2, 3] - // a compile error. - let _x: Vec = vec![1, 2, 3]; - - // Calling a Vec method through a mutable reference - let mut x = vec![1, 2, 3]; - let re = &mut x; - re.push(4); - - // Comparing arrays whose length is not equal is a compile error - let x = vec![1, 2, 3]; - let y = vec![1, 2, 3, 4]; - dbg!(x == y); - - // Non-copy types - let _x = vec![String::new(); 10]; - #[allow(clippy::rc_clone_in_vec_init)] - let _x = vec![Rc::new(1); 10]; - - // Too large - let _x = vec![1; 201]; -} - -fn issue11075() { - macro_rules! repro { - ($e:expr) => { - stringify!($e) - }; - } - #[allow(clippy::never_loop)] - for _string in vec![repro!(true), repro!(null)] { - //~^ useless_vec - unimplemented!(); - } - - macro_rules! in_macro { - ($e:expr, $vec:expr, $vec2:expr) => {{ - vec![1; 2].fill(3); - vec![1, 2].fill(3); - for _ in vec![1, 2] {} - for _ in vec![1; 2] {} - for _ in vec![$e, $e] {} - for _ in vec![$e; 2] {} - for _ in $vec {} - for _ in $vec2 {} - }}; - } - - in_macro!(1, vec![1, 2], vec![1; 2]); - //~^ useless_vec - //~| useless_vec - - macro_rules! from_macro { - () => { - vec![1, 2, 3] - }; - } - macro_rules! from_macro_repeat { - () => { - vec![1; 3] - }; - } - - for _ in from_macro!() {} - for _ in from_macro_repeat!() {} -} - -#[clippy::msrv = "1.53"] -fn above() { - for a in vec![1, 2, 3] { - //~^ useless_vec - let _: usize = a; - } - - for a in vec![String::new(), String::new()] { - //~^ useless_vec - let _: String = a; - } -} - -#[clippy::msrv = "1.52"] -fn below() { - for a in vec![1, 2, 3] { - let _: usize = a; - } - - for a in vec![String::new(), String::new()] { - let _: String = a; - } -} - -fn func_needing_vec(_bar: usize, _baz: Vec) {} -fn func_not_needing_vec(_bar: usize, _baz: usize) {} - -fn issue11861() { - macro_rules! this_macro_needs_vec { - ($x:expr) => {{ - func_needing_vec($x.iter().sum(), $x); - for _ in $x {} - }}; - } - macro_rules! this_macro_doesnt_need_vec { - ($x:expr) => {{ func_not_needing_vec($x.iter().sum(), $x.iter().sum()) }}; - } - - // Do not lint the next line - this_macro_needs_vec!(vec![1]); - this_macro_doesnt_need_vec!(vec![1]); - //~^ useless_vec - - macro_rules! m { - ($x:expr) => { - fn f2() { - let _x: Vec = $x; - } - fn f() { - let _x = $x; - $x.starts_with(&[]); - } - }; - } - - // should not lint - m!(vec![1]); -} - -fn issue_11958() { - fn f(_s: &[String]) {} - - // should not lint, `String` is not `Copy` - f(&vec!["test".to_owned(); 2]); -} - -fn issue_12101() { - for a in &(vec![1, 2]) {} - //~^ useless_vec -} - -fn issue_14531() { - // The lint used to suggest using an array rather than a reference to a slice. - - fn requires_ref_slice(v: &[()]) {} - let v = &vec![]; - //~^ useless_vec - requires_ref_slice(v); -} diff --git a/tests/ui/vec.stderr b/tests/ui/vec.stderr deleted file mode 100644 index d16c8a8944a2..000000000000 --- a/tests/ui/vec.stderr +++ /dev/null @@ -1,137 +0,0 @@ -error: useless use of `vec!` - --> tests/ui/vec.rs:30:14 - | -LL | on_slice(&vec![]); - | ^^^^^^^ help: you can use a slice directly: `&[]` - | - = note: `-D clippy::useless-vec` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:33:18 - | -LL | on_mut_slice(&mut vec![]); - | ^^^^^^^^^^^ help: you can use a slice directly: `&mut []` - -error: useless use of `vec!` - --> tests/ui/vec.rs:36:14 - | -LL | on_slice(&vec![1, 2]); - | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:39:18 - | -LL | on_mut_slice(&mut vec![1, 2]); - | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:42:14 - | -LL | on_slice(&vec![1, 2]); - | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:45:18 - | -LL | on_mut_slice(&mut vec![1, 2]); - | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:48:14 - | -LL | on_slice(&vec!(1, 2)); - | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:51:18 - | -LL | on_mut_slice(&mut vec![1, 2]); - | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:54:14 - | -LL | on_slice(&vec![1; 2]); - | ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:57:18 - | -LL | on_mut_slice(&mut vec![1; 2]); - | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1; 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:84:19 - | -LL | let _x: i32 = vec![1, 2, 3].iter().sum(); - | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:88:17 - | -LL | let mut x = vec![1, 2, 3]; - | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:95:22 - | -LL | let _x: &[i32] = &vec![1, 2, 3]; - | ^^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:98:14 - | -LL | for _ in vec![1, 2, 3] {} - | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:138:20 - | -LL | for _string in vec![repro!(true), repro!(null)] { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[repro!(true), repro!(null)]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:156:18 - | -LL | in_macro!(1, vec![1, 2], vec![1; 2]); - | ^^^^^^^^^^ help: you can use an array directly: `[1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:156:30 - | -LL | in_macro!(1, vec![1, 2], vec![1; 2]); - | ^^^^^^^^^^ help: you can use an array directly: `[1; 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:177:14 - | -LL | for a in vec![1, 2, 3] { - | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:182:14 - | -LL | for a in vec![String::new(), String::new()] { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:215:33 - | -LL | this_macro_doesnt_need_vec!(vec![1]); - | ^^^^^^^ help: you can use an array directly: `[1]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:242:14 - | -LL | for a in &(vec![1, 2]) {} - | ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:250:13 - | -LL | let v = &vec![]; - | ^^^^^^^ help: you can use a slice directly: `&[]` - -error: aborting due to 22 previous errors - diff --git a/triagebot.toml b/triagebot.toml index db951b95ef50..3bf62b6b3bba 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -63,7 +63,8 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB users_on_vacation = [ "matthiaskrgr", "Manishearth", - "blyxyas", + "Alexendoo", + "y21", ] [assign.owners] diff --git a/util/gh-pages/index_template.html b/util/gh-pages/index_template.html index e443baff0808..91a5c1263195 100644 --- a/util/gh-pages/index_template.html +++ b/util/gh-pages/index_template.html @@ -57,118 +57,114 @@ Otherwise, have a great day =^.^= {# #} {% for lint in lints %} diff --git a/util/gh-pages/style.css b/util/gh-pages/style.css index 18bb95cf67b6..242e2227ed94 100644 --- a/util/gh-pages/style.css +++ b/util/gh-pages/style.css @@ -113,29 +113,26 @@ label { background: var(--bg); border: 1px solid var(--theme-popup-border); box-shadow: 0 1px 1px rgba(0,0,0,.05); + display: block; } -div.panel-body { - padding: 15px; +#menu-filters { + padding: 15px 0; + display: flex; + flex-direction: column; } -div.panel-body::before, div.panel-body::after { - display: table; - content: " "; -} -div.panel-body::after { - clear: both; -} -div.panel-body button { + +#menu-filters button { background: var(--searchbar-bg); border-color: var(--theme-popup-border); color: var(--searchbar-fg); } -div.panel-body button:hover { +#menu-filters button:hover { box-shadow: 0 0 3px var(--searchbar-shadow-color); } -div.panel-body button.open { +#menu-filters button.open { filter: brightness(90%); } @@ -242,33 +239,10 @@ article:hover .panel-title-name .anchor { display: inline;} min-height: 1px; padding-right: 15px; padding-left: 15px; -} - -.input-group { - position: relative; display: flex; } -.input-group > :last-child { - border-left: 0; -} -.input-group > :first-child, .btn-group > :first-child { - border-right: 0; - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} -.input-group > :last-child, .btn-group > :last-child { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} -.input-group .form-control:not(:first-child):not(:last-child) { - border-radius: 0; -} -.form-control:focus { - border-color: #66afe9; - outline: 0; - box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6); -} -.input-group-addon { + +#filter-label { padding: 6px 12px; font-size: 14px; font-weight: 400; @@ -280,6 +254,29 @@ article:hover .panel-title-name .anchor { display: inline;} display: flex; align-items: center; justify-content: center; + border-right: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.search-control > :last-child { + border-left: 0; +} +.btn-group > :first-child { + border-right: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.search-control > :last-child, .btn-group > :last-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.search-control .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} +.form-control:focus { + border-color: #66afe9; + outline: 0; + box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6); } .glyphicon.glyphicon-collapse-up::before, .glyphicon.glyphicon-collapse-down::before { @@ -343,6 +340,7 @@ article:hover .panel-title-name .anchor { display: inline;} @media (min-width: 992px) { .search-control { margin-top: 0; + align-self: flex-start; } .container { width: 970px; @@ -357,6 +355,10 @@ article:hover .panel-title-name .anchor { display: inline;} margin-top: 0; padding: 0px 15px; width: 16.66666667%; + align-self: flex-start; + } + #menu-filters { + flex-direction: row; } } @@ -376,7 +378,7 @@ article:hover .panel-title-name .anchor { display: inline;} @media (max-width: 412px) { #upper-filters, - .panel-body .search-control { + #menu-filters .search-control { padding-right: 8px; padding-left: 8px; } @@ -617,6 +619,7 @@ L4.75,12h2.5l0.5393066-2.1572876 c0.2276001-0.1062012,0.4459839-0.2269287,0.649 color: var(--fg); background: var(--theme-hover); border: 1px solid var(--theme-popup-border); + padding: 8px; } .page-header { border: 0; From 8f55c15bfe539a012f111bd00687241ad5a4a947 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 15 Oct 2025 09:55:38 +0000 Subject: [PATCH 120/585] Remove -Zoom=panic There are major questions remaining about the reentrancy that this allows. It doesn't have any users on github outside of a single project that uses it in a panic=abort project to show backtraces. It can still be emulated through #[alloc_error_handler] or set_alloc_error_hook depending on if you use the standard library or not. And finally it makes it harder to do various improvements to the allocator shim. --- .../rustc_codegen_cranelift/src/allocator.rs | 39 +--------------- compiler/rustc_codegen_gcc/src/allocator.rs | 39 +--------------- compiler/rustc_codegen_llvm/src/allocator.rs | 44 +------------------ .../src/back/symbol_export.rs | 3 +- compiler/rustc_interface/src/tests.rs | 9 ++-- compiler/rustc_session/src/config.rs | 26 +---------- compiler/rustc_session/src/options.rs | 12 ----- library/alloc/src/alloc.rs | 19 ++------ library/std/src/alloc.rs | 11 ----- src/tools/miri/src/shims/foreign_items.rs | 9 +--- .../tests/panic/alloc_error_handler_panic.rs | 18 -------- .../panic/alloc_error_handler_panic.stderr | 6 --- ...c-unwind.rs => alloc_error_hook-unwind.rs} | 8 ++-- 13 files changed, 22 insertions(+), 221 deletions(-) delete mode 100644 src/tools/miri/tests/panic/alloc_error_handler_panic.rs delete mode 100644 src/tools/miri/tests/panic/alloc_error_handler_panic.stderr rename tests/ui/panics/{oom-panic-unwind.rs => alloc_error_hook-unwind.rs} (84%) diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index 67b89114356b..4a9b0c0952ff 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -6,7 +6,6 @@ AllocatorMethod, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, default_fn_name, global_fn_name, }; use rustc_codegen_ssa::base::{allocator_kind_for_codegen, allocator_shim_contents}; -use rustc_session::config::OomStrategy; use rustc_symbol_mangling::mangle_internal_symbol; use crate::prelude::*; @@ -15,16 +14,11 @@ pub(crate) fn codegen(tcx: TyCtxt<'_>, module: &mut dyn Module) -> bool { let Some(kind) = allocator_kind_for_codegen(tcx) else { return false }; let methods = allocator_shim_contents(tcx, kind); - codegen_inner(tcx, module, &methods, tcx.sess.opts.unstable_opts.oom); + codegen_inner(tcx, module, &methods); true } -fn codegen_inner( - tcx: TyCtxt<'_>, - module: &mut dyn Module, - methods: &[AllocatorMethod], - oom_strategy: OomStrategy, -) { +fn codegen_inner(tcx: TyCtxt<'_>, module: &mut dyn Module, methods: &[AllocatorMethod]) { let usize_ty = module.target_config().pointer_type(); for method in methods { @@ -65,35 +59,6 @@ fn codegen_inner( ); } - { - let sig = Signature { - call_conv: module.target_config().default_call_conv, - params: vec![], - returns: vec![AbiParam::new(types::I8)], - }; - let func_id = module - .declare_function( - &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), - Linkage::Export, - &sig, - ) - .unwrap(); - let mut ctx = Context::new(); - ctx.func.signature = sig; - { - let mut func_ctx = FunctionBuilderContext::new(); - let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); - - let block = bcx.create_block(); - bcx.switch_to_block(block); - let value = bcx.ins().iconst(types::I8, oom_strategy.should_panic() as i64); - bcx.ins().return_(&[value]); - bcx.seal_all_blocks(); - bcx.finalize(); - } - module.define_function(func_id, &mut ctx).unwrap(); - } - { let sig = Signature { call_conv: module.target_config().default_call_conv, diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index 647569694b04..1f464d7e1226 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -1,12 +1,11 @@ #[cfg(feature = "master")] use gccjit::FnAttribute; -use gccjit::{Context, FunctionType, RValue, ToRValue, Type}; +use gccjit::{Context, FunctionType, ToRValue, Type}; use rustc_ast::expand::allocator::{ AllocatorMethod, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, default_fn_name, global_fn_name, }; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; -use rustc_session::config::OomStrategy; use rustc_symbol_mangling::mangle_internal_symbol; use crate::GccContext; @@ -59,14 +58,6 @@ pub(crate) unsafe fn codegen( create_wrapper_function(tcx, context, &from_name, Some(&to_name), &types, output); } - create_const_value_function( - tcx, - context, - &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), - i8, - context.new_rvalue_from_int(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as i32), - ); - create_wrapper_function( tcx, context, @@ -77,34 +68,6 @@ pub(crate) unsafe fn codegen( ); } -fn create_const_value_function( - tcx: TyCtxt<'_>, - context: &Context<'_>, - name: &str, - output: Type<'_>, - value: RValue<'_>, -) { - let func = context.new_function(None, FunctionType::Exported, output, &[], name, false); - - #[cfg(feature = "master")] - { - func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc( - tcx.sess.default_visibility(), - ))); - - // FIXME(antoyo): cg_llvm sets AlwaysInline, but AlwaysInline is different in GCC and using - // it here will causes linking errors when using LTO. - func.add_attribute(FnAttribute::Inline); - } - - if tcx.sess.must_emit_unwind_tables() { - // TODO(antoyo): emit unwind tables. - } - - let block = func.new_block("entry"); - block.end_with_return(None, value); -} - fn create_wrapper_function( tcx: TyCtxt<'_>, context: &Context<'_>, diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index de0b85ebb63b..24b2bd37aa46 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -7,13 +7,13 @@ use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{DebugInfo, OomStrategy}; +use rustc_session::config::DebugInfo; use rustc_symbol_mangling::mangle_internal_symbol; use crate::attributes::llfn_attrs_from_instance; use crate::builder::SBuilder; use crate::declare::declare_simple_fn; -use crate::llvm::{self, FALSE, FromGeneric, TRUE, Type, Value}; +use crate::llvm::{self, FromGeneric, TRUE, Type}; use crate::{SimpleCx, attributes, debuginfo}; pub(crate) unsafe fn codegen( @@ -28,7 +28,6 @@ pub(crate) unsafe fn codegen( 64 => cx.type_i64(), tws => bug!("Unsupported target word size for int: {}", tws), }; - let i8 = cx.type_i8(); let i8p = cx.type_ptr(); for method in methods { @@ -87,17 +86,6 @@ pub(crate) unsafe fn codegen( ); } - // __rust_alloc_error_handler_should_panic_v2 - create_const_value_function( - tcx, - &cx, - &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), - &i8, - unsafe { - llvm::LLVMConstInt(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as u64, FALSE) - }, - ); - // __rust_no_alloc_shim_is_unstable_v2 create_wrapper_function( tcx, @@ -117,34 +105,6 @@ pub(crate) unsafe fn codegen( } } -fn create_const_value_function( - tcx: TyCtxt<'_>, - cx: &SimpleCx<'_>, - name: &str, - output: &Type, - value: &Value, -) { - let ty = cx.type_func(&[], output); - let llfn = declare_simple_fn( - &cx, - name, - llvm::CallConv::CCallConv, - llvm::UnnamedAddr::Global, - llvm::Visibility::from_generic(tcx.sess.default_visibility()), - ty, - ); - - attributes::apply_to_llfn( - llfn, - llvm::AttributePlace::Function, - &[llvm::AttributeKind::AlwaysInline.create_attr(cx.llcx)], - ); - - let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) }; - let mut bx = SBuilder::build(&cx, llbb); - bx.ret(value); -} - fn create_wrapper_function( tcx: TyCtxt<'_>, cx: &SimpleCx<'_>, diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index a80976fad02a..9d06de2b35c2 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -15,7 +15,7 @@ use rustc_middle::query::LocalCrate; use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolName, Ty, TyCtxt}; use rustc_middle::util::Providers; -use rustc_session::config::{CrateType, OomStrategy}; +use rustc_session::config::CrateType; use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::{Arch, Os, TlsModel}; use tracing::debug; @@ -493,7 +493,6 @@ pub(crate) fn allocator_shim_symbols( .map(move |method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str())) .chain([ mangle_internal_symbol(tcx, global_fn_name(ALLOC_ERROR_HANDLER).as_str()), - mangle_internal_symbol(tcx, OomStrategy::SYMBOL), mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), ]) .map(move |symbol_name| { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 8bf9f8420c05..24de3620ca3c 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -14,10 +14,10 @@ CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, - NextSolverConfig, Offload, OomStrategy, Options, OutFileName, OutputType, OutputTypes, - PAuthKey, PacRet, Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, - SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, build_configuration, - build_session_options, rustc_optgroups, + NextSolverConfig, Offload, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, + Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, + SymbolManglingVersion, WasiExecModel, build_configuration, build_session_options, + rustc_optgroups, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -839,7 +839,6 @@ macro_rules! tracked { tracked!(no_unique_section_names, true); tracked!(offload, vec![Offload::Enable]); tracked!(on_broken_pipe, OnBrokenPipe::Kill); - tracked!(oom, OomStrategy::Panic); tracked!(osx_rpath_install_name, true); tracked!(packed_bundled_libs, true); tracked!(panic_abort_tests, true); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f97a29e064b6..c5f253a00e32 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3127,8 +3127,8 @@ pub(crate) mod dep_tracking { AnnotateMoves, AutoDiff, BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions, CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, - LocationDetail, LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OomStrategy, - OptLevel, OutFileName, OutputType, OutputTypes, PatchableFunctionEntry, Polonius, + LocationDetail, LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OptLevel, + OutFileName, OutputType, OutputTypes, PatchableFunctionEntry, Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, }; @@ -3227,7 +3227,6 @@ fn hash( LocationDetail, FmtDebug, BranchProtection, - OomStrategy, LanguageIdentifier, NextSolverConfig, PatchableFunctionEntry, @@ -3340,27 +3339,6 @@ pub(crate) fn stable_hash( } } -/// Default behavior to use in out-of-memory situations. -#[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)] -pub enum OomStrategy { - /// Generate a panic that can be caught by `catch_unwind`. - Panic, - - /// Abort the process immediately. - Abort, -} - -impl OomStrategy { - pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic_v2"; - - pub fn should_panic(self) -> u8 { - match self { - OomStrategy::Panic => 1, - OomStrategy::Abort => 0, - } - } -} - /// How to run proc-macro code when building this crate #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum ProcMacroExecutionStrategy { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 7c7e9118d590..f30612fa77b5 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -806,7 +806,6 @@ mod desc { pub(crate) const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`"; pub(crate) const parse_patchable_function_entry: &str = "either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops)"; pub(crate) const parse_opt_panic_strategy: &str = parse_panic_strategy; - pub(crate) const parse_oom_strategy: &str = "either `panic` or `abort`"; pub(crate) const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; pub(crate) const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`, or 'realtime'"; pub(crate) const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; @@ -1242,15 +1241,6 @@ pub(crate) fn parse_patchable_function_entry( false } - pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool { - match v { - Some("panic") => *slot = OomStrategy::Panic, - Some("abort") => *slot = OomStrategy::Abort, - _ => return false, - } - true - } - pub(crate) fn parse_relro_level(slot: &mut Option, v: Option<&str>) -> bool { match v { Some(s) => match s.parse::() { @@ -2529,8 +2519,6 @@ pub(crate) fn parse_align(slot: &mut Option, v: Option<&str>) -> bool { Currently the only option available"), on_broken_pipe: OnBrokenPipe = (OnBrokenPipe::Default, parse_on_broken_pipe, [TRACKED], "behavior of std::io::ErrorKind::BrokenPipe (SIGPIPE)"), - oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED], - "panic strategy for out-of-memory handling"), osx_rpath_install_name: bool = (false, parse_bool, [TRACKED], "pass `-install_name @rpath/...` to the macOS linker (default: no)"), packed_bundled_libs: bool = (false, parse_bool, [TRACKED], diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 39450f69ce30..c5f16f3708d7 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -426,20 +426,9 @@ pub mod __alloc_error_handler { // `#[alloc_error_handler]`. #[rustc_std_internal_symbol] pub unsafe fn __rdl_alloc_error_handler(size: usize, _align: usize) -> ! { - unsafe extern "Rust" { - // This symbol is emitted by rustc next to __rust_alloc_error_handler. - // Its value depends on the -Zoom={panic,abort} compiler option. - #[rustc_std_internal_symbol] - fn __rust_alloc_error_handler_should_panic_v2() -> u8; - } - - if unsafe { __rust_alloc_error_handler_should_panic_v2() != 0 } { - panic!("memory allocation of {size} bytes failed") - } else { - core::panicking::panic_nounwind_fmt( - format_args!("memory allocation of {size} bytes failed"), - /* force_no_backtrace */ false, - ) - } + core::panicking::panic_nounwind_fmt( + format_args!("memory allocation of {size} bytes failed"), + /* force_no_backtrace */ false, + ) } } diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 701b3be6894d..35eb77315a22 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -350,17 +350,6 @@ fn default_alloc_error_hook(layout: Layout) { return; } - unsafe extern "Rust" { - // This symbol is emitted by rustc next to __rust_alloc_error_handler. - // Its value depends on the -Zoom={panic,abort} compiler option. - #[rustc_std_internal_symbol] - fn __rust_alloc_error_handler_should_panic_v2() -> u8; - } - - if unsafe { __rust_alloc_error_handler_should_panic_v2() != 0 } { - panic!("memory allocation of {} bytes failed", layout.size()); - } - // This is the default path taken on OOM, and the only path taken on stable with std. // Crucially, it does *not* call any user-defined code, and therefore users do not have to // worry about allocation failure causing reentrancy issues. That makes it different from diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 440388673e7d..8a959d06bf9c 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -12,7 +12,6 @@ use rustc_middle::mir::interpret::AllocInit; use rustc_middle::ty::{Instance, Ty}; use rustc_middle::{mir, ty}; -use rustc_session::config::OomStrategy; use rustc_span::Symbol; use rustc_target::callconv::FnAbi; use rustc_target::spec::{Arch, Os}; @@ -305,18 +304,12 @@ fn emulate_foreign_item_inner( // Here we dispatch all the shims for foreign functions. If you have a platform specific // shim, add it to the corresponding submodule. match link_name.as_str() { - // Magic functions Rust emits (and not as part of the allocator shim). + // Magic function Rust emits (and not as part of the allocator shim). name if name == this.mangle_internal_symbol(NO_ALLOC_SHIM_IS_UNSTABLE) => { // This is a no-op shim that only exists to prevent making the allocator shims // instantly stable. let [] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; } - name if name == this.mangle_internal_symbol(OomStrategy::SYMBOL) => { - // Gets the value of the `oom` option. - let [] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; - let val = this.tcx.sess.opts.unstable_opts.oom.should_panic(); - this.write_int(val, dest)?; - } // Miri-specific extern functions "miri_alloc" => { diff --git a/src/tools/miri/tests/panic/alloc_error_handler_panic.rs b/src/tools/miri/tests/panic/alloc_error_handler_panic.rs deleted file mode 100644 index c434e8d3227a..000000000000 --- a/src/tools/miri/tests/panic/alloc_error_handler_panic.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@compile-flags: -Zoom=panic -#![feature(allocator_api)] - -use std::alloc::*; - -struct Bomb; -impl Drop for Bomb { - fn drop(&mut self) { - eprintln!("yes we are unwinding!"); - } -} - -#[allow(unreachable_code, unused_variables)] -fn main() { - let bomb = Bomb; - handle_alloc_error(Layout::for_value(&0)); - std::mem::forget(bomb); // defuse unwinding bomb -} diff --git a/src/tools/miri/tests/panic/alloc_error_handler_panic.stderr b/src/tools/miri/tests/panic/alloc_error_handler_panic.stderr deleted file mode 100644 index 7c2d089f952e..000000000000 --- a/src/tools/miri/tests/panic/alloc_error_handler_panic.stderr +++ /dev/null @@ -1,6 +0,0 @@ - -thread 'main' ($TID) panicked at RUSTLIB/std/src/alloc.rs:LL:CC: -memory allocation of 4 bytes failed -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect -yes we are unwinding! diff --git a/tests/ui/panics/oom-panic-unwind.rs b/tests/ui/panics/alloc_error_hook-unwind.rs similarity index 84% rename from tests/ui/panics/oom-panic-unwind.rs rename to tests/ui/panics/alloc_error_hook-unwind.rs index 4f7939ce60b2..8a107bc390d4 100644 --- a/tests/ui/panics/oom-panic-unwind.rs +++ b/tests/ui/panics/alloc_error_hook-unwind.rs @@ -1,17 +1,19 @@ -//! Test that out-of-memory conditions trigger catchable panics with `-Z oom=panic`. +//! Test that out-of-memory conditions trigger catchable panics with `set_alloc_error_hook`. -//@ compile-flags: -Z oom=panic //@ run-pass -//@ no-prefer-dynamic //@ needs-unwind //@ only-linux //@ ignore-backends: gcc +#![feature(alloc_error_hook)] + use std::hint::black_box; use std::mem::forget; use std::panic::catch_unwind; fn main() { + std::alloc::set_alloc_error_hook(|_| panic!()); + let panic = catch_unwind(|| { // This is guaranteed to exceed even the size of the address space for _ in 0..16 { From 3f67246af50fe6f67d5c56b02efaeb01a0d48f0e Mon Sep 17 00:00:00 2001 From: Skgland Date: Fri, 28 Nov 2025 20:47:03 +0100 Subject: [PATCH 121/585] fix tests/run-make/track-path-dep-info attempt 2 --- tests/run-make/track-path-dep-info/macro_def.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-make/track-path-dep-info/macro_def.rs b/tests/run-make/track-path-dep-info/macro_def.rs index 032594d905d0..b7271cac2344 100644 --- a/tests/run-make/track-path-dep-info/macro_def.rs +++ b/tests/run-make/track-path-dep-info/macro_def.rs @@ -1,4 +1,4 @@ -#![feature(proc_macro_track_path)] +#![feature(proc_macro_tracked_path)] #![crate_type = "proc-macro"] extern crate proc_macro; From 5d8e7ae8057f8278784420f3925ebe4e99b79a2e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 28 Nov 2025 11:47:54 -0800 Subject: [PATCH 122/585] Fix some broken links `P` was removed in https://github.com/rust-lang/rust/pull/145146 (replaced with plain Box). `CrateLoader` was inlined to `CStore` in https://github.com/rust-lang/rust/pull/144059. `elaborate_drops.rs` was moved in https://github.com/rust-lang/rust/pull/137008. --- src/doc/rustc-dev-guide/src/appendix/bibliography.md | 2 +- src/doc/rustc-dev-guide/src/appendix/code-index.md | 1 - src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md | 7 +++---- src/doc/rustc-dev-guide/src/contributing.md | 4 ++-- .../rustc-dev-guide/src/llvm-coverage-instrumentation.md | 4 ++-- src/doc/rustc-dev-guide/src/mir/drop-elaboration.md | 2 +- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/appendix/bibliography.md b/src/doc/rustc-dev-guide/src/appendix/bibliography.md index 93426b645a61..3729194f5fa1 100644 --- a/src/doc/rustc-dev-guide/src/appendix/bibliography.md +++ b/src/doc/rustc-dev-guide/src/appendix/bibliography.md @@ -32,7 +32,7 @@ Rust, as well as publications about Rust. * [Scheduling techniques for concurrent systems](https://www.stanford.edu/~ouster/cgi-bin/papers/coscheduling.pdf) * [Singularity: rethinking the software stack](https://research.microsoft.com/pubs/69431/osr2007_rethinkingsoftwarestack.pdf) * [The data locality of work stealing](http://www.aladdin.cs.cmu.edu/papers/pdfs/y2000/locality_spaa00.pdf) -* [Thread scheduling for multiprogramming multiprocessors](https://www.eecis.udel.edu/%7Ecavazos/cisc879-spring2008/papers/arora98thread.pdf) +* [Thread scheduling for multiprogramming multiprocessors](https://dl.acm.org/doi/10.1145/277651.277678) * [Three layer cake for shared-memory programming](https://dl.acm.org/doi/10.1145/1953611.1953616) * [Work-first and help-first scheduling policies for async-finish task parallelism](https://dl.acm.org/doi/10.1109/IPDPS.2009.5161079) - More general than fully-strict work stealing diff --git a/src/doc/rustc-dev-guide/src/appendix/code-index.md b/src/doc/rustc-dev-guide/src/appendix/code-index.md index 0795d83b2e9a..22b3396ed1ff 100644 --- a/src/doc/rustc-dev-guide/src/appendix/code-index.md +++ b/src/doc/rustc-dev-guide/src/appendix/code-index.md @@ -16,7 +16,6 @@ Item | Kind | Short description | Chapter | `HirId` | struct | One of four types of HIR node identifiers | [Identifiers in the HIR] | [compiler/rustc_hir_id/src/lib.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.HirId.html) `Lexer` | struct | This is the lexer used during parsing. It consumes characters from the raw source code being compiled and produces a series of tokens for use by the rest of the parser | [The parser] | [compiler/rustc_parse/src/lexer/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/lexer/struct.Lexer.html) `NodeId` | struct | One of four types of HIR node identifiers. Being phased out | [Identifiers in the HIR] | [compiler/rustc_ast/src/ast.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/node_id/struct.NodeId.html) -`P` | struct | An owned immutable smart pointer. By contrast, `&T` is not owned, and `Box` is not immutable. | None | [compiler/rustc_ast/src/ptr.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ptr/struct.P.html) `ParamEnv` | struct | Information about generic parameters or `Self`, useful for working with associated or generic items | [Parameter Environment] | [compiler/rustc_middle/src/ty/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html) `ParseSess` | struct | This struct contains information about a parsing session | [The parser] | [compiler/rustc_session/src/parse/parse.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/struct.ParseSess.html) `Rib` | struct | Represents a single scope of names | [Name resolution] | [compiler/rustc_resolve/src/lib.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/struct.Rib.html) diff --git a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md index aa1d644703a0..44b647d28a1e 100644 --- a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md +++ b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md @@ -133,12 +133,12 @@ crate name, so they need to be disambiguated). Crate loading can have quite a few subtle complexities. During [name resolution], when an external crate is referenced (via an `extern crate` or -path), the resolver uses the [`CrateLoader`] which is responsible for finding +path), the resolver uses the [`CStore`] which is responsible for finding the crate libraries and loading the [metadata] for them. After the dependency -is loaded, the `CrateLoader` will provide the information the resolver needs +is loaded, the `CStore` will provide the information the resolver needs to perform its job (such as expanding macros, resolving paths, etc.). -To load each external crate, the `CrateLoader` uses a [`CrateLocator`] to +To load each external crate, the `CStore` uses a [`CrateLocator`] to actually find the correct files for one specific crate. There is some great documentation in the [`locator`] module that goes into detail on how loading works, and I strongly suggest reading it to get the full picture. @@ -157,7 +157,6 @@ wrapped in the [`CrateMetadata`] struct. After resolution and expansion, the compilation. [name resolution]: ../name-resolution.md -[`CrateLoader`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/creader/struct.CrateLoader.html [`CrateLocator`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/locator/struct.CrateLocator.html [`locator`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/locator/index.html [`CStore`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/creader/struct.CStore.html diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 4476ed842dae..40ad58e025c1 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -468,7 +468,7 @@ Just a few things to keep in mind: #### ⚠️ Note: Where to contribute `rustc-dev-guide` changes For detailed information about where to contribute rustc-dev-guide changes and the benefits of doing so, -see [the rustc-dev-guide working group documentation]. +see [the rustc-dev-guide team documentation]. ## Issue triage @@ -485,7 +485,7 @@ Please see . [regression-]: https://github.com/rust-lang/rust/labels?q=regression [relnotes]: https://github.com/rust-lang/rust/labels/relnotes [S-tracking-]: https://github.com/rust-lang/rust/labels?q=s-tracking -[the rustc-dev-guide working group documentation]: https://forge.rust-lang.org/wg-rustc-dev-guide/index.html#where-to-contribute-rustc-dev-guide-changes +[the rustc-dev-guide team documentation]: https://forge.rust-lang.org/rustc-dev-guide/index.html#where-to-contribute-rustc-dev-guide-changes ### rfcbot labels diff --git a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md index 30a1c5ebc7ef..d71e51d5f61b 100644 --- a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md +++ b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md @@ -84,11 +84,11 @@ Note that when building `rustc`, `profiler_builtins` is only included when `build.profiler = true` is set in `bootstrap.toml`. When compiling with `-C instrument-coverage`, -[`CrateLoader::postprocess()`][crate-loader-postprocess] dynamically loads +[`CStore::postprocess()`][crate-loader-postprocess] dynamically loads `profiler_builtins` by calling `inject_profiler_runtime()`. [compiler-rt-profile]: https://github.com/llvm/llvm-project/tree/main/compiler-rt/lib/profile -[crate-loader-postprocess]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/creader/struct.CrateLoader.html#method.postprocess +[crate-loader-postprocess]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/creader/struct.CStore.html#method.postprocess ## Testing coverage instrumentation diff --git a/src/doc/rustc-dev-guide/src/mir/drop-elaboration.md b/src/doc/rustc-dev-guide/src/mir/drop-elaboration.md index 93e21e2b227f..7ef60f4cca00 100644 --- a/src/doc/rustc-dev-guide/src/mir/drop-elaboration.md +++ b/src/doc/rustc-dev-guide/src/mir/drop-elaboration.md @@ -188,6 +188,6 @@ known to be uninitialized) to run these checks. [RFC 320]: https://rust-lang.github.io/rfcs/0320-nonzeroing-dynamic-drop.html [reference-drop]: https://doc.rust-lang.org/reference/destructors.html -[drops]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +[drops]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_mir_transform/src/elaborate_drops.rs [drops-shim]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_mir_transform/src/shim.rs [drops-transform]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_mir_transform/src/elaborate_drops.rs From b87bfdc9fc10b372c3f13be4e8b8b14cb499e1de Mon Sep 17 00:00:00 2001 From: Harin Date: Sat, 29 Nov 2025 01:28:07 +0530 Subject: [PATCH 123/585] Better document some combinations of flags (#808) --------- Co-authored-by: FrancescoV1985 Co-authored-by: FrancescoV1985 <62872737+FrancescoV1985@users.noreply.github.com> Co-authored-by: antoyo --- CONTRIBUTING.md | 37 +++++++++++++++++++++++++++++++++++++ build_system/src/build.rs | 12 ++++++++++-- build_system/src/config.rs | 7 ++----- build_system/src/test.rs | 6 ------ 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 54cba0e6de37..8f81ecca445a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,6 +25,43 @@ We encourage new contributors to join our communication channels and introduce t ## Understanding Core Concepts +### Sysroot & compilation flags + +#### What *is* the sysroot? +The **sysroot** is the directory that stores the compiled standard +library (`core`, `alloc`, `std`, `test`, …) and compiler built-ins. +Rustup ships these libraries **pre-compiled with LLVM**. + +**rustc_codegen_gcc** replaces LLVM with the GCC backend. + +The freshly compiled sysroot ends up in +`build/build_sysroot/...`. + +A rebuild of sysroot is needed when + +* the backend changes in a way that affects code generation, or +* the user switches toolchains / updates submodules. + +Both backend and sysroot can be built using different [profiles](https://doc.rust-lang.org/cargo/reference/profiles.html#default-profiles). +That is exactly what the `--sysroot`, `--release-sysroot` and `--release` flag supported by the build system script `y.sh` take care of. + + +#### Typical flag combinations + +| Command | Backend Profile | Sysroot Profile | Usage Scenario | +|--------------------------------------------|-------------------------------|----------------------------------|------------------------------------------------------------| +| `./y.sh build` |  dev* |  n/a |  Build backend in dev mode with optimized dependencies without rebuilding sysroot | +| `./y.sh build --release` |  release (optimized) |  n/a |  Build backend in release mode with optimized dependencies without rebuilding sysroot | +| `./y.sh build --release --sysroot` |  release (optimized) |  dev |  Build backend in release mode with optimized dependencies and sysroot in dev mode (unoptimized) | +| `./y.sh build --sysroot` |  dev* |  dev |  Build backend in dev mode with optimized dependencies and sysroot in dev mode (unoptimized) | +| `./y.sh build --release-sysroot --sysroot`|  dev* |  release (optimized) |  Build backend in dev mode and sysroot in release mode, both with optimized dependencies | + +\* In `dev` mode, dependencies are compiled with optimizations, while the code of the backend itself is not. + + +Note: `--release-sysroot` must be used together with `--sysroot`. + + ### Common Development Tasks #### Running Specific Tests diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 56503b239a3b..27476465d740 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -46,8 +46,16 @@ fn usage() { println!( r#" `build` command help: - - --sysroot : Build with sysroot"# + --sysroot : When used on its own, build backend in dev mode with optimized dependencies + and sysroot in dev mode (unoptimized) + When used together with --release, build backend in release mode with optimized dependencies + When used together with --release-sysroot, + build the sysroot in release mode with optimized dependencies instead of in dev mode + --release-sysroot : When combined with --sysroot, additionally + build the sysroot in release mode with optimized dependencies. + It has no effect if `--sysroot` is not specified. + It should not be used on its own. + --sysroot-panic-abort : Build the sysroot without unwinding support"# ); ConfigInfo::show_usage(); println!(" --help : Show this help"); diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 19255e1ba2b2..8eb6d8f019e1 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -459,14 +459,11 @@ pub fn setup( pub fn show_usage() { println!( - "\ - --features [arg] : Add a new feature [arg] + " --features [arg] : Add a new feature [arg] --target-triple [arg] : Set the target triple to [arg] --target [arg] : Set the target to [arg] + --release : Build backend in release mode with optimized dependencies --out-dir : Location where the files will be generated - --release : Build in release mode - --release-sysroot : Build sysroot in release mode - --sysroot-panic-abort : Build the sysroot without unwinding support --config-file : Location of the config file to be used --gcc-path : Location of the GCC root folder --cg_gcc-path : Location of the rustc_codegen_gcc root folder (used diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 8aabfa894ce0..ca2a2a7dc2de 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -64,8 +64,6 @@ fn show_usage() { r#" `test` command help: - --release : Build codegen in release mode - --sysroot-panic-abort : Build the sysroot without unwinding support. --features [arg] : Add a new feature [arg] --use-system-gcc : Use system installed libgccjit --build-only : Only build rustc_codegen_gcc then exits @@ -92,7 +90,6 @@ struct TestArg { test_args: Vec, nb_parts: Option, current_part: Option, - sysroot_panic_abort: bool, config_info: ConfigInfo, sysroot_features: Vec, keep_lto_tests: bool, @@ -128,9 +125,6 @@ fn new() -> Result, String> { test_arg.current_part = Some(get_number_after_arg(&mut args, "--current-part")?); } - "--sysroot-panic-abort" => { - test_arg.sysroot_panic_abort = true; - } "--keep-lto-tests" => { test_arg.keep_lto_tests = true; } From 673be1b82a4169ffae9cf4b0bd4ab7435e842a1f Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 28 Nov 2025 14:49:42 -0800 Subject: [PATCH 124/585] Use a delayed bug for this layout ICE Fixes 144501 --- compiler/rustc_errors/src/lib.rs | 2 +- .../rustc_ty_utils/src/layout/invariant.rs | 14 ++++-- .../invalid-niche-discriminant.normal.stderr | 35 ++++++++++++++ .../invalid-niche-discriminant.rs | 25 ++++++++++ ...lid-niche-discriminant.with_delayed.stderr | 47 +++++++++++++++++++ 5 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 tests/ui/enum-discriminant/invalid-niche-discriminant.normal.stderr create mode 100644 tests/ui/enum-discriminant/invalid-niche-discriminant.rs create mode 100644 tests/ui/enum-discriminant/invalid-niche-discriminant.with_delayed.stderr diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index bbdda155496f..41679e3a68e5 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1366,7 +1366,7 @@ pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed { self.create_err(err).emit() } - /// Ensures that an error is printed. See `Level::DelayedBug`. + /// Ensures that an error is printed. See [`Level::DelayedBug`]. // // No `#[rustc_lint_diagnostics]` and no `impl Into` because bug messages aren't // user-facing. diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index d1484aed1671..01435f7e67a4 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -281,10 +281,16 @@ fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) { } // Ensure that for niche encoded tags the discriminant coincides with the variant index. - assert_eq!( - layout.ty.discriminant_for_variant(tcx, idx).unwrap().val, - u128::from(idx.as_u32()), - ); + let val = layout.ty.discriminant_for_variant(tcx, idx).unwrap().val; + if val != u128::from(idx.as_u32()) { + let adt_def = layout.ty.ty_adt_def().unwrap(); + cx.tcx().dcx().span_delayed_bug( + cx.tcx().def_span(adt_def.did()), + format!( + "variant {idx:?} has discriminant {val:?} in niche-encoded type" + ), + ); + } } } for variant in variants.iter() { diff --git a/tests/ui/enum-discriminant/invalid-niche-discriminant.normal.stderr b/tests/ui/enum-discriminant/invalid-niche-discriminant.normal.stderr new file mode 100644 index 000000000000..9c66c1782e4d --- /dev/null +++ b/tests/ui/enum-discriminant/invalid-niche-discriminant.normal.stderr @@ -0,0 +1,35 @@ +error[E0732]: `#[repr(inttype)]` must be specified for enums with explicit discriminants and non-unit variants + --> $DIR/invalid-niche-discriminant.rs:11:1 + | +LL | enum E { + | ^^^^^^ +... +LL | S0 { + | -- non-unit discriminant declared here +... +LL | Bar = { + | ___________- +LL | | let x = 1; +LL | | 3 +LL | | }, + | |_____- explicit discriminant specified here + +error[E0599]: no variant named `S1` found for enum `E` + --> $DIR/invalid-niche-discriminant.rs:23:18 + | +LL | enum E { + | ------ variant `S1` not found here +... +LL | static C: E = E::S1 { u: 23 }; + | ^^ + | +help: there is a variant with a similar name + | +LL - static C: E = E::S1 { u: 23 }; +LL + static C: E = E::S0 { u: 23 }; + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0599, E0732. +For more information about an error, try `rustc --explain E0599`. diff --git a/tests/ui/enum-discriminant/invalid-niche-discriminant.rs b/tests/ui/enum-discriminant/invalid-niche-discriminant.rs new file mode 100644 index 000000000000..f70f7d1736ba --- /dev/null +++ b/tests/ui/enum-discriminant/invalid-niche-discriminant.rs @@ -0,0 +1,25 @@ +//@ needs-rustc-debug-assertions +//@ revisions: normal with_delayed +//@ [with_delayed] compile-flags: -Z eagerly-emit-delayed-bugs + +#![crate_type = "lib"] + +// Repro for +// which ICEd because the calculated layout is invalid +// but which we needn't care about as the discriminant already was. + +enum E { +//~^ ERROR must be specified +//[with_delayed]~| ERROR variant 1 has discriminant 3 + S0 { + s: String, + }, + Bar = { + let x = 1; + 3 + }, +} + +static C: E = E::S1 { u: 23 }; +//~^ ERROR no variant named +//[with_delayed]~| ERROR but no error emitted diff --git a/tests/ui/enum-discriminant/invalid-niche-discriminant.with_delayed.stderr b/tests/ui/enum-discriminant/invalid-niche-discriminant.with_delayed.stderr new file mode 100644 index 000000000000..20f118655a17 --- /dev/null +++ b/tests/ui/enum-discriminant/invalid-niche-discriminant.with_delayed.stderr @@ -0,0 +1,47 @@ +error[E0732]: `#[repr(inttype)]` must be specified for enums with explicit discriminants and non-unit variants + --> $DIR/invalid-niche-discriminant.rs:11:1 + | +LL | enum E { + | ^^^^^^ +... +LL | S0 { + | -- non-unit discriminant declared here +... +LL | Bar = { + | ___________- +LL | | let x = 1; +LL | | 3 +LL | | }, + | |_____- explicit discriminant specified here + +error: variant 1 has discriminant 3 in niche-encoded type + --> $DIR/invalid-niche-discriminant.rs:11:1 + | +LL | enum E { + | ^^^^^^ + +error[E0599]: no variant named `S1` found for enum `E` + --> $DIR/invalid-niche-discriminant.rs:23:18 + | +LL | enum E { + | ------ variant `S1` not found here +... +LL | static C: E = E::S1 { u: 23 }; + | ^^ + | +help: there is a variant with a similar name + | +LL - static C: E = E::S1 { u: 23 }; +LL + static C: E = E::S0 { u: 23 }; + | + +error: `Res::Err` but no error emitted + --> $DIR/invalid-niche-discriminant.rs:23:15 + | +LL | static C: E = E::S1 { u: 23 }; + | ^^^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0599, E0732. +For more information about an error, try `rustc --explain E0599`. From 05b8b5ae92f32e551b8fe189140cc0a9d43c2455 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 29 Nov 2025 02:05:46 +0200 Subject: [PATCH 125/585] sembr backend/libs-and-metadata.md --- .../src/backend/libs-and-metadata.md | 146 +++++++++--------- 1 file changed, 77 insertions(+), 69 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md index 44b647d28a1e..4cf0dfa6a6da 100644 --- a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md +++ b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md @@ -1,36 +1,41 @@ # Libraries and metadata When the compiler sees a reference to an external crate, it needs to load some -information about that crate. This chapter gives an overview of that process, +information about that crate. +This chapter gives an overview of that process, and the supported file formats for crate libraries. ## Libraries -A crate dependency can be loaded from an `rlib`, `dylib`, or `rmeta` file. A -key point of these file formats is that they contain `rustc`-specific -[*metadata*](#metadata). This metadata allows the compiler to discover enough +A crate dependency can be loaded from an `rlib`, `dylib`, or `rmeta` file. +A key point of these file formats is that they contain `rustc`-specific +[*metadata*](#metadata). +This metadata allows the compiler to discover enough information about the external crate to understand the items it contains, which macros it exports, and *much* more. ### rlib -An `rlib` is an [archive file], which is similar to a tar file. This file -format is specific to `rustc`, and may change over time. This file contains: +An `rlib` is an [archive file], which is similar to a tar file. +This file format is specific to `rustc`, and may change over time. +This file contains: -* Object code, which is the result of code generation. This is used during - regular linking. There is a separate `.o` file for each [codegen unit]. The - codegen step can be skipped with the [`-C +* Object code, which is the result of code generation. + This is used during regular linking. + There is a separate `.o` file for each [codegen unit]. + The codegen step can be skipped with the [`-C linker-plugin-lto`][linker-plugin-lto] CLI option, which means each `.o` file will only contain LLVM bitcode. * [LLVM bitcode], which is a binary representation of LLVM's intermediate - representation, which is embedded as a section in the `.o` files. This can - be used for [Link Time Optimization] (LTO). This can be removed with the + representation, which is embedded as a section in the `.o` files. + This can be used for [Link Time Optimization] (LTO). + This can be removed with the [`-C embed-bitcode=no`][embed-bitcode] CLI option to improve compile times and reduce disk space if LTO is not needed. * `rustc` [metadata], in a file named `lib.rmeta`. * A symbol table, which is essentially a list of symbols with offsets to the - object files that contain that symbol. This is pretty standard for archive - files. + object files that contain that symbol. + This is pretty standard for archive files. [archive file]: https://en.wikipedia.org/wiki/Ar_(Unix) [LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html @@ -41,46 +46,46 @@ format is specific to `rustc`, and may change over time. This file contains: ### dylib -A `dylib` is a platform-specific shared library. It includes the `rustc` -[metadata] in a special link section called `.rustc`. +A `dylib` is a platform-specific shared library. +It includes the `rustc` [metadata] in a special link section called `.rustc`. ### rmeta -An `rmeta` file is a custom binary format that contains the [metadata] for the -crate. This file can be used for fast "checks" of a project by skipping all code +An `rmeta` file is a custom binary format that contains the [metadata] for the crate. +This file can be used for fast "checks" of a project by skipping all code generation (as is done with `cargo check`), collecting enough information for documentation (as is done with `cargo doc`), or for [pipelining](#pipelining). This file is created if the [`--emit=metadata`][emit] CLI option is used. -`rmeta` files do not support linking, since they do not contain compiled -object files. +`rmeta` files do not support linking, since they do not contain compiled object files. [emit]: https://doc.rust-lang.org/rustc/command-line-arguments.html#option-emit ## Metadata -The metadata contains a wide swath of different elements. This guide will not go -into detail about every field it contains. You are encouraged to browse the +The metadata contains a wide swath of different elements. +This guide will not go into detail about every field it contains. +You are encouraged to browse the [`CrateRoot`] definition to get a sense of the different elements it contains. -Everything about metadata encoding and decoding is in the [`rustc_metadata`] -package. +Everything about metadata encoding and decoding is in the [`rustc_metadata`] package. Here are a few highlights of things it contains: -* The version of the `rustc` compiler. The compiler will refuse to load files - from any other version. -* The [Strict Version Hash](#strict-version-hash) (SVH). This helps ensure the - correct dependency is loaded. -* The [Stable Crate Id](#stable-crate-id). This is a hash used - to identify crates. -* Information about all the source files in the library. This can be used for - a variety of things, such as diagnostics pointing to sources in a +* The version of the `rustc` compiler. + The compiler will refuse to load files from any other version. +* The [Strict Version Hash](#strict-version-hash) (SVH). + This helps ensure the correct dependency is loaded. +* The [Stable Crate Id](#stable-crate-id). + This is a hash used to identify crates. +* Information about all the source files in the library. + This can be used for a variety of things, such as diagnostics pointing to sources in a dependency. -* Information about exported macros, traits, types, and items. Generally, - anything that's needed to be known when a path references something inside a - crate dependency. -* Encoded [MIR]. This is optional, and only encoded if needed for code - generation. `cargo check` skips this for performance reasons. +* Information about exported macros, traits, types, and items. + Generally, + anything that's needed to be known when a path references something inside a crate dependency. +* Encoded [MIR]. + This is optional, and only encoded if needed for code generation. + `cargo check` skips this for performance reasons. [`CrateRoot`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/rmeta/struct.CrateRoot.html [`rustc_metadata`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/index.html @@ -89,10 +94,10 @@ Here are a few highlights of things it contains: ### Strict Version Hash The Strict Version Hash ([SVH], also known as the "crate hash") is a 64-bit -hash that is used to ensure that the correct crate dependencies are loaded. It -is possible for a directory to contain multiple copies of the same dependency -built with different settings, or built from different sources. The crate -loader will skip any crates that have the wrong SVH. +hash that is used to ensure that the correct crate dependencies are loaded. +It is possible for a directory to contain multiple copies of the same dependency +built with different settings, or built from different sources. +The crate loader will skip any crates that have the wrong SVH. The SVH is also used for the [incremental compilation] session filename, though that usage is mostly historic. @@ -114,14 +119,15 @@ See [`compute_hir_hash`] for where the hash is actually computed. ### Stable Crate Id The [`StableCrateId`] is a 64-bit hash used to identify different crates with -potentially the same name. It is a hash of the crate name and all the -[`-C metadata`] CLI options computed in [`StableCrateId::new`]. It is -used in a variety of places, such as symbol name mangling, crate loading, and +potentially the same name. +It is a hash of the crate name and all the +[`-C metadata`] CLI options computed in [`StableCrateId::new`]. +It is used in a variety of places, such as symbol name mangling, crate loading, and much more. By default, all Rust symbols are mangled and incorporate the stable crate id. -This allows multiple versions of the same crate to be included together. Cargo -automatically generates `-C metadata` hashes based on a variety of factors, like +This allows multiple versions of the same crate to be included together. +Cargo automatically generates `-C metadata` hashes based on a variety of factors, like the package version, source, and target kind (a lib and test can have the same crate name, so they need to be disambiguated). @@ -131,30 +137,31 @@ crate name, so they need to be disambiguated). ## Crate loading -Crate loading can have quite a few subtle complexities. During [name -resolution], when an external crate is referenced (via an `extern crate` or +Crate loading can have quite a few subtle complexities. +During [name resolution], when an external crate is referenced (via an `extern crate` or path), the resolver uses the [`CStore`] which is responsible for finding -the crate libraries and loading the [metadata] for them. After the dependency -is loaded, the `CStore` will provide the information the resolver needs +the crate libraries and loading the [metadata] for them. +After the dependency is loaded, the `CStore` will provide the information the resolver needs to perform its job (such as expanding macros, resolving paths, etc.). To load each external crate, the `CStore` uses a [`CrateLocator`] to -actually find the correct files for one specific crate. There is some great -documentation in the [`locator`] module that goes into detail on how loading +actually find the correct files for one specific crate. +There is some great documentation in the [`locator`] module that goes into detail on how loading works, and I strongly suggest reading it to get the full picture. -The location of a dependency can come from several different places. Direct -dependencies are usually passed with `--extern` flags, and the loader can look -at those directly. Direct dependencies often have references to their own -dependencies, which need to be loaded, too. These are usually found by +The location of a dependency can come from several different places. +Direct dependencies are usually passed with `--extern` flags, and the loader can look +at those directly. +Direct dependencies often have references to their own dependencies, which need to be loaded, too. +These are usually found by scanning the directories passed with the `-L` flag for any file whose metadata -contains a matching crate name and [SVH](#strict-version-hash). The loader -will also look at the [sysroot] to find dependencies. +contains a matching crate name and [SVH](#strict-version-hash). +The loader will also look at the [sysroot] to find dependencies. As crates are loaded, they are kept in the [`CStore`] with the crate metadata -wrapped in the [`CrateMetadata`] struct. After resolution and expansion, the -`CStore` will make its way into the [`GlobalCtxt`] for the rest of the -compilation. +wrapped in the [`CrateMetadata`] struct. +After resolution and expansion, the +`CStore` will make its way into the [`GlobalCtxt`] for the rest of the compilation. [name resolution]: ../name-resolution.md [`CrateLocator`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/locator/struct.CrateLocator.html @@ -167,20 +174,21 @@ compilation. ## Pipelining One trick to improve compile times is to start building a crate as soon as the -metadata for its dependencies is available. For a library, there is no need to -wait for the code generation of dependencies to finish. Cargo implements this -technique by telling `rustc` to emit an [`rmeta`](#rmeta) file for each -dependency as well as an [`rlib`](#rlib). As early as it can, `rustc` will -save the `rmeta` file to disk before it continues to the code generation -phase. The compiler sends a JSON message to let the build tool know that it +metadata for its dependencies is available. +For a library, there is no need to wait for the code generation of dependencies to finish. +Cargo implements this technique by telling `rustc` to emit an [`rmeta`](#rmeta) file for each +dependency as well as an [`rlib`](#rlib). +As early as it can, `rustc` will +save the `rmeta` file to disk before it continues to the code generation phase. +The compiler sends a JSON message to let the build tool know that it can start building the next crate if possible. The [crate loading](#crate-loading) system is smart enough to know when it -sees an `rmeta` file to use that if the `rlib` is not there (or has only been -partially written). +sees an `rmeta` file to use that if the `rlib` is not there (or has only been partially written). This pipelining isn't possible for binaries, because the linking phase will -require the code generation of all its dependencies. In the future, it may be +require the code generation of all its dependencies. +In the future, it may be possible to further improve this scenario by splitting linking into a separate command (see [#64191]). From 9e61149e8e40538b2de23db5979ad54d034403b0 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 29 Nov 2025 02:24:02 +0200 Subject: [PATCH 126/585] link text spanning separate lines is awkward --- src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md index 4cf0dfa6a6da..4a0b75c69431 100644 --- a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md +++ b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md @@ -23,9 +23,8 @@ This file contains: * Object code, which is the result of code generation. This is used during regular linking. There is a separate `.o` file for each [codegen unit]. - The codegen step can be skipped with the [`-C - linker-plugin-lto`][linker-plugin-lto] CLI option, which means each `.o` - file will only contain LLVM bitcode. + The codegen step can be skipped with the [`-C linker-plugin-lto`][linker-plugin-lto] CLI option, + which means each `.o` file will only contain LLVM bitcode. * [LLVM bitcode], which is a binary representation of LLVM's intermediate representation, which is embedded as a section in the `.o` files. This can be used for [Link Time Optimization] (LTO). From 4046385d609f73d32069ec0680a92b6d04d96761 Mon Sep 17 00:00:00 2001 From: EFanZh Date: Sat, 29 Nov 2025 09:52:19 +0800 Subject: [PATCH 127/585] Add `ilog10` result range hints --- library/core/src/num/int_log10.rs | 111 +++++---- library/core/src/num/int_macros.rs | 6 +- library/core/src/num/nonzero.rs | 2 +- .../lib-optimizations/ilog10-range.rs | 213 ++++++++++++++++++ 4 files changed, 282 insertions(+), 50 deletions(-) create mode 100644 tests/codegen-llvm/lib-optimizations/ilog10-range.rs diff --git a/library/core/src/num/int_log10.rs b/library/core/src/num/int_log10.rs index 649a736b6e7b..af8e1f90968d 100644 --- a/library/core/src/num/int_log10.rs +++ b/library/core/src/num/int_log10.rs @@ -1,9 +1,11 @@ //! These functions compute the integer logarithm of their type, assuming //! that someone has already checked that the value is strictly positive. +use crate::num::NonZero; + // 0 < val <= u8::MAX #[inline] -pub(super) const fn u8(val: u8) -> u32 { +const fn u8_impl(val: u8) -> u32 { let val = val as u32; // For better performance, avoid branches by assembling the solution @@ -45,13 +47,13 @@ const fn less_than_5(val: u32) -> u32 { // 0 < val <= u16::MAX #[inline] -pub(super) const fn u16(val: u16) -> u32 { +const fn u16_impl(val: u16) -> u32 { less_than_5(val as u32) } // 0 < val <= u32::MAX #[inline] -pub(super) const fn u32(mut val: u32) -> u32 { +const fn u32_impl(mut val: u32) -> u32 { let mut log = 0; if val >= 100_000 { val /= 100_000; @@ -62,7 +64,7 @@ pub(super) const fn u32(mut val: u32) -> u32 { // 0 < val <= u64::MAX #[inline] -pub(super) const fn u64(mut val: u64) -> u32 { +const fn u64_impl(mut val: u64) -> u32 { let mut log = 0; if val >= 10_000_000_000 { val /= 10_000_000_000; @@ -77,66 +79,87 @@ pub(super) const fn u64(mut val: u64) -> u32 { // 0 < val <= u128::MAX #[inline] -pub(super) const fn u128(mut val: u128) -> u32 { +const fn u128_impl(mut val: u128) -> u32 { let mut log = 0; if val >= 100_000_000_000_000_000_000_000_000_000_000 { val /= 100_000_000_000_000_000_000_000_000_000_000; log += 32; - return log + u32(val as u32); + return log + u32_impl(val as u32); } if val >= 10_000_000_000_000_000 { val /= 10_000_000_000_000_000; log += 16; } - log + u64(val as u64) + log + u64_impl(val as u64) } -#[cfg(target_pointer_width = "16")] -#[inline] -pub(super) const fn usize(val: usize) -> u32 { - u16(val as _) +macro_rules! define_unsigned_ilog10 { + ($($ty:ident => $impl_fn:ident,)*) => {$( + #[inline] + pub(super) const fn $ty(val: NonZero<$ty>) -> u32 { + let result = $impl_fn(val.get()); + + // SAFETY: Integer logarithm is monotonic non-decreasing, so the computed `result` cannot + // exceed the value produced for the maximum input. + unsafe { crate::hint::assert_unchecked(result <= const { $impl_fn($ty::MAX) }) }; + + result + } + )*}; } -#[cfg(target_pointer_width = "32")] -#[inline] -pub(super) const fn usize(val: usize) -> u32 { - u32(val as _) +define_unsigned_ilog10! { + u8 => u8_impl, + u16 => u16_impl, + u32 => u32_impl, + u64 => u64_impl, + u128 => u128_impl, } -#[cfg(target_pointer_width = "64")] #[inline] -pub(super) const fn usize(val: usize) -> u32 { - u64(val as _) +pub(super) const fn usize(val: NonZero) -> u32 { + #[cfg(target_pointer_width = "16")] + let impl_fn = u16; + + #[cfg(target_pointer_width = "32")] + let impl_fn = u32; + + #[cfg(target_pointer_width = "64")] + let impl_fn = u64; + + // SAFETY: We have selected the correct `impl_fn`, so the converting `val` to the argument is + // safe. + impl_fn(unsafe { NonZero::new_unchecked(val.get() as _) }) } -// 0 < val <= i8::MAX -#[inline] -pub(super) const fn i8(val: i8) -> u32 { - u8(val as u8) +macro_rules! define_signed_ilog10 { + ($($ty:ident => $impl_fn:ident,)*) => {$( + // 0 < val <= $ty::MAX + #[inline] + pub(super) const fn $ty(val: $ty) -> Option { + if val > 0 { + let result = $impl_fn(val.cast_unsigned()); + + // SAFETY: Integer logarithm is monotonic non-decreasing, so the computed `result` + // cannot exceed the value produced for the maximum input. + unsafe { + crate::hint::assert_unchecked(result <= const { $impl_fn($ty::MAX.cast_unsigned()) }); + } + + Some(result) + } else { + None + } + } + )*}; } -// 0 < val <= i16::MAX -#[inline] -pub(super) const fn i16(val: i16) -> u32 { - u16(val as u16) -} - -// 0 < val <= i32::MAX -#[inline] -pub(super) const fn i32(val: i32) -> u32 { - u32(val as u32) -} - -// 0 < val <= i64::MAX -#[inline] -pub(super) const fn i64(val: i64) -> u32 { - u64(val as u64) -} - -// 0 < val <= i128::MAX -#[inline] -pub(super) const fn i128(val: i128) -> u32 { - u128(val as u128) +define_signed_ilog10! { + i8 => u8_impl, + i16 => u16_impl, + i32 => u32_impl, + i64 => u64_impl, + i128 => u128_impl, } /// Instantiate this panic logic once, rather than for all the ilog methods diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 62f83a3a14d9..3e1749855d73 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -3527,11 +3527,7 @@ pub const fn checked_ilog2(self) -> Option { without modifying the original"] #[inline] pub const fn checked_ilog10(self) -> Option { - if self > 0 { - Some(int_log10::$ActualT(self as $ActualT)) - } else { - None - } + int_log10::$ActualT(self as $ActualT) } /// Computes the absolute value of `self`. diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index ee375dbaaab2..2b5279efb7f7 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1657,7 +1657,7 @@ pub const fn ilog2(self) -> u32 { without modifying the original"] #[inline] pub const fn ilog10(self) -> u32 { - super::int_log10::$Int(self.get()) + super::int_log10::$Int(self) } /// Calculates the midpoint (average) between `self` and `rhs`. diff --git a/tests/codegen-llvm/lib-optimizations/ilog10-range.rs b/tests/codegen-llvm/lib-optimizations/ilog10-range.rs new file mode 100644 index 000000000000..b466855389fb --- /dev/null +++ b/tests/codegen-llvm/lib-optimizations/ilog10-range.rs @@ -0,0 +1,213 @@ +//! Make sure the compiler knows the result range of `ilog10`. + +//@ compile-flags: -O -Z merge-functions=disabled + +#![crate_type = "lib"] + +use std::num::NonZero; + +// Signed integers. + +#[no_mangle] +fn i8_ilog10_range(value: i8) { + const MAX_RESULT: u32 = i8::MAX.ilog10(); + + // CHECK-LABEL: @i8_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value <= 0 || value.ilog10() <= MAX_RESULT); + assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT)); +} + +#[no_mangle] +fn i16_ilog10_range(value: i16) { + const MAX_RESULT: u32 = i16::MAX.ilog10(); + + // CHECK-LABEL: @i16_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value <= 0 || value.ilog10() <= MAX_RESULT); + assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT)); +} + +#[no_mangle] +fn i32_ilog10_range(value: i32) { + const MAX_RESULT: u32 = i32::MAX.ilog10(); + + // CHECK-LABEL: @i32_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value <= 0 || value.ilog10() <= MAX_RESULT); + assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT)); +} + +#[no_mangle] +fn i64_ilog10_range(value: i64) { + const MAX_RESULT: u32 = i64::MAX.ilog10(); + + // CHECK-LABEL: @i64_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value <= 0 || value.ilog10() <= MAX_RESULT); + assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT)); +} + +#[no_mangle] +fn i128_ilog10_range(value: i128) { + const MAX_RESULT: u32 = i128::MAX.ilog10(); + + // CHECK-LABEL: @i128_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value <= 0 || value.ilog10() <= MAX_RESULT); + assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT)); +} + +#[no_mangle] +fn isize_ilog10_range(value: isize) { + const MAX_RESULT: u32 = isize::MAX.ilog10(); + + // CHECK-LABEL: @isize_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value <= 0 || value.ilog10() <= MAX_RESULT); + assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT)); +} + +// Unsigned integer types. + +#[no_mangle] +fn u8_ilog10_range(value: u8) { + const MAX_RESULT: u32 = u8::MAX.ilog10(); + + // CHECK-LABEL: @u8_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value == 0 || value.ilog10() <= MAX_RESULT); + assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT)); +} + +#[no_mangle] +fn u16_ilog10_range(value: u16) { + const MAX_RESULT: u32 = u16::MAX.ilog10(); + + // CHECK-LABEL: @u16_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value == 0 || value.ilog10() <= MAX_RESULT); + assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT)); +} + +#[no_mangle] +fn u32_ilog10_range(value: u32) { + const MAX_RESULT: u32 = u32::MAX.ilog10(); + + // CHECK-LABEL: @u32_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value == 0 || value.ilog10() <= MAX_RESULT); + assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT)); +} + +#[no_mangle] +fn u64_ilog10_range(value: u64) { + const MAX_RESULT: u32 = u64::MAX.ilog10(); + + // CHECK-LABEL: @u64_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value == 0 || value.ilog10() <= MAX_RESULT); + assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT)); +} + +#[no_mangle] +fn u128_ilog10_range(value: u128) { + const MAX_RESULT: u32 = u128::MAX.ilog10(); + + // CHECK-LABEL: @u128_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value == 0 || value.ilog10() <= MAX_RESULT); + assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT)); +} + +#[no_mangle] +fn usize_ilog10_range(value: usize) { + const MAX_RESULT: u32 = usize::MAX.ilog10(); + + // CHECK-LABEL: @usize_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value == 0 || value.ilog10() <= MAX_RESULT); + assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT)); +} + +// Signed non-zero integers do not have `ilog10` methods. + +// Unsigned non-zero integers. + +#[no_mangle] +fn non_zero_u8_ilog10_range(value: NonZero) { + // CHECK-LABEL: @non_zero_u8_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value.ilog10() <= const { u8::MAX.ilog10() }); +} + +#[no_mangle] +fn non_zero_u16_ilog10_range(value: NonZero) { + // CHECK-LABEL: @non_zero_u16_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value.ilog10() <= const { u16::MAX.ilog10() }); +} + +#[no_mangle] +fn non_zero_u32_ilog10_range(value: NonZero) { + // CHECK-LABEL: @non_zero_u32_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value.ilog10() <= const { u32::MAX.ilog10() }); +} + +#[no_mangle] +fn non_zero_u64_ilog10_range(value: NonZero) { + // CHECK-LABEL: @non_zero_u64_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value.ilog10() <= const { u64::MAX.ilog10() }); +} + +#[no_mangle] +fn non_zero_u128_ilog10_range(value: NonZero) { + // CHECK-LABEL: @non_zero_u128_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value.ilog10() <= const { u128::MAX.ilog10() }); +} + +#[no_mangle] +fn non_zero_usize_ilog10_range(value: NonZero) { + // CHECK-LABEL: @non_zero_usize_ilog10_range( + // CHECK-NOT: panic + // CHECK: ret void + // CHECK-NEXT: } + assert!(value.ilog10() <= const { usize::MAX.ilog10() }); +} From 6cdfb609f9dba3dfc9e412bb6a6d87ee9efcf462 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 28 Nov 2025 23:31:41 -0500 Subject: [PATCH 128/585] make assoc fn inherit const stability from inherent `const impl` blocks --- compiler/rustc_passes/src/stability.rs | 2 +- .../traits/const-traits/auxiliary/staged-api.rs | 9 ++++++++- .../const-traits/inherent-impl-stability.rs | 16 ++++++++++++++++ .../const-traits/inherent-impl-stability.stderr | 13 +++++++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/const-traits/inherent-impl-stability.rs create mode 100644 tests/ui/traits/const-traits/inherent-impl-stability.stderr diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index b7e6e2d451e3..39830db2b11d 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -54,7 +54,7 @@ fn inherit_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { match def_kind { DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { match tcx.def_kind(tcx.local_parent(def_id)) { - DefKind::Impl { of_trait: true } => true, + DefKind::Impl { .. } => true, _ => false, } } diff --git a/tests/ui/traits/const-traits/auxiliary/staged-api.rs b/tests/ui/traits/const-traits/auxiliary/staged-api.rs index b2b1e0615c37..65e75864ff82 100644 --- a/tests/ui/traits/const-traits/auxiliary/staged-api.rs +++ b/tests/ui/traits/const-traits/auxiliary/staged-api.rs @@ -1,4 +1,3 @@ -//@ compile-flags: -Znext-solver #![feature(const_trait_impl)] #![feature(staged_api)] #![stable(feature = "rust1", since = "1.0.0")] @@ -19,6 +18,14 @@ impl const MyTrait for Unstable { fn func() {} } +// tested in inherent-impl-stability.rs instead to avoid clutter +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "unstable", issue = "none")] +const impl Unstable { + #[stable(feature = "rust1", since = "1.0.0")] + pub fn inherent_func() {} +} + #[stable(feature = "rust1", since = "1.0.0")] pub struct Unstable2; diff --git a/tests/ui/traits/const-traits/inherent-impl-stability.rs b/tests/ui/traits/const-traits/inherent-impl-stability.rs new file mode 100644 index 000000000000..e520e5af2e09 --- /dev/null +++ b/tests/ui/traits/const-traits/inherent-impl-stability.rs @@ -0,0 +1,16 @@ +//@ aux-build: staged-api.rs +extern crate staged_api; + +use staged_api::*; + +// Const stability has no impact on usage in non-const contexts. +fn non_const_context() { + Unstable::inherent_func(); +} + +const fn stable_const_context() { + Unstable::inherent_func(); + //~^ ERROR: `staged_api::Unstable::inherent_func` is not yet stable as a const fn +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/inherent-impl-stability.stderr b/tests/ui/traits/const-traits/inherent-impl-stability.stderr new file mode 100644 index 000000000000..018065c1f4f0 --- /dev/null +++ b/tests/ui/traits/const-traits/inherent-impl-stability.stderr @@ -0,0 +1,13 @@ +error: `staged_api::Unstable::inherent_func` is not yet stable as a const fn + --> $DIR/inherent-impl-stability.rs:12:5 + | +LL | Unstable::inherent_func(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add `#![feature(unstable)]` to the crate attributes to enable + | +LL + #![feature(unstable)] + | + +error: aborting due to 1 previous error + From 74da3a26c60ddf6fbdf12bedba409a12c51789da Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Sat, 29 Nov 2025 14:29:58 +0000 Subject: [PATCH 129/585] add coercions chapter and split out non hir typeck stuff --- src/doc/rustc-dev-guide/src/SUMMARY.md | 17 +- .../src/appendix/code-index.md | 2 +- .../rustc-dev-guide/src/appendix/glossary.md | 2 +- .../src/hir-typeck/coercions.md | 284 ++++++++++++++++++ .../src/{ => hir-typeck}/method-lookup.md | 0 .../summary.md} | 8 +- src/doc/rustc-dev-guide/src/overview.md | 2 +- src/doc/rustc-dev-guide/src/thir.md | 2 +- .../src/traits/canonical-queries.md | 2 +- 9 files changed, 302 insertions(+), 17 deletions(-) create mode 100644 src/doc/rustc-dev-guide/src/hir-typeck/coercions.md rename src/doc/rustc-dev-guide/src/{ => hir-typeck}/method-lookup.md (100%) rename src/doc/rustc-dev-guide/src/{type-checking.md => hir-typeck/summary.md} (94%) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 37ab3ff56979..c136d37160c5 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -186,14 +186,15 @@ - [Opaque types](./solve/opaque-types.md) - [Significant changes and quirks](./solve/significant-changes.md) - [`Unsize` and `CoerceUnsized` traits](./traits/unsize.md) -- [Type checking](./type-checking.md) - - [Method lookup](./method-lookup.md) - - [Variance](./variance.md) - - [Coherence checking](./coherence.md) - - [Opaque types](./opaque-types-type-alias-impl-trait.md) - - [Inference details](./opaque-types-impl-trait-inference.md) - - [Return Position Impl Trait In Trait](./return-position-impl-trait-in-trait.md) - - [Region inference restrictions][opaque-infer] +- [Variance](./variance.md) +- [Coherence checking](./coherence.md) +- [HIR Type checking](./hir-typeck/summary.md) + - [Coercions](./hir-typeck/coercions.md) + - [Method lookup](./hir-typeck/method-lookup.md) +- [Opaque types](./opaque-types-type-alias-impl-trait.md) + - [Inference details](./opaque-types-impl-trait-inference.md) + - [Return Position Impl Trait In Trait](./return-position-impl-trait-in-trait.md) + - [Region inference restrictions][opaque-infer] - [Const condition checking](./effects.md) - [Pattern and exhaustiveness checking](./pat-exhaustive-checking.md) - [Unsafety checking](./unsafety-checking.md) diff --git a/src/doc/rustc-dev-guide/src/appendix/code-index.md b/src/doc/rustc-dev-guide/src/appendix/code-index.md index 22b3396ed1ff..bf9d3bd46564 100644 --- a/src/doc/rustc-dev-guide/src/appendix/code-index.md +++ b/src/doc/rustc-dev-guide/src/appendix/code-index.md @@ -33,7 +33,7 @@ Item | Kind | Short description | Chapter | [Identifiers in the HIR]: ../hir.html#hir-id [The parser]: ../the-parser.html [The Rustc Driver and Interface]: ../rustc-driver/intro.html -[Type checking]: ../type-checking.html +[Type checking]: ../hir-typeck/summary.html [The `ty` modules]: ../ty.html [Rustdoc]: ../rustdoc.html [Emitting Diagnostics]: ../diagnostics.html diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md index 21162f8ee7d0..901fb68c0513 100644 --- a/src/doc/rustc-dev-guide/src/appendix/glossary.md +++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md @@ -88,7 +88,7 @@ Term | Meaning trans | Short for _translation_, the code to translate MIR into LLVM IR. Renamed to [codegen](#codegen). `Ty` | The internal representation of a type. ([see more](../ty.md)) `TyCtxt` | The data structure often referred to as [`tcx`](#tcx) in code which provides access to session data and the query system. -UFCS | Short for _universal function call syntax_, this is an unambiguous syntax for calling a method. **Term no longer in use!** Prefer _fully-qualified path/syntax_. ([see more](../type-checking.md), [see the reference](https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls)) +UFCS | Short for _universal function call syntax_, this is an unambiguous syntax for calling a method. **Term no longer in use!** Prefer _fully-qualified path/syntax_. ([see more](../hir-typeck/summary.md), [see the reference](https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls)) uninhabited type | A type which has _no_ values. This is not the same as a ZST, which has exactly 1 value. An example of an uninhabited type is `enum Foo {}`, which has no variants, and so, can never be created. The compiler can treat code that deals with uninhabited types as dead code, since there is no such value to be manipulated. `!` (the never type) is an uninhabited type. Uninhabited types are also called _empty types_. upvar | A variable captured by a closure from outside the closure. variance | Determines how changes to a generic parameter affect subtyping; for example, if `T` is a subtype of `U`, then `Vec` is a subtype `Vec` because `Vec` is _covariant_ in its generic parameter. See [the background chapter](./background.md#variance) for a more general explanation. See the [variance chapter](../variance.md) for an explanation of how type checking handles variance. diff --git a/src/doc/rustc-dev-guide/src/hir-typeck/coercions.md b/src/doc/rustc-dev-guide/src/hir-typeck/coercions.md new file mode 100644 index 000000000000..384ea9bcf030 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/hir-typeck/coercions.md @@ -0,0 +1,284 @@ +# Coercions + +Coercions are implicit operations which transform a value into a different type. A coercion *site* is a position where a coercion is able to be implicitly performed. There are two kinds of coercion sites: +- one-to-one +- LUB (Least-Uppper-Bound) + +```rust +let one_to_one_coercion: &u32 = &mut 8; + +let lub_coercion = match my_bool { + true => &mut 10, + false => &12, +}; +``` + +See the Reference page on coercions for descriptions of what coercions exist and what expressions are coercion sites: + +## one-to-one coercions + +With a one-to-one coercion we coerce from one singular type to a known target type. In the above example this would be the coercion from `&mut u32` to `&u32`. + +A one-to-one coercion can be performed by calling [`FnCtxt::coerce`][fnctxt_coerce]. + +## LUB coercions + +With a LUB coercion we coerce a set of source types to some unknown target type. Unlike one-to-one coercions, a LUB coercion *produces* the target type that all of the source types coerce to. + +In the above example this would be the LUB coercion of both `&mut i32` and `&i32`, where we produce the target type `&i32`. + +The name "LUB coercion" (Least-Upper-Bound coercion) comes from how this coercion takes a set of types and computes the least coerced/subtyped type that both source types are coercable/subtypeable into. + +The general process for performing a LUB coercion is as follows: + +```rust ignore +// * 1 +let mut coerce = CoerceMany::new(intial_lub_ty); +for expr in exprs { + // * 2 + let expr_ty = fcx.check_expr_with_expectation(expr, expectation); + coerce.coerce(fcx, &cause, expr, expr_ty); +} +// * 3 +let final_ty = coerce.complete(fcx); +``` + +There are a few key steps here: +1. Creating the [`CoerceMany`][coerce_many] value and picking an initial lub +2. Typechecking each expression and registering its type as part of the LUB coercion +3. Completing the LUB coercion to get the resulting lubbed type + +### Step 1 + +First we create a [`CoerceMany`][coerce_many] value, this stores all of the state required for the LUB coercion. Unlike one-to-one coercions, a LUB coercion isn't a single function call as we want to intermix typechecking with advancing the LUB coercion. + +Creating a `CoerceMany` takes some `initial_lub` type. This is different from the *target* of the coercion which is an output of a LUB coercion rather than an input (unlike a one-to-one coercion). + +The initial lub ty should be derived from the [`Expectation`][expectation] for whatever expression this LUB coercion is for. It allows for inference constraints from computing the LUB coercion to propagate into the `Expectation`s used for type checking later expressions participating in the LUB coercion. + +See the ["unnecessary inference constraints"][unnecessary_inference_constraints] header for some more information about the effects this has. + +If there's no `Expectation` to use then some new infer var should be made for the initial lub ty. + +### Step 2 + +Next, for each expression participating in the LUB coercion, we typecheck it then invoke [`CoerceMany::coerce`][coerce_many_coerce] with its type. + +In some cases the expression participating in the LUB coercion doesn't actually exist in the HIR. For example when handling an operand-less `break` or `return` expression we need `()` to participate in the LUB coercion. + +In these cases the [`CoerceMany::coerce_forced_unit`][coerce_many_coerce_forced_unit] method can be used. + +The `CoerceMany::coerce` and `coerce_forced_unit` methods will both emit errors if the new type causes the LUB coercion to be unsatisfiable. In this case the final type of the LUB coercion will be an error type. + +### Step 3 + +Finally once all expressions have been coerced the final type of the LUB coercion can be obtained by calling [`CoerceMany::complete`][coerce_many_complete]. + +The resulting type of the LUB coercion is meaningfully different from the initial lub type passed in when constructing the [`CoerceMany`][coerce_many]. You should always take the resulting type of the LUB coercion and perform any necessary checks on it. + +## Implementation nuances + +### Adjustments + +When a coerce operation succeeds we record what kind of coercion it was, for example an unsize coercion or an autoderef etc. This is handled as part of the coerce operation by writing a list of *adjustments* into the in-progress [`TypeckResults`][typeck_results]. + +When building THIR we take the adjustments stored in the `TypeckResults` and make all of the coercion steps explicit. After this point in the compiler there isn't really a notion of coercions, only explicit casts and subtyping in the MIR. + +TODO: write and link to an adjustments chapter here + +### How does `CoerceMany` work + +[`CoerceMany`][coerce_many] works by repeatedly taking the current lub ty and some new source type, and computing a new lub ty which both types can coerce to. The core logic of taking a pair of types and computing some new third type can be found in [`try_find_coercion_lub`][try_find_coercion_lub]. + +```rust +fn foo() {} +fn bar() {} + +let a = match my_bool { + true => foo, + true if other_bool => foo, + false => bar, +} +``` + +In this example when type checking the `match` expression a LUB coercion is performed. This LUB coercion starts out with an initial lub ty of some inference variable `?x` due to the let statement having no known type. + +There are three expressions that participate in this LUB coercion. The first expression of a LUB coercion is special, instead of computing a new type with the existing initial lub ty, we coerce directly from the first expression to the initial lub ty. + +1. After type checking `true => foo,` we wind up with the type `FnDef(Foo)`. We then call [`CoerceMany::coerce`][coerce_many_coerce] which will perform a one-to-one coercion of `FnDef(Foo)` to `?x`. This infers `?x=FnDef(Foo)` giving us a new lub ty for the LUB coercion. +2. After type checking `true if other_bool => foo,` we once again wind up with the type `FnDef(Foo)`. We'll then call `CoerceMany::coerce` which will attempt to compute a new lub ty from our previous lub ty (`FnDef(Foo)`) and the type of this expression (`FnDef(Foo)`). This gives us a lub ty of `FnDef(Foo)`. +3. After type checking `false => bar,` we'll wind up with the type `FnDef(Bar)`. We'll then call `CoerceMany::coerce` which will attempt to compute a new lub ty from our previous lub ty (`FnDef(Foo)`) and the type of this expression (`FnDef(Bar)`). In this case we get the type `fn() -> ()` as we choose to coerce both function item types to a function pointer. + +This gives us a final type for the LUB coercion of `fn() -> ()`. + +### Transitive coercions + +[`CoerceMany`][coerce_many]'s algorithm of repeatedly attempting to coerce the currrent target type to the new type currently results in "Transitive Coercions". It's possible for a step in a LUB coercion to coerce an expression, and then a later step to coerce that expression further. + +```rust +struct Foo; + +use std::ops::Deref; + +impl Deref for Foo { + type Target = [u8; 2]; + + fn deref(&self) -> &[u8; 2] { + &[1; _] + } +} + +fn main() { + match () { + _ if true => &Foo, + _ if true => &[1_u8; 2], + _ => &[1_u8; 2] as &[u8], + }; +} +``` + +Here we have a LUB coercion with an initial lub ty of `?x`. In the first step we do a one-to-one coercion of `&Foo` to `?x` (reminder the first step is special). + +In the second step we compute a new lub ty from the current lub ty of `&Foo` and the new type of `&[u8; 2]`. This new lub ty would be `&[u8; 2]` by performing a deref coercion of `&Foo` to `&[u8; 2]` on the first expression. + +In the third step we compute a new lub ty from the current lub ty of `&[u8; 2]` and the new type of `&[u8]`. This new lub ty would be `&[u8]` by performing an unsizing coercion of `&[u8; 2]` to `&[u8]` on the first two expressions. + +Note how the first expression is coerced twice. Once a deref coercion from `&Foo` to `&[u8; 2]`, and then an unsizing coercion from `&[u8; 2]` to `&[u8]`. + +The current implementation of transitive coercions is broken, the previous example actually ICEs on stable. While the logic for performing a LUB coercion can produce transitive coercions just fine, the rest of the compiler is not set up to handle them. + +One-to-one coercions are also not capable of producing a lot of the kinds of transitive coercions that LUB coercions can. For example if we take the previous example and turn it into a one-to-one coercion we get a compile error: +```rust +struct Foo; + +use std::ops::Deref; + +impl Deref for Foo { + type Target = [u8; 2]; + + fn deref(&self) -> &[u8; 2] { + &[1; _] + } +} + +fn main() { + let a: &[u8] = &Foo; +} +``` + +Here we try to perform a one-to-one coercion from `&Foo` to `&[u8]` which fails as we can only perform a deref coercion *or* an unsizing coercion, we can't compose the two. + +### How does `try_find_coercion_lub` work + +There are three ways that we can compute a new lub ty for a LUB coercion: +1. Coerce both the current lub ty and the new type to a function pointer +2. Coerce the current lub ty to the new type (or vice versa) +3. Compute a mutual supertype of the current lub ty and the new type + +Unfortunately the actual implementation obsfucates this a fair amount. + +Computing a mutual supertype happens implicitly due to reusing the logic for one-to-one coercions which already handles subtyping if coercing fails. + +Additionally when trying to coerce both the current lub ty and the new type to function pointers we eagerly try to compute a mutual supertype to avoid unnecessary coercions. + +There is likely room for improving the structure of this function to make it more closely align with the conceptual model. + +### `use_lub` field in one-to-one coercions + +The implementation of one-to-one coercions is reused as part of LUB coercions. + +It would be wrong for LUB coercions to use one way subtyping when relating signatures or falling back to subtyping in the case of no coercions being possible. Instead we want to compute a mutual supertype of the two types. + +The `use_lub` field on [`Coerce`][coerce_ty] exists to toggle whether to perform normal subtyping (in the case of a one-to-one coercion), or whether to compute a mutual supertype (in the case of a LUB coercion). + +### Lubbing + +In theory computing a mutual supertype should be as simple as creating some new infer var `?mutual_sup` and then requiring `lub_ty <: ?mutual_sup` and `new_ty <: ?mutual_sup`. In reality LUB coercions use a special [`TypeRelation`][type_relation], [`LatticeOp`][lattice_op]. + +This is primarily to work around subtyping/generalization for higher ranked types being fairly broken. Unlike normal subtyping, when encountering higher ranked types the lub type relation will switch to invariance. + +This enforces that the binders of the higher ranked types are equivalent which avoids the need to pick a "most general" binder, which would be quite difficult to do. + +It also avoids the process of computing a mutual supertype being *order dependent*. Given the types `a` and `b`, it may be nice if computing the mutual supertype of `a` and `b` would yield the same result as computing the mutual supertype of `b` and `a`. + +The current issues with higher ranked types and subtyping would cause this property to not hold if we were to use the naive method of computing a mutual supertype. + +Coercions being turned into explicit MIR operations during MIR building means that the process of computing the final type of a LUB coercion only occurs during HIR typeck. This also means the behaviour of computing a mutual supertype only matters for type inference, and is not soundness relevant. + +## Cautionary notes + +### Probes + +Care should be taken when coercing from inside of a probe as both one-to-one coercions and LUB coercions have side effects that can't be rolled back by a probe. + +LUB coercions will emit error when a coercion step fails, this makes it entirely suitable for use inside of probes. + +1-to-1 and LUB coercions will both apply *adjustments* to the coerced expressions on success. This means that if inside of a probe and an attempt to coerce succeeds, then the probe must not rollback anything. + +It's therefore correct to wrap a [`FnCtxt::coerce`][fnctxt_coerce] call inside of a [`commit_if_ok`][commit_if_ok], but would be wrong to do so if returning `Err` after the coerce call. It would also be wrong to call `FnCtxt::coerce` from within a [`probe`][probe]. + +[`CoerceMany`][coerce_many] should never be used from within a `probe` or `commit_if_ok`. + +### Never-to-Any coercions + +Coercing from the never type (`!`) to an inference variable will result in a [`NeverToAny`][never_to_any] coercion with a target type of the inference variable. This is subtly different from *unifying* the inference variable with the never type. + +Unifying some infer var `?x` with `!` requires that `?x` actually be *equal* to `!`. However, a `NeverToAny` coercion allows for `?x` to be inferred to any possible type. + +This distinction means that in cases where the initial lub ty of a coercion is an inference variable (e.g. there's no [`Expectation`][expectation] to use for the initial lub ty), it's still important to use a coercion instead of subtyping. + +See PR [#147834](https://github.com/rust-lang/rust/pull/147834) which fixes a bug where we were incorrectly inferring things to the never type instead of going through a coercion. + +### Fallback to subtyping + +Even though subtyping is not a coercion, both [`FnCtxt::coerce`][fnctxt_coerce] and [`CoerceMany::coerce`][coerce_many_coerce]/[`coerce_forced_unit`][coerce_many_coerce_forced_unit] are able to succeed due to subtyping. + +For one-to-one coercions we will try to enforce the source type is a subtype of the target type. For LUB coercions we will try to compute a type that is a supertype of all the existing types. + +For example performing a one-to-one coercion of `?x` to `u32` will fallback to subtyping, inferring `?x eq u32`. This means that when a coercion fails there's no need to attempt subtyping afterwards. + +### Unnecessary inference constraints + +Using types from [`Expectation`][expectation]s as the initial lub ty can cause infer vars to be constrained by the types of the expressions participating in the LUB coercion. This is not always desirable as these infer vars actually only need to be constrained by the final type of the LUB coercion. + +```rust +fn foo(_: T) {} + +fn a() {} +fn b() {} + +foo::(match my_bool { + true => a, + false => b, +}) +``` + +Here we have a LUB coercion with the first expression being of type `FnDef(a)` and the second expression being of type `FnDef(b)`. If we use `?x` as the initial lub ty of the LUB coercion then we would get the following behaviour: +- expression 1: infer `?x=FnDef(a)` +- expression 2: find a coercion lub between `FnDef(a), FnDef(b)` resulting in `fn() -> ()` +- the final type of the LUB coercion is `fn() -> ()`. equate `?x eq fn() -> ()`, where `?x` actually already has been inferred to `FnDef(a)`, so this is actually equating `FnDef(a) eq fn() -> ()` which does not hold + +To avoid some (but not all) of these undesirable inference constraints, if the `Expectation` for the LUB coercion is an inference variable then we won't use it as the initial lub ty. Instead we create a new infer var, for example in the above code snippet we would actually make some new infer var `?y` for the initial lub ty instead of using `?x`. +- expression 1: infer `?y=FnDef(a)` +- expression 2: find a coercion lub between `FnDef(a), FnDef(b)` resulting in `fn() -> ()` +- the final type of the LUB coercion is `fn() -> ()`, infer `?x=fn() -> ()` + +See [#140283](https://github.com/rust-lang/rust/pull/140283) for a case where we had undesirable inference constraints caused by not creating a new infer var. + +This doesn't avoid unnecessary constraints in *all* cases, only the most common case of having an infer var as our `Expectation`. In theory it would be desirable to avoid these constraints in all cases but it would be quite involved to do so. + +[coerce_many]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/coercion/struct.CoerceMany.html +[coerce_many_coerce]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/coercion/struct.CoerceMany.html#method.coerce +[coerce_many_coerce_forced_unit]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/coercion/struct.CoerceMany.html#method.coerce_forced_unit +[coerce_many_complete]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/coercion/struct.CoerceMany.html#method.complete +[try_find_coercion_lub]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html#method.try_find_coercion_lub +[expectation]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/expectation/enum.Expectation.html +[unnecessary_inference_constraints]: #unnecessary-inference-constraints +[typeck_results]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html +[type_relation]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/canonical/ir/relate/trait.TypeRelation.html +[lattice_op]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/relate/lattice/struct.LatticeOp.html +[fnctxt_coerce]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html#method.coerce +[coerce_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/coercion/struct.Coerce.html +[commit_if_ok]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html#method.commit_if_ok +[probe]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html#method.probe +[never_to_any]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adjustment/enum.Adjust.html#variant.NeverToAny diff --git a/src/doc/rustc-dev-guide/src/method-lookup.md b/src/doc/rustc-dev-guide/src/hir-typeck/method-lookup.md similarity index 100% rename from src/doc/rustc-dev-guide/src/method-lookup.md rename to src/doc/rustc-dev-guide/src/hir-typeck/method-lookup.md diff --git a/src/doc/rustc-dev-guide/src/type-checking.md b/src/doc/rustc-dev-guide/src/hir-typeck/summary.md similarity index 94% rename from src/doc/rustc-dev-guide/src/type-checking.md rename to src/doc/rustc-dev-guide/src/hir-typeck/summary.md index 4e8b30b19fc7..23df97a9cf83 100644 --- a/src/doc/rustc-dev-guide/src/type-checking.md +++ b/src/doc/rustc-dev-guide/src/hir-typeck/summary.md @@ -1,4 +1,4 @@ -# Type checking +# HIR Type checking The [`hir_analysis`] crate contains the source for "type collection" as well as a bunch of related functionality. @@ -7,8 +7,8 @@ These crates draw heavily on the [type inference] and [trait solving]. [`hir_analysis`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/index.html [`hir_typeck`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/index.html -[type inference]: ./type-inference.md -[trait solving]: ./traits/resolution.md +[type inference]: ./../type-inference.md +[trait solving]: ./../traits/resolution.md ## Type collection @@ -40,7 +40,7 @@ type *checking*). For more details, see the [`collect`][collect] module. -[queries]: ./query.md +[queries]: ../query.md [collect]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/collect/index.html **TODO**: actually talk about type checking... [#1161](https://github.com/rust-lang/rustc-dev-guide/issues/1161) diff --git a/src/doc/rustc-dev-guide/src/overview.md b/src/doc/rustc-dev-guide/src/overview.md index f83b5b2e181c..23cc94d41846 100644 --- a/src/doc/rustc-dev-guide/src/overview.md +++ b/src/doc/rustc-dev-guide/src/overview.md @@ -130,7 +130,7 @@ with additional low-level types and annotations added (e.g. an ELF object or the final binary. [*trait solving*]: traits/resolution.md -[*type checking*]: type-checking.md +[*type checking*]: hir-typeck/summary.md [*type inference*]: type-inference.md [`bump`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/struct.Parser.html#method.bump [`check`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/struct.Parser.html#method.check diff --git a/src/doc/rustc-dev-guide/src/thir.md b/src/doc/rustc-dev-guide/src/thir.md index 3d3dafaef49b..d5f7d8b5fcb7 100644 --- a/src/doc/rustc-dev-guide/src/thir.md +++ b/src/doc/rustc-dev-guide/src/thir.md @@ -5,7 +5,7 @@ The THIR ("Typed High-Level Intermediate Representation"), previously called HAI [type checking]. It is (as of January 2024) used for [MIR construction], [exhaustiveness checking], and [unsafety checking]. -[type checking]: ./type-checking.md +[type checking]: ./hir-typeck/summary.md [MIR construction]: ./mir/construction.md [exhaustiveness checking]: ./pat-exhaustive-checking.md [unsafety checking]: ./unsafety-checking.md diff --git a/src/doc/rustc-dev-guide/src/traits/canonical-queries.md b/src/doc/rustc-dev-guide/src/traits/canonical-queries.md index 792858bd2af8..389f380e4b8d 100644 --- a/src/doc/rustc-dev-guide/src/traits/canonical-queries.md +++ b/src/doc/rustc-dev-guide/src/traits/canonical-queries.md @@ -214,7 +214,7 @@ As a result of this assignment, the type of `u` is forced to be `Option>`, where `?V` represents the element type of the vector. This in turn implies that `?U` is [unified] to `Vec`. -[unified]: ../type-checking.html +[unified]: ../hir-typeck/summary.md Let's suppose that the type checker decides to revisit the "as-yet-unproven" trait obligation we saw before, `Vec: From 5009847d1461d2af722dc154a00614765a80ac16 Mon Sep 17 00:00:00 2001 From: joboet Date: Wed, 17 Sep 2025 17:24:25 +0200 Subject: [PATCH 130/585] std: don't call `current_os_id` from signal handler --- .../std/src/sys/pal/unix/stack_overflow.rs | 33 ++++++++++--------- .../pal/unix/stack_overflow/thread_info.rs | 10 ++++-- library/std/src/sys/thread/unix.rs | 9 +++-- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 226b6bce01b5..040fda75a508 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -8,8 +8,8 @@ pub struct Handler { } impl Handler { - pub unsafe fn new(thread_name: Option>) -> Handler { - make_handler(false, thread_name) + pub unsafe fn new() -> Handler { + make_handler(false) } fn null() -> Handler { @@ -117,8 +117,15 @@ mod imp { if let Some(thread_info) = thread_info && thread_info.guard_page_range.contains(&fault_addr) { - let name = thread_info.thread_name.as_deref().unwrap_or(""); - let tid = crate::thread::current_os_id(); + // Hey you! Yes, you modifying the stack overflow message! + // Please make sure that all functions called here are + // actually async-signal-safe. If they're not, try retrieving + // the information beforehand and storing it in `ThreadInfo`. + // Thank you! + // - says Jonas after having had to watch his carefully + // written code get made unsound again. + let tid = thread_info.tid; + let name = thread_info.name.as_deref().unwrap_or(""); rtprintpanic!("\nthread '{name}' ({tid}) has overflowed its stack\n"); rtabort!("stack overflow"); } @@ -164,12 +171,12 @@ pub unsafe fn init() { if !NEED_ALTSTACK.load(Ordering::Relaxed) { // haven't set up our sigaltstack yet NEED_ALTSTACK.store(true, Ordering::Release); - let handler = unsafe { make_handler(true, None) }; + let handler = unsafe { make_handler(true) }; MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed); mem::forget(handler); if let Some(guard_page_range) = guard_page_range.take() { - set_current_info(guard_page_range, Some(Box::from("main"))); + set_current_info(guard_page_range); } } @@ -240,14 +247,14 @@ unsafe fn get_stack() -> libc::stack_t { /// # Safety /// Mutates the alternate signal stack #[forbid(unsafe_op_in_unsafe_fn)] - pub unsafe fn make_handler(main_thread: bool, thread_name: Option>) -> Handler { + pub unsafe fn make_handler(main_thread: bool) -> Handler { if cfg!(panic = "immediate-abort") || !NEED_ALTSTACK.load(Ordering::Acquire) { return Handler::null(); } if !main_thread { if let Some(guard_page_range) = unsafe { current_guard() } { - set_current_info(guard_page_range, thread_name); + set_current_info(guard_page_range); } } @@ -633,10 +640,7 @@ pub unsafe fn init() {} pub unsafe fn cleanup() {} - pub unsafe fn make_handler( - _main_thread: bool, - _thread_name: Option>, - ) -> super::Handler { + pub unsafe fn make_handler(_main_thread: bool) -> super::Handler { super::Handler::null() } @@ -720,10 +724,7 @@ pub unsafe fn init() { pub unsafe fn cleanup() {} - pub unsafe fn make_handler( - main_thread: bool, - _thread_name: Option>, - ) -> super::Handler { + pub unsafe fn make_handler(main_thread: bool) -> super::Handler { if !main_thread { reserve_stack(); } diff --git a/library/std/src/sys/pal/unix/stack_overflow/thread_info.rs b/library/std/src/sys/pal/unix/stack_overflow/thread_info.rs index e81429b98a6c..42eb0cd9a61a 100644 --- a/library/std/src/sys/pal/unix/stack_overflow/thread_info.rs +++ b/library/std/src/sys/pal/unix/stack_overflow/thread_info.rs @@ -32,8 +32,9 @@ use crate::sys::os::errno_location; pub struct ThreadInfo { + pub tid: u64, + pub name: Option>, pub guard_page_range: Range, - pub thread_name: Option>, } static LOCK: Mutex<()> = Mutex::new(()); @@ -108,14 +109,17 @@ fn spin_lock_in_setup(this: usize) -> UnlockOnDrop { } } -pub fn set_current_info(guard_page_range: Range, thread_name: Option>) { +pub fn set_current_info(guard_page_range: Range) { + let tid = crate::thread::current_os_id(); + let name = crate::thread::with_current_name(|name| name.map(Box::from)); + let this = errno_location().addr(); let _lock_guard = LOCK.lock(); let _spin_guard = spin_lock_in_setup(this); // SAFETY: we own the spin lock, so `THREAD_INFO` cannot be aliased. let thread_info = unsafe { &mut *(&raw mut THREAD_INFO) }; - thread_info.insert(this, ThreadInfo { guard_page_range, thread_name }); + thread_info.insert(this, ThreadInfo { tid, name, guard_page_range }); } pub fn delete_current_info() { diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index d4c27097afd7..4adc94d0e5c9 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -14,7 +14,7 @@ #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto",))] use crate::sys::weak::weak; use crate::sys::{os, stack_overflow}; -use crate::thread::{ThreadInit, current}; +use crate::thread::ThreadInit; use crate::time::Duration; use crate::{cmp, io, ptr}; #[cfg(not(any( @@ -111,10 +111,9 @@ extern "C" fn thread_start(data: *mut libc::c_void) -> *mut libc::c_void { let init = Box::from_raw(data as *mut ThreadInit); let rust_start = init.init(); - // Set up our thread name and stack overflow handler which may get triggered - // if we run out of stack. - let thread = current(); - let _handler = stack_overflow::Handler::new(thread.name().map(Box::from)); + // Now that the thread information is set, set up our stack + // overflow handler. + let _handler = stack_overflow::Handler::new(); rust_start(); } From c3c14018cf98d2944b206716b8184e2caa9a59ac Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 29 Nov 2025 19:41:44 +0200 Subject: [PATCH 131/585] do not mess with a &[u8; 2] --- src/doc/rustc-dev-guide/ci/sembr/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index b74dbbe56bfe..7ace34aed984 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -27,7 +27,7 @@ struct Cli { static REGEX_IGNORE_LINK_TARGETS: LazyLock = LazyLock::new(|| Regex::new(r"^\[.+\]: ").unwrap()); static REGEX_SPLIT: LazyLock = - LazyLock::new(|| Regex::new(r"([^\.\d\-\*]\.|[^r]\?|;|!)\s").unwrap()); + LazyLock::new(|| Regex::new(r"([^\.\d\-\*]\.|[^r]\?|!)\s").unwrap()); // list elements, numbered (1.) or not (- and *) static REGEX_LIST_ENTRY: LazyLock = LazyLock::new(|| Regex::new(r"^\s*(\d\.|\-|\*)\s+").unwrap()); @@ -196,7 +196,7 @@ fn lengthen_lines(content: &str, limit: usize) -> String { fn test_sembr() { let original = " # some. heading -must! be; split? +must! be. split? 1. ignore a dot after number. but no further ignore | tables ignore e.g. and @@ -214,7 +214,7 @@ fn test_sembr() { let expected = " # some. heading must! -be; +be. split? 1. ignore a dot after number. but no further From e26128a3c71a553e2c00e58253a48ab95dbb4dc8 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 29 Nov 2025 19:42:53 +0200 Subject: [PATCH 132/585] sembr tests/crater.md --- src/doc/rustc-dev-guide/src/tests/crater.md | 41 +++++++++++---------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/crater.md b/src/doc/rustc-dev-guide/src/tests/crater.md index 96bb5a4f2ae6..df7e8ef0b7ed 100644 --- a/src/doc/rustc-dev-guide/src/tests/crater.md +++ b/src/doc/rustc-dev-guide/src/tests/crater.md @@ -1,43 +1,46 @@ # Crater [Crater](https://github.com/rust-lang/crater) is a tool for compiling and -running tests for _every_ crate on [crates.io](https://crates.io) (and a few on -GitHub). It is mainly used for checking the extent of breakage when implementing +running tests for _every_ crate on [crates.io](https://crates.io) (and a few on GitHub). +It is mainly used for checking the extent of breakage when implementing potentially breaking changes and ensuring lack of breakage by running beta vs stable compiler versions. ## When to run Crater You should request a Crater run if your PR makes large changes to the compiler -or could cause breakage. If you are unsure, feel free to ask your PR's reviewer. +or could cause breakage. +If you are unsure, feel free to ask your PR's reviewer. ## Requesting Crater Runs The Rust team maintains a few machines that can be used for Crater runs -on the changes introduced by a PR. If your PR needs a Crater run, leave a -comment for the triage team in the PR thread. Please inform the team whether you -require a "check-only" Crater run, a "build only" Crater run, or a -"build-and-test" Crater run. The difference is primarily in time; -if you're not sure, go for the build-and-test run. If +on the changes introduced by a PR. +If your PR needs a Crater run, leave a comment for the triage team in the PR thread. +Please inform the team whether you +require a "check-only" Crater run, a "build only" Crater run, or a "build-and-test" Crater run. +The difference is primarily in time; +if you're not sure, go for the build-and-test run. +If making changes that will only have an effect at compile-time (e.g., implementing a new trait), then you only need a check run. -Your PR will be enqueued by the triage team and the results will be posted when -they are ready. Check runs will take around ~3-4 days, and the other two taking -5-6 days on average. +Your PR will be enqueued by the triage team and the results will be posted when they are ready. +Check runs will take around ~3-4 days, and the other two taking 5-6 days on average. -While Crater is really useful, it is also important to be aware of a few -caveats: +While Crater is really useful, it is also important to be aware of a few caveats: -- Not all code is on crates.io! There is a lot of code in repos on GitHub and - elsewhere. Also, companies may not wish to publish their code. Thus, a - successful Crater run does not mean there will be no +- Not all code is on crates.io! + There is a lot of code in repos on GitHub and elsewhere. + Also, companies may not wish to publish their code. + Thus, a successful Crater run does not mean there will be no breakage; you still need to be careful. -- Crater only runs Linux builds on x86_64. Thus, other architectures and - platforms are not tested. Critically, this includes Windows. +- Crater only runs Linux builds on x86_64. Thus, other architectures and platforms are not tested. + Critically, this includes Windows. -- Many crates are not tested. This could be for a lot of reasons, including that +- Many crates are not tested. + This could be for a lot of reasons, including that the crate doesn't compile any more (e.g. used old nightly features), has broken or flaky tests, requires network access, or other reasons. From c58288a411123f898a61b1b1e7d90b6fa040bbaa Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 29 Nov 2025 20:00:25 +0200 Subject: [PATCH 133/585] manual formatting improvement --- src/doc/rustc-dev-guide/src/tests/crater.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/crater.md b/src/doc/rustc-dev-guide/src/tests/crater.md index df7e8ef0b7ed..beea10aab770 100644 --- a/src/doc/rustc-dev-guide/src/tests/crater.md +++ b/src/doc/rustc-dev-guide/src/tests/crater.md @@ -21,9 +21,8 @@ Please inform the team whether you require a "check-only" Crater run, a "build only" Crater run, or a "build-and-test" Crater run. The difference is primarily in time; if you're not sure, go for the build-and-test run. -If -making changes that will only have an effect at compile-time (e.g., implementing -a new trait), then you only need a check run. +If making changes that will only have an effect at compile-time +(e.g., implementing a new trait), then you only need a check run. Your PR will be enqueued by the triage team and the results will be posted when they are ready. Check runs will take around ~3-4 days, and the other two taking 5-6 days on average. From bbadb72919e510c3a98cbe303cac2f58e0c5d065 Mon Sep 17 00:00:00 2001 From: Sergio Giro Date: Sat, 29 Nov 2025 18:40:32 +0000 Subject: [PATCH 134/585] while_let_on_iterator: consider all deref adjustments for by_ref --- .../src/loops/while_let_on_iterator.rs | 30 ++++---- tests/ui/while_let_on_iterator.fixed | 73 +++++++++++++++++++ tests/ui/while_let_on_iterator.rs | 73 +++++++++++++++++++ tests/ui/while_let_on_iterator.stderr | 22 +++++- 4 files changed, 182 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index c063e9263ba0..6c95c7b54c50 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -12,7 +12,6 @@ use rustc_hir::{Closure, Expr, ExprKind, HirId, LetStmt, Mutability, UnOp}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter::OnlyBodies; -use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; use rustc_span::Symbol; use rustc_span::symbol::sym; @@ -52,9 +51,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { || !iter_expr_struct.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr_struct, expr) { - make_iterator_snippet(cx, iter_expr, iterator) + make_iterator_snippet(cx, iter_expr, &iterator) } else { - iterator.to_string() + iterator.into_owned() }; span_lint_and_sugg( @@ -358,17 +357,20 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) { } /// Constructs the transformed iterator expression for the suggestion. -/// Returns `iterator.by_ref()` unless the iterator type is a reference to an unsized type, -/// in which case it returns `&mut *iterator`. -fn make_iterator_snippet<'tcx>(cx: &LateContext<'tcx>, iter_expr: &Expr<'tcx>, iterator: impl Into) -> String { - let iterator = iterator.into(); - let ty = cx.typeck_results().expr_ty(iter_expr); - - if let ty::Ref(_, inner_ty, _) = ty.kind() - && !inner_ty.is_sized(cx.tcx, cx.typing_env()) +/// Returns `iterator.by_ref()` unless the last deref adjustment targets an unsized type, +/// in which case it applies all derefs (e.g., `&mut **iterator` or `&mut ***iterator`). +fn make_iterator_snippet<'tcx>(cx: &LateContext<'tcx>, iter_expr: &Expr<'tcx>, iterator: &str) -> String { + if let Some((n, adjust)) = cx + .typeck_results() + .expr_adjustments(iter_expr) + .iter() + .take_while(|x| matches!(x.kind, Adjust::Deref(_))) + .enumerate() + .last() + && !adjust.target.is_sized(cx.tcx, cx.typing_env()) { - return format!("&mut *{iterator}"); + format!("&mut {:*(T); + impl core::ops::Deref for S { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl core::ops::DerefMut for S { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + fn f(mut x: S>>) { + for _ in &mut ***x {} + //~^ while_let_on_iterator + } +} + +fn issue16089_nested_derefs_last_not_sized() { + struct WithSize(T); + impl core::ops::Deref for WithSize { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl core::ops::DerefMut for WithSize { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + // The suggestion must use `&mut **x`. Using `x.by_ref()` doesn't work in this + // case, since the last type adjustment for `x` in the expression `x.next()` is + // to dereference a `?Sized` trait. + fn f(mut x: WithSize<&mut dyn Iterator>) { + for _ in &mut **x {} + //~^ while_let_on_iterator + } +} + +fn issue16089_nested_derefs_last_sized() { + struct NoSize(T); + impl core::ops::Deref for NoSize { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl core::ops::DerefMut for NoSize { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct SizedIter {} + + impl Iterator for SizedIter { + type Item = u32; + fn next(&mut self) -> Option { + Some(0) + } + } + + // We want the suggestion to be `x.by_ref()`. It works in this case since the last type + // adjustment for `x` in the expression `x.next()` is to dereference a Sized type. + fn f(mut x: NoSize>) { + for _ in x.by_ref() {} + //~^ while_let_on_iterator + } +} + fn main() { let mut it = 0..20; for _ in it { diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs index cc65fda6d18f..e1d9e9081e45 100644 --- a/tests/ui/while_let_on_iterator.rs +++ b/tests/ui/while_let_on_iterator.rs @@ -523,6 +523,79 @@ fn use_after_iter(&mut self) {} } } +fn issue16089_nested_derefs() { + struct S(T); + impl core::ops::Deref for S { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl core::ops::DerefMut for S { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + fn f(mut x: S>>) { + while let Some(_) = x.next() {} + //~^ while_let_on_iterator + } +} + +fn issue16089_nested_derefs_last_not_sized() { + struct WithSize(T); + impl core::ops::Deref for WithSize { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl core::ops::DerefMut for WithSize { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + // The suggestion must use `&mut **x`. Using `x.by_ref()` doesn't work in this + // case, since the last type adjustment for `x` in the expression `x.next()` is + // to dereference a `?Sized` trait. + fn f(mut x: WithSize<&mut dyn Iterator>) { + while let Some(_) = x.next() {} + //~^ while_let_on_iterator + } +} + +fn issue16089_nested_derefs_last_sized() { + struct NoSize(T); + impl core::ops::Deref for NoSize { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl core::ops::DerefMut for NoSize { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct SizedIter {} + + impl Iterator for SizedIter { + type Item = u32; + fn next(&mut self) -> Option { + Some(0) + } + } + + // We want the suggestion to be `x.by_ref()`. It works in this case since the last type + // adjustment for `x` in the expression `x.next()` is to dereference a Sized type. + fn f(mut x: NoSize>) { + while let Some(_) = x.next() {} + //~^ while_let_on_iterator + } +} + fn main() { let mut it = 0..20; while let Some(..) = it.next() { diff --git a/tests/ui/while_let_on_iterator.stderr b/tests/ui/while_let_on_iterator.stderr index 21ebc22f699d..cd43d3c17800 100644 --- a/tests/ui/while_let_on_iterator.stderr +++ b/tests/ui/while_let_on_iterator.stderr @@ -176,10 +176,28 @@ LL | while let Some(r) = self.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for r in self.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:528:5 + --> tests/ui/while_let_on_iterator.rs:541:9 + | +LL | while let Some(_) = x.next() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in &mut ***x` + +error: this loop could be written as a `for` loop + --> tests/ui/while_let_on_iterator.rs:563:9 + | +LL | while let Some(_) = x.next() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in &mut **x` + +error: this loop could be written as a `for` loop + --> tests/ui/while_let_on_iterator.rs:594:9 + | +LL | while let Some(_) = x.next() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in x.by_ref()` + +error: this loop could be written as a `for` loop + --> tests/ui/while_let_on_iterator.rs:601:5 | LL | while let Some(..) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` -error: aborting due to 30 previous errors +error: aborting due to 33 previous errors From 9cb6306a48f02d96ee839398e85b17e181fa3844 Mon Sep 17 00:00:00 2001 From: Artur Sulej Date: Sun, 23 Nov 2025 22:51:03 +0100 Subject: [PATCH 135/585] New lint: decimal_bitwise_operands --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + .../src/operators/decimal_bitwise_operands.rs | 76 +++++++ clippy_lints/src/operators/mod.rs | 28 +++ tests/ui/decimal_bitwise_operands.rs | 133 ++++++++++++ tests/ui/decimal_bitwise_operands.stderr | 204 ++++++++++++++++++ 6 files changed, 443 insertions(+) create mode 100644 clippy_lints/src/operators/decimal_bitwise_operands.rs create mode 100644 tests/ui/decimal_bitwise_operands.rs create mode 100644 tests/ui/decimal_bitwise_operands.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 78b81b5b74d6..dc93753a2130 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6280,6 +6280,7 @@ Released 2018-09-13 [`cyclomatic_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cyclomatic_complexity [`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call +[`decimal_bitwise_operands`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_bitwise_operands [`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation [`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const [`default_constructed_unit_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_constructed_unit_structs diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 4a350dca2993..de7d01ce0d1b 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -578,6 +578,7 @@ crate::operators::ASSIGN_OP_PATTERN_INFO, crate::operators::BAD_BIT_MASK_INFO, crate::operators::CMP_OWNED_INFO, + crate::operators::DECIMAL_BITWISE_OPERANDS_INFO, crate::operators::DOUBLE_COMPARISONS_INFO, crate::operators::DURATION_SUBSEC_INFO, crate::operators::EQ_OP_INFO, diff --git a/clippy_lints/src/operators/decimal_bitwise_operands.rs b/clippy_lints/src/operators/decimal_bitwise_operands.rs new file mode 100644 index 000000000000..8511f2151342 --- /dev/null +++ b/clippy_lints/src/operators/decimal_bitwise_operands.rs @@ -0,0 +1,76 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::numeric_literal; +use clippy_utils::numeric_literal::NumericLiteral; +use clippy_utils::source::SpanRangeExt; +use rustc_ast::LitKind; +use rustc_data_structures::packed::Pu128; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::Span; + +use super::DECIMAL_BITWISE_OPERANDS; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, op: BinOpKind, left: &'tcx Expr<'_>, right: &'tcx Expr<'_>) { + if !matches!(op, BinOpKind::BitAnd | BinOpKind::BitOr | BinOpKind::BitXor) { + return; + } + + for expr in [left, right] { + check_expr(cx, expr); + } +} + +fn check_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { + match &expr.kind { + ExprKind::Block(block, _) => { + if let Some(block_expr) = block.expr { + check_expr(cx, block_expr); + } + }, + ExprKind::Cast(cast_expr, _) => { + check_expr(cx, cast_expr); + }, + ExprKind::Unary(_, unary_expr) => { + check_expr(cx, unary_expr); + }, + ExprKind::AddrOf(_, _, addr_of_expr) => { + check_expr(cx, addr_of_expr); + }, + ExprKind::Lit(lit) => { + if let LitKind::Int(Pu128(val), _) = lit.node + && !is_single_digit(val) + && !is_power_of_twoish(val) + && let Some(src) = lit.span.get_source_text(cx) + && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) + && num_lit.is_decimal() + { + emit_lint(cx, lit.span, num_lit.suffix, val); + } + }, + _ => (), + } +} + +fn is_power_of_twoish(val: u128) -> bool { + val.is_power_of_two() || val.wrapping_add(1).is_power_of_two() +} + +fn is_single_digit(val: u128) -> bool { + val <= 9 +} + +fn emit_lint(cx: &LateContext<'_>, span: Span, suffix: Option<&str>, val: u128) { + span_lint_and_help( + cx, + DECIMAL_BITWISE_OPERANDS, + span, + "using decimal literal for bitwise operation", + None, + format!( + "use binary ({}), hex ({}), or octal ({}) notation for better readability", + numeric_literal::format(&format!("{val:#b}"), suffix, false), + numeric_literal::format(&format!("{val:#x}"), suffix, false), + numeric_literal::format(&format!("{val:#o}"), suffix, false), + ), + ); +} diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 8db2cc1d3f57..53b8e9e5d5ae 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -3,6 +3,7 @@ mod bit_mask; mod cmp_owned; mod const_comparisons; +mod decimal_bitwise_operands; mod double_comparison; mod duration_subsec; mod eq_op; @@ -935,6 +936,28 @@ "use of disallowed default division and remainder operations" } +declare_clippy_lint! { + /// ### What it does + /// Checks for decimal literals used as bit masks in bitwise operations. + /// + /// ### Why is this bad? + /// Using decimal literals for bit masks can make the code less readable and obscure the intended bit pattern. + /// Binary, hexadecimal, or octal literals make the bit pattern more explicit and easier to understand at a glance. + /// + /// ### Example + /// ```rust,no_run + /// let a = 14 & 6; // Bit pattern is not immediately clear + /// ``` + /// Use instead: + /// ```rust,no_run + /// let a = 0b1110 & 0b0110; + /// ``` + #[clippy::version = "1.93.0"] + pub DECIMAL_BITWISE_OPERANDS, + pedantic, + "use binary, hex, or octal literals for bitwise operations" +} + pub struct Operators { arithmetic_context: numeric_arithmetic::Context, verbose_bit_mask_threshold: u64, @@ -984,6 +1007,7 @@ pub fn new(conf: &'static Conf) -> Self { MANUAL_IS_MULTIPLE_OF, MANUAL_DIV_CEIL, INVALID_UPCAST_COMPARISONS, + DECIMAL_BITWISE_OPERANDS ]); impl<'tcx> LateLintPass<'tcx> for Operators { @@ -1003,6 +1027,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { needless_bitwise_bool::check(cx, e, op.node, lhs, rhs); manual_midpoint::check(cx, e, op.node, lhs, rhs, self.msrv); manual_is_multiple_of::check(cx, e, op.node, lhs, rhs, self.msrv); + decimal_bitwise_operands::check(cx, op.node, lhs, rhs); } self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs); bit_mask::check(cx, e, op.node, lhs, rhs); @@ -1028,6 +1053,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { }, ExprKind::AssignOp(op, lhs, rhs) => { let bin_op = op.node.into(); + if !e.span.from_expansion() { + decimal_bitwise_operands::check(cx, bin_op, lhs, rhs); + } self.arithmetic_context.check_binary(cx, e, bin_op, lhs, rhs); misrefactored_assign_op::check(cx, e, bin_op, lhs, rhs); modulo_arithmetic::check(cx, e, bin_op, lhs, rhs, false); diff --git a/tests/ui/decimal_bitwise_operands.rs b/tests/ui/decimal_bitwise_operands.rs new file mode 100644 index 000000000000..f1c053bb4358 --- /dev/null +++ b/tests/ui/decimal_bitwise_operands.rs @@ -0,0 +1,133 @@ +#![allow( + clippy::erasing_op, + clippy::no_effect, + clippy::unnecessary_operation, + clippy::unnecessary_cast, + clippy::op_ref +)] +#![warn(clippy::decimal_bitwise_operands)] + +macro_rules! bitwise_op { + ($x:expr, $y:expr) => { + $x & $y; + }; +} + +pub const SOME_CONST: i32 = 12345; + +fn main() { + let mut x = 0; + // BAD: Bitwise operation, decimal literal, one literal + x & 9_8765_4321; //~ decimal_bitwise_operands + x & 100_i32; //~ decimal_bitwise_operands + x | (/* comment */99); //~ decimal_bitwise_operands + x ^ (99); //~ decimal_bitwise_operands + x &= 99; //~ decimal_bitwise_operands + x |= { 99 }; //~ decimal_bitwise_operands + x |= { { 99 } }; //~ decimal_bitwise_operands + x |= { + 0b1000; + 99 //~ decimal_bitwise_operands + }; + x ^= (99); //~ decimal_bitwise_operands + + // BAD: Bitwise operation, decimal literal, two literals + 0b1010 & 99; //~ decimal_bitwise_operands + 0b1010 | (99); //~ decimal_bitwise_operands + 0b1010 ^ (/* comment */99); //~ decimal_bitwise_operands + 99 & 0b1010; //~ decimal_bitwise_operands + (99) | 0b1010; //~ decimal_bitwise_operands + (/* comment */99) ^ 0b1010; //~ decimal_bitwise_operands + 0xD | { 99 }; //~ decimal_bitwise_operands + 88 & 99; + //~^ decimal_bitwise_operands + //~| decimal_bitwise_operands + 37 & 38 & 39; + //~^ decimal_bitwise_operands + //~| decimal_bitwise_operands + //~| decimal_bitwise_operands + + // GOOD: Bitwise operation, binary/hex/octal literal, one literal + x & 0b1010; + x | 0b1010; + x ^ 0b1010; + x &= 0b1010; + x |= 0b1010; + x ^= 0b1010; + x & 0xD; + x & 0o77; + x | 0o123; + x ^ 0o377; + x &= 0o777; + x |= 0o7; + x ^= 0o70; + + // GOOD: Bitwise operation, binary/hex/octal literal, two literals + 0b1010 & 0b1101; + 0xD ^ 0xF; + 0o377 ^ 0o77; + 0b1101 ^ 0xFF; + + // GOOD: Numeric operation, any literal + x += 99; + x -= 0b1010; + x *= 0xD; + 99 + 99; + 0b1010 - 0b1101; + 0xD * 0xD; + + // BAD: Unary, cast and reference, decimal literal + x & !100; //~ decimal_bitwise_operands + x & -100; //~ decimal_bitwise_operands + x & (100 as i32); //~ decimal_bitwise_operands + x & &100; //~ decimal_bitwise_operands + + // GOOD: Unary, cast and reference, non-decimal literal + x & !0b1101; + x & -0xD; + x & (0o333 as i32); + x & &0b1010; + + // GOOD: Bitwise operation, variables only + let y = 0; + x & y; + x &= y; + x + y; + x += y; + + // GOOD: Macro expansion (should be ignored) + bitwise_op!(x, 123); + bitwise_op!(0b1010, 123); + + // GOOD: Using const (should be ignored) + x & SOME_CONST; + x |= SOME_CONST; + + // GOOD: Parenthesized binary/hex literal (should not trigger lint) + x & (0b1111); + x |= (0b1010); + x ^ (/* comment */0b1100); + (0xFF) & x; + + // GOOD: Power of two and power of two minus one + x & 16; // 2^4 + x | (31); // 2^5 - 1 + x ^ 0x40; // 2^6 (hex) + x ^= 7; // 2^3 - 1 + + // GOOD: Bitwise operation, single digit decimal literal + 5 & 9; + x ^ 6; + x ^= 7; + + // GOOD: More complex expressions + (x + 1) & 0xFF; + (x * 2) | (y & 0xF); + (x ^ y) & 0b11110000; + x | (1 << 9); + + // GOOD: Special cases + x & 0; // All bits off + x | !0; // All bits on + x ^ 1; // Toggle LSB +} diff --git a/tests/ui/decimal_bitwise_operands.stderr b/tests/ui/decimal_bitwise_operands.stderr new file mode 100644 index 000000000000..1b2b7bb71b69 --- /dev/null +++ b/tests/ui/decimal_bitwise_operands.stderr @@ -0,0 +1,204 @@ +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:21:9 + | +LL | x & 9_8765_4321; + | ^^^^^^^^^^^ + | + = help: use binary (0b11_1010_1101_1110_0110_1000_1011_0001), hex (0x3ade_68b1), or octal (0o7_267_464_261) notation for better readability + = note: `-D clippy::decimal-bitwise-operands` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::decimal_bitwise_operands)]` + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:22:9 + | +LL | x & 100_i32; + | ^^^^^^^ + | + = help: use binary (0b110_0100_i32), hex (0x0064_i32), or octal (0o144_i32) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:23:23 + | +LL | x | (/* comment */99); + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:24:10 + | +LL | x ^ (99); + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:25:10 + | +LL | x &= 99; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:26:12 + | +LL | x |= { 99 }; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:27:14 + | +LL | x |= { { 99 } }; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:30:9 + | +LL | 99 + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:32:11 + | +LL | x ^= (99); + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:35:14 + | +LL | 0b1010 & 99; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:36:15 + | +LL | 0b1010 | (99); + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:37:28 + | +LL | 0b1010 ^ (/* comment */99); + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:38:5 + | +LL | 99 & 0b1010; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:39:6 + | +LL | (99) | 0b1010; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:40:19 + | +LL | (/* comment */99) ^ 0b1010; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:41:13 + | +LL | 0xD | { 99 }; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:42:5 + | +LL | 88 & 99; + | ^^ + | + = help: use binary (0b101_1000), hex (0x0058), or octal (0o130) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:42:10 + | +LL | 88 & 99; + | ^^ + | + = help: use binary (0b110_0011), hex (0x0063), or octal (0o143) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:45:15 + | +LL | 37 & 38 & 39; + | ^^ + | + = help: use binary (0b10_0111), hex (0x0027), or octal (0o47) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:45:5 + | +LL | 37 & 38 & 39; + | ^^ + | + = help: use binary (0b10_0101), hex (0x0025), or octal (0o45) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:45:10 + | +LL | 37 & 38 & 39; + | ^^ + | + = help: use binary (0b10_0110), hex (0x0026), or octal (0o46) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:80:10 + | +LL | x & !100; + | ^^^ + | + = help: use binary (0b110_0100), hex (0x0064), or octal (0o144) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:81:10 + | +LL | x & -100; + | ^^^ + | + = help: use binary (0b110_0100), hex (0x0064), or octal (0o144) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:82:10 + | +LL | x & (100 as i32); + | ^^^ + | + = help: use binary (0b110_0100), hex (0x0064), or octal (0o144) notation for better readability + +error: using decimal literal for bitwise operation + --> tests/ui/decimal_bitwise_operands.rs:83:10 + | +LL | x & &100; + | ^^^ + | + = help: use binary (0b110_0100), hex (0x0064), or octal (0o144) notation for better readability + +error: aborting due to 25 previous errors + From 41691d33767c9720ac61d1ee18ded0dec9d2151f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 30 Nov 2025 14:05:35 +1100 Subject: [PATCH 136/585] Set `test = false` in the compiletest binary crate The binary crate is a tiny stub; all of the logic and tests should be in the library crate. Disabling unit tests for the binary crate makes `x test compiletest` less noisy. --- src/tools/compiletest/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 6597c3c70f69..c7c23d338e5b 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -9,6 +9,9 @@ doctest = false [[bin]] name = "compiletest" path = "src/bin/main.rs" +# The compiletest binary crate is a tiny stub that shouldn't contain any unit +# tests of its own; all of the logic is in the library crate. +test = false [dependencies] # tidy-alphabetical-start From 49ccc43427c7b391037106c89cf16d1fbe63543e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 28 Nov 2025 16:55:20 +1100 Subject: [PATCH 137/585] Use a set to detect `ignore-` directives handled elsewhere This commit also renames the confusing `NotADirective` outcome, and fuses it with `External` into a single `NotHandledHere` outcome. --- src/tools/compiletest/src/directives/cfg.rs | 68 ++++++++----------- src/tools/compiletest/src/directives/tests.rs | 13 ++++ 2 files changed, 40 insertions(+), 41 deletions(-) diff --git a/src/tools/compiletest/src/directives/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs index 531763c1b3e2..13c85bc3972a 100644 --- a/src/tools/compiletest/src/directives/cfg.rs +++ b/src/tools/compiletest/src/directives/cfg.rs @@ -1,10 +1,25 @@ use std::collections::HashSet; +use std::sync::LazyLock; use crate::common::{CompareMode, Config, Debugger}; use crate::directives::{DirectiveLine, IgnoreDecision}; const EXTRA_ARCHS: &[&str] = &["spirv"]; +const EXTERNAL_IGNORES_LIST: &[&str] = &[ + // tidy-alphabetical-start + "ignore-backends", + "ignore-gdb-version", + "ignore-llvm-version", + "ignore-pass", + // tidy-alphabetical-end +]; + +/// Directive names that begin with `ignore-`, but are disregarded by this +/// module because they are handled elsewhere. +pub(crate) static EXTERNAL_IGNORES_SET: LazyLock> = + LazyLock::new(|| EXTERNAL_IGNORES_LIST.iter().copied().collect()); + pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { let parsed = parse_cfg_name_directive(config, line, "ignore-"); let line = line.display(); @@ -18,8 +33,7 @@ pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> Ignore }, }, MatchOutcome::Invalid => IgnoreDecision::Error { message: format!("invalid line: {line}") }, - MatchOutcome::External => IgnoreDecision::Continue, - MatchOutcome::NotADirective => IgnoreDecision::Continue, + MatchOutcome::NotHandledHere => IgnoreDecision::Continue, } } @@ -38,8 +52,7 @@ pub(super) fn handle_only(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDe }, }, MatchOutcome::Invalid => IgnoreDecision::Error { message: format!("invalid line: {line}") }, - MatchOutcome::External => IgnoreDecision::Continue, - MatchOutcome::NotADirective => IgnoreDecision::Continue, + MatchOutcome::NotHandledHere => IgnoreDecision::Continue, } } @@ -51,9 +64,13 @@ fn parse_cfg_name_directive<'a>( prefix: &str, ) -> ParsedNameDirective<'a> { let Some(name) = line.name.strip_prefix(prefix) else { - return ParsedNameDirective::not_a_directive(); + return ParsedNameDirective::not_handled_here(); }; + if prefix == "ignore-" && EXTERNAL_IGNORES_SET.contains(line.name) { + return ParsedNameDirective::not_handled_here(); + } + // FIXME(Zalathar): This currently allows either a space or a colon, and // treats any "value" after a colon as though it were a remark. // We should instead forbid the colon syntax for these directives. @@ -62,7 +79,7 @@ fn parse_cfg_name_directive<'a>( // Some of the matchers might be "" depending on what the target information is. To avoid // problems we outright reject empty directives. if name.is_empty() { - return ParsedNameDirective::not_a_directive(); + return ParsedNameDirective::not_handled_here(); } let mut outcome = MatchOutcome::Invalid; @@ -256,35 +273,6 @@ macro_rules! condition { message: "when performing tests on dist toolchain" } - if prefix == "ignore-" && outcome == MatchOutcome::Invalid { - // Don't error out for ignore-tidy-* diretives, as those are not handled by compiletest. - if name.starts_with("tidy-") { - outcome = MatchOutcome::External; - } - - // Don't error out for ignore-pass, as that is handled elsewhere. - if name == "pass" { - outcome = MatchOutcome::External; - } - - // Don't error out for ignore-llvm-version, that has a custom syntax and is handled - // elsewhere. - if name == "llvm-version" { - outcome = MatchOutcome::External; - } - - // Don't error out for ignore-llvm-version, that has a custom syntax and is handled - // elsewhere. - if name == "gdb-version" { - outcome = MatchOutcome::External; - } - - // Don't error out for ignore-backends,as it is handled elsewhere. - if name == "backends" { - outcome = MatchOutcome::External; - } - } - ParsedNameDirective { name: Some(name), comment: comment.map(|c| c.trim().trim_start_matches('-').trim()), @@ -303,12 +291,12 @@ pub(super) struct ParsedNameDirective<'a> { } impl ParsedNameDirective<'_> { - fn not_a_directive() -> Self { + fn not_handled_here() -> Self { Self { name: None, pretty_reason: None, comment: None, - outcome: MatchOutcome::NotADirective, + outcome: MatchOutcome::NotHandledHere, } } } @@ -321,10 +309,8 @@ pub(super) enum MatchOutcome { Match, /// The directive was invalid. Invalid, - /// The directive is handled by other parts of our tooling. - External, - /// The line is not actually a directive. - NotADirective, + /// The directive should be ignored by this module, because it is handled elsewhere. + NotHandledHere, } trait CustomContains { diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index bb8002de391e..90e2cb77e304 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -26,6 +26,19 @@ fn handler_names() { ); } +#[test] +fn external_ignores() { + let unknown_names = directives::cfg::EXTERNAL_IGNORES_SET + .difference(&KNOWN_DIRECTIVE_NAMES_SET) + .into_iter() + .collect::>(); + + assert!( + unknown_names.is_empty(), + "Directive names not in `directive_names.rs`: {unknown_names:#?}" + ); +} + fn make_test_description( config: &Config, name: String, From daf592985ef14a4a053ac1165fd5efb921154344 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 30 Nov 2025 04:57:57 +0000 Subject: [PATCH 138/585] Prepare for merging from rust-lang/rust This updates the rust-version file to 3ff30e7eafc1da7104c3960187d17939172428ed. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 1efb31457bab..5c4de1da0312 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -1eb0657f78777f0b4d6bcc49c126d5d35212cae5 +3ff30e7eafc1da7104c3960187d17939172428ed From ad7ba50e528c512f3714348ed46c4b41d4f17c9c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Nov 2025 10:12:38 +0100 Subject: [PATCH 139/585] bless genmc tests --- .../tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr | 4 ++-- src/tools/miri/tests/genmc/pass/std/arc.check_count.stderr | 6 +++--- src/tools/miri/tests/genmc/pass/std/arc.try_upgrade.stderr | 6 +++--- src/tools/miri/tests/genmc/pass/std/empty_main.stderr | 2 +- .../miri/tests/genmc/pass/std/spawn_std_threads.stderr | 6 +++--- src/tools/miri/tests/genmc/pass/std/thread_locals.stderr | 6 +++--- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr b/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr index e74b76ea415e..e2148bedd318 100644 --- a/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr +++ b/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr @@ -18,7 +18,7 @@ LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquir = note: inside `std::sys::env::PLATFORM::getenv` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC = note: inside `std::env::_var_os` at RUSTLIB/std/src/env.rs:LL:CC = note: inside `std::env::var_os::<&str>` at RUSTLIB/std/src/env.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC note: inside `miri_start` --> tests/genmc/fail/shims/mutex_diff_thread_unlock.rs:LL:CC | @@ -48,7 +48,7 @@ LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquir = note: inside `std::sys::env::PLATFORM::getenv` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC = note: inside `std::env::_var_os` at RUSTLIB/std/src/env.rs:LL:CC = note: inside `std::env::var_os::<&str>` at RUSTLIB/std/src/env.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC note: inside `miri_start` --> tests/genmc/fail/shims/mutex_diff_thread_unlock.rs:LL:CC | diff --git a/src/tools/miri/tests/genmc/pass/std/arc.check_count.stderr b/src/tools/miri/tests/genmc/pass/std/arc.check_count.stderr index 695aa3f5aeaf..fdbb9eff2faa 100644 --- a/src/tools/miri/tests/genmc/pass/std/arc.check_count.stderr +++ b/src/tools/miri/tests/genmc/pass/std/arc.check_count.stderr @@ -1,6 +1,6 @@ Running GenMC Verification... warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/std/src/thread/mod.rs:LL:CC + --> RUSTLIB/std/src/thread/id.rs:LL:CC | LL | match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code @@ -46,7 +46,7 @@ LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquir | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC note: inside `main` --> tests/genmc/pass/std/arc.rs:LL:CC | @@ -67,7 +67,7 @@ LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquir | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC note: inside `main` --> tests/genmc/pass/std/arc.rs:LL:CC | diff --git a/src/tools/miri/tests/genmc/pass/std/arc.try_upgrade.stderr b/src/tools/miri/tests/genmc/pass/std/arc.try_upgrade.stderr index 8609c2c5c864..a5423f9a398b 100644 --- a/src/tools/miri/tests/genmc/pass/std/arc.try_upgrade.stderr +++ b/src/tools/miri/tests/genmc/pass/std/arc.try_upgrade.stderr @@ -1,6 +1,6 @@ Running GenMC Verification... warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/std/src/thread/mod.rs:LL:CC + --> RUSTLIB/std/src/thread/id.rs:LL:CC | LL | match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code @@ -46,7 +46,7 @@ LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquir | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC note: inside `main` --> tests/genmc/pass/std/arc.rs:LL:CC | @@ -67,7 +67,7 @@ LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquir | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC note: inside `main` --> tests/genmc/pass/std/arc.rs:LL:CC | diff --git a/src/tools/miri/tests/genmc/pass/std/empty_main.stderr b/src/tools/miri/tests/genmc/pass/std/empty_main.stderr index b1413ee6d574..de07943b0d8d 100644 --- a/src/tools/miri/tests/genmc/pass/std/empty_main.stderr +++ b/src/tools/miri/tests/genmc/pass/std/empty_main.stderr @@ -1,6 +1,6 @@ Running GenMC Verification... warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/std/src/thread/mod.rs:LL:CC + --> RUSTLIB/std/src/thread/id.rs:LL:CC | LL | match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code diff --git a/src/tools/miri/tests/genmc/pass/std/spawn_std_threads.stderr b/src/tools/miri/tests/genmc/pass/std/spawn_std_threads.stderr index 87d3c60ef02e..701934a7cd7f 100644 --- a/src/tools/miri/tests/genmc/pass/std/spawn_std_threads.stderr +++ b/src/tools/miri/tests/genmc/pass/std/spawn_std_threads.stderr @@ -1,6 +1,6 @@ Running GenMC Verification... warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/std/src/thread/mod.rs:LL:CC + --> RUSTLIB/std/src/thread/id.rs:LL:CC | LL | match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code @@ -20,7 +20,7 @@ LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquir | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC note: inside closure --> tests/genmc/pass/std/spawn_std_threads.rs:LL:CC | @@ -52,7 +52,7 @@ LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquir | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC note: inside closure --> tests/genmc/pass/std/spawn_std_threads.rs:LL:CC | diff --git a/src/tools/miri/tests/genmc/pass/std/thread_locals.stderr b/src/tools/miri/tests/genmc/pass/std/thread_locals.stderr index 91d2f5daa146..fd6538fd70fa 100644 --- a/src/tools/miri/tests/genmc/pass/std/thread_locals.stderr +++ b/src/tools/miri/tests/genmc/pass/std/thread_locals.stderr @@ -1,6 +1,6 @@ Running GenMC Verification... warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/std/src/thread/mod.rs:LL:CC + --> RUSTLIB/std/src/thread/id.rs:LL:CC | LL | match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code @@ -20,7 +20,7 @@ LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquir | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC note: inside `main` --> tests/genmc/pass/std/thread_locals.rs:LL:CC | @@ -42,7 +42,7 @@ LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquir | = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC note: inside `main` --> tests/genmc/pass/std/thread_locals.rs:LL:CC | From 8eb411b0981c0a4b8c21c16b5e1fad94a2dcec5f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Nov 2025 10:39:56 +0100 Subject: [PATCH 140/585] use fully deterministic concurrency for while-queued tests --- .../concurrency/libc_pthread_mutex_read_while_queued.rs | 2 +- .../concurrency/libc_pthread_mutex_write_while_queued.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.rs index 555d765d24ba..418259ca4e8e 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.rs @@ -1,5 +1,5 @@ //@ignore-target: windows # No pthreads on Windows -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency use std::cell::UnsafeCell; use std::sync::atomic::*; diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.rs index 00274f7080f3..0778f06ff6fe 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.rs @@ -1,5 +1,5 @@ //@ignore-target: windows # No pthreads on Windows -//@compile-flags: -Zmiri-fixed-schedule +//@compile-flags: -Zmiri-deterministic-concurrency use std::cell::UnsafeCell; use std::sync::atomic::*; From d4af0f07729e1ce75e35f6c15ae5bab0830db760 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sun, 30 Nov 2025 20:29:26 +0900 Subject: [PATCH 141/585] Fix indent in E0591.md --- .../rustc_error_codes/src/error_codes/E0591.md | 16 ++++++++-------- tests/ui/explain/basic.stdout | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0591.md b/compiler/rustc_error_codes/src/error_codes/E0591.md index 6ed8370e8c1c..c32aa95a3bfd 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0591.md +++ b/compiler/rustc_error_codes/src/error_codes/E0591.md @@ -62,14 +62,14 @@ This pattern should be rewritten. There are a few possible ways to do this: and do the cast in the fn body (the preferred option) - cast the fn item of a fn pointer before calling transmute, as shown here: - ``` - # extern "C" fn foo(_: Box) {} - # use std::mem::transmute; - # unsafe { - let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_)); - let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too - # } - ``` +``` +# extern "C" fn foo(_: Box) {} +# use std::mem::transmute; +# unsafe { +let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_)); +let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too +# } +``` The same applies to transmutes to `*mut fn()`, which were observed in practice. Note though that use of this type is generally incorrect. diff --git a/tests/ui/explain/basic.stdout b/tests/ui/explain/basic.stdout index ef1d866c3ff3..6377768d4785 100644 --- a/tests/ui/explain/basic.stdout +++ b/tests/ui/explain/basic.stdout @@ -56,10 +56,10 @@ This pattern should be rewritten. There are a few possible ways to do this: and do the cast in the fn body (the preferred option) - cast the fn item of a fn pointer before calling transmute, as shown here: - ``` - let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_)); - let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too - ``` +``` +let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_)); +let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too +``` The same applies to transmutes to `*mut fn()`, which were observed in practice. Note though that use of this type is generally incorrect. From a6162c3dd9e8b620c277f6b90df1ed3f669864f8 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 3 Sep 2025 15:53:13 +0200 Subject: [PATCH 142/585] add `ptr_offset_by_literal` lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 37 +++++ .../src/methods/ptr_offset_by_literal.rs | 138 +++++++++++++++++ tests/ui/borrow_as_ptr.fixed | 2 +- tests/ui/borrow_as_ptr.rs | 2 +- tests/ui/crashes/ice-4579.rs | 2 +- tests/ui/ptr_offset_by_literal.fixed | 50 +++++++ tests/ui/ptr_offset_by_literal.rs | 50 +++++++ tests/ui/ptr_offset_by_literal.stderr | 141 ++++++++++++++++++ tests/ui/zero_offset.rs | 2 +- 11 files changed, 422 insertions(+), 4 deletions(-) create mode 100644 clippy_lints/src/methods/ptr_offset_by_literal.rs create mode 100644 tests/ui/ptr_offset_by_literal.fixed create mode 100644 tests/ui/ptr_offset_by_literal.rs create mode 100644 tests/ui/ptr_offset_by_literal.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cb2755be0ee..434cfff20510 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6764,6 +6764,7 @@ Released 2018-09-13 [`ptr_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr [`ptr_cast_constness`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_cast_constness [`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq +[`ptr_offset_by_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_by_literal [`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names [`pub_underscore_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index a754eea31165..1414e6076364 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -443,6 +443,7 @@ crate::methods::OR_THEN_UNWRAP_INFO, crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO, crate::methods::PATH_ENDS_WITH_EXT_INFO, + crate::methods::PTR_OFFSET_BY_LITERAL_INFO, crate::methods::PTR_OFFSET_WITH_CAST_INFO, crate::methods::RANGE_ZIP_WITH_LEN_INFO, crate::methods::READONLY_WRITE_LOCK_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c22b0a548e3d..e6b9589233c9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -94,6 +94,7 @@ mod or_then_unwrap; mod path_buf_push_overwrite; mod path_ends_with_ext; +mod ptr_offset_by_literal; mod ptr_offset_with_cast; mod range_zip_with_len; mod read_line_without_trim; @@ -1728,6 +1729,40 @@ "Check for offset calculations on raw pointers to zero-sized types" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of the `offset` pointer method with an integer + /// literal. + /// + /// ### Why is this bad? + /// The `add` and `sub` methods more accurately express the intent. + /// + /// ### Example + /// ```no_run + /// let vec = vec![b'a', b'b', b'c']; + /// let ptr = vec.as_ptr(); + /// + /// unsafe { + /// ptr.offset(-8); + /// } + /// ``` + /// + /// Could be written: + /// + /// ```no_run + /// let vec = vec![b'a', b'b', b'c']; + /// let ptr = vec.as_ptr(); + /// + /// unsafe { + /// ptr.sub(8); + /// } + /// ``` + #[clippy::version = "1.92.0"] + pub PTR_OFFSET_BY_LITERAL, + pedantic, + "unneeded pointer offset" +} + declare_clippy_lint! { /// ### What it does /// Checks for usage of the `offset` pointer method with a `usize` casted to an @@ -4803,6 +4838,7 @@ pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self { UNINIT_ASSUMED_INIT, MANUAL_SATURATING_ARITHMETIC, ZST_OFFSET, + PTR_OFFSET_BY_LITERAL, PTR_OFFSET_WITH_CAST, FILETYPE_IS_FILE, OPTION_AS_REF_DEREF, @@ -5426,6 +5462,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { zst_offset::check(cx, expr, recv); ptr_offset_with_cast::check(cx, name, expr, recv, arg, self.msrv); + ptr_offset_by_literal::check(cx, expr, self.msrv); }, (sym::ok_or_else, [arg]) => { unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"); diff --git a/clippy_lints/src/methods/ptr_offset_by_literal.rs b/clippy_lints/src/methods/ptr_offset_by_literal.rs new file mode 100644 index 000000000000..b5d2add65cf1 --- /dev/null +++ b/clippy_lints/src/methods/ptr_offset_by_literal.rs @@ -0,0 +1,138 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::SpanRangeExt; +use clippy_utils::sym; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, Lit, UnOp}; +use rustc_lint::LateContext; +use std::cmp::Ordering; +use std::fmt; + +use super::PTR_OFFSET_BY_LITERAL; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Msrv) { + // `pointer::add` and `pointer::wrapping_add` are only stable since 1.26.0. These functions + // became const-stable in 1.61.0, the same version that `pointer::offset` became const-stable. + if !msrv.meets(cx, msrvs::POINTER_ADD_SUB_METHODS) { + return; + } + + let ExprKind::MethodCall(method_name, recv, [arg_expr], _) = expr.kind else { + return; + }; + + let method = match method_name.ident.name { + sym::offset => Method::Offset, + sym::wrapping_offset => Method::WrappingOffset, + _ => return, + }; + + if !cx.typeck_results().expr_ty_adjusted(recv).is_raw_ptr() { + return; + } + + // Check if the argument to the method call is a (negated) literal. + let Some((literal, literal_text)) = expr_as_literal(cx, arg_expr) else { + return; + }; + + match method.suggestion(literal) { + None => { + let msg = format!("use of `{method}` with zero"); + span_lint_and_then(cx, PTR_OFFSET_BY_LITERAL, expr.span, msg, |diag| { + diag.span_suggestion( + expr.span.with_lo(recv.span.hi()), + format!("remove the call to `{method}`"), + String::new(), + Applicability::MachineApplicable, + ); + }); + }, + Some(method_suggestion) => { + let msg = format!("use of `{method}` with a literal"); + span_lint_and_then(cx, PTR_OFFSET_BY_LITERAL, expr.span, msg, |diag| { + diag.multipart_suggestion( + format!("use `{method_suggestion}` instead"), + vec![ + (method_name.ident.span, method_suggestion.to_string()), + (arg_expr.span, literal_text), + ], + Applicability::MachineApplicable, + ); + }); + }, + } +} + +fn get_literal_bits<'tcx>(expr: &'tcx Expr<'tcx>) -> Option { + match expr.kind { + ExprKind::Lit(Lit { + node: LitKind::Int(packed_u128, _), + .. + }) => Some(packed_u128.get()), + _ => None, + } +} + +// If the given expression is a (negated) literal, return its value. +fn expr_as_literal<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<(i128, String)> { + if let Some(literal_bits) = get_literal_bits(expr) { + // The value must fit in a isize, so we can't have overflow here. + return Some((literal_bits.cast_signed(), format_isize_literal(cx, expr)?)); + } + + if let ExprKind::Unary(UnOp::Neg, inner) = expr.kind + && let Some(literal_bits) = get_literal_bits(inner) + { + return Some((-(literal_bits.cast_signed()), format_isize_literal(cx, inner)?)); + } + + None +} + +fn format_isize_literal<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option { + let text = expr.span.get_source_text(cx)?; + let text = peel_parens_str(&text); + Some(text.trim_end_matches("isize").trim_end_matches('_').to_string()) +} + +fn peel_parens_str(snippet: &str) -> &str { + let mut s = snippet.trim(); + while let Some(next) = s.strip_prefix("(").and_then(|suf| suf.strip_suffix(")")) { + s = next.trim(); + } + s +} + +#[derive(Copy, Clone)] +enum Method { + Offset, + WrappingOffset, +} + +impl Method { + fn suggestion(self, literal: i128) -> Option<&'static str> { + match Ord::cmp(&literal, &0) { + Ordering::Greater => match self { + Method::Offset => Some("add"), + Method::WrappingOffset => Some("wrapping_add"), + }, + // `ptr.offset(0)` is equivalent to `ptr`, so no adjustment is needed + Ordering::Equal => None, + Ordering::Less => match self { + Method::Offset => Some("sub"), + Method::WrappingOffset => Some("wrapping_sub"), + }, + } + } +} + +impl fmt::Display for Method { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Offset => write!(f, "offset"), + Self::WrappingOffset => write!(f, "wrapping_offset"), + } + } +} diff --git a/tests/ui/borrow_as_ptr.fixed b/tests/ui/borrow_as_ptr.fixed index bfe826508f36..a4689a7840ce 100644 --- a/tests/ui/borrow_as_ptr.fixed +++ b/tests/ui/borrow_as_ptr.fixed @@ -1,6 +1,6 @@ //@aux-build:proc_macros.rs #![warn(clippy::borrow_as_ptr)] -#![allow(clippy::useless_vec)] +#![allow(clippy::useless_vec, clippy::ptr_offset_by_literal)] extern crate proc_macros; diff --git a/tests/ui/borrow_as_ptr.rs b/tests/ui/borrow_as_ptr.rs index ce248f157c6e..d7468f37a3a4 100644 --- a/tests/ui/borrow_as_ptr.rs +++ b/tests/ui/borrow_as_ptr.rs @@ -1,6 +1,6 @@ //@aux-build:proc_macros.rs #![warn(clippy::borrow_as_ptr)] -#![allow(clippy::useless_vec)] +#![allow(clippy::useless_vec, clippy::ptr_offset_by_literal)] extern crate proc_macros; diff --git a/tests/ui/crashes/ice-4579.rs b/tests/ui/crashes/ice-4579.rs index 14c8113e315b..a2592e74c66d 100644 --- a/tests/ui/crashes/ice-4579.rs +++ b/tests/ui/crashes/ice-4579.rs @@ -1,6 +1,6 @@ //@ check-pass -#![allow(clippy::single_match)] +#![allow(clippy::single_match, clippy::ptr_offset_by_literal)] use std::ptr; diff --git a/tests/ui/ptr_offset_by_literal.fixed b/tests/ui/ptr_offset_by_literal.fixed new file mode 100644 index 000000000000..bd9e41def938 --- /dev/null +++ b/tests/ui/ptr_offset_by_literal.fixed @@ -0,0 +1,50 @@ +#![warn(clippy::ptr_offset_by_literal)] +#![allow(clippy::inconsistent_digit_grouping)] + +fn main() { + let arr = [b'a', b'b', b'c']; + let ptr = arr.as_ptr(); + + let var = 32; + const CONST: isize = 42; + + unsafe { + let _ = ptr; + //~^ ptr_offset_by_literal + let _ = ptr; + //~^ ptr_offset_by_literal + + let _ = ptr.add(5); + //~^ ptr_offset_by_literal + let _ = ptr.sub(5); + //~^ ptr_offset_by_literal + + let _ = ptr.offset(var); + let _ = ptr.offset(CONST); + + let _ = ptr.wrapping_add(5); + //~^ ptr_offset_by_literal + let _ = ptr.wrapping_sub(5); + //~^ ptr_offset_by_literal + + let _ = ptr.sub(5); + //~^ ptr_offset_by_literal + let _ = ptr.wrapping_sub(5); + //~^ ptr_offset_by_literal + + // isize::MAX and isize::MIN on 32-bit systems. + let _ = ptr.add(2_147_483_647); + //~^ ptr_offset_by_literal + let _ = ptr.sub(2_147_483_648); + //~^ ptr_offset_by_literal + + let _ = ptr.add(5_0); + //~^ ptr_offset_by_literal + let _ = ptr.sub(5_0); + //~^ ptr_offset_by_literal + + macro_rules! offs { { $e:expr, $offs:expr } => { $e.offset($offs) }; } + offs!(ptr, 6); + offs!(ptr, var); + } +} diff --git a/tests/ui/ptr_offset_by_literal.rs b/tests/ui/ptr_offset_by_literal.rs new file mode 100644 index 000000000000..b8e3f9b26c68 --- /dev/null +++ b/tests/ui/ptr_offset_by_literal.rs @@ -0,0 +1,50 @@ +#![warn(clippy::ptr_offset_by_literal)] +#![allow(clippy::inconsistent_digit_grouping)] + +fn main() { + let arr = [b'a', b'b', b'c']; + let ptr = arr.as_ptr(); + + let var = 32; + const CONST: isize = 42; + + unsafe { + let _ = ptr.offset(0); + //~^ ptr_offset_by_literal + let _ = ptr.offset(-0); + //~^ ptr_offset_by_literal + + let _ = ptr.offset(5); + //~^ ptr_offset_by_literal + let _ = ptr.offset(-5); + //~^ ptr_offset_by_literal + + let _ = ptr.offset(var); + let _ = ptr.offset(CONST); + + let _ = ptr.wrapping_offset(5isize); + //~^ ptr_offset_by_literal + let _ = ptr.wrapping_offset(-5isize); + //~^ ptr_offset_by_literal + + let _ = ptr.offset(-(5)); + //~^ ptr_offset_by_literal + let _ = ptr.wrapping_offset(-(5)); + //~^ ptr_offset_by_literal + + // isize::MAX and isize::MIN on 32-bit systems. + let _ = ptr.offset(2_147_483_647isize); + //~^ ptr_offset_by_literal + let _ = ptr.offset(-2_147_483_648isize); + //~^ ptr_offset_by_literal + + let _ = ptr.offset(5_0__isize); + //~^ ptr_offset_by_literal + let _ = ptr.offset(-5_0__isize); + //~^ ptr_offset_by_literal + + macro_rules! offs { { $e:expr, $offs:expr } => { $e.offset($offs) }; } + offs!(ptr, 6); + offs!(ptr, var); + } +} diff --git a/tests/ui/ptr_offset_by_literal.stderr b/tests/ui/ptr_offset_by_literal.stderr new file mode 100644 index 000000000000..f85fef87d55f --- /dev/null +++ b/tests/ui/ptr_offset_by_literal.stderr @@ -0,0 +1,141 @@ +error: use of `offset` with zero + --> tests/ui/ptr_offset_by_literal.rs:12:17 + | +LL | let _ = ptr.offset(0); + | ^^^---------- + | | + | help: remove the call to `offset` + | + = note: `-D clippy::ptr-offset-by-literal` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ptr_offset_by_literal)]` + +error: use of `offset` with zero + --> tests/ui/ptr_offset_by_literal.rs:14:17 + | +LL | let _ = ptr.offset(-0); + | ^^^----------- + | | + | help: remove the call to `offset` + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:17:17 + | +LL | let _ = ptr.offset(5); + | ^^^^^^^^^^^^^ + | +help: use `add` instead + | +LL - let _ = ptr.offset(5); +LL + let _ = ptr.add(5); + | + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:19:17 + | +LL | let _ = ptr.offset(-5); + | ^^^^^^^^^^^^^^ + | +help: use `sub` instead + | +LL - let _ = ptr.offset(-5); +LL + let _ = ptr.sub(5); + | + +error: use of `wrapping_offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:25:17 + | +LL | let _ = ptr.wrapping_offset(5isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `wrapping_add` instead + | +LL - let _ = ptr.wrapping_offset(5isize); +LL + let _ = ptr.wrapping_add(5); + | + +error: use of `wrapping_offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:27:17 + | +LL | let _ = ptr.wrapping_offset(-5isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `wrapping_sub` instead + | +LL - let _ = ptr.wrapping_offset(-5isize); +LL + let _ = ptr.wrapping_sub(5); + | + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:30:17 + | +LL | let _ = ptr.offset(-(5)); + | ^^^^^^^^^^^^^^^^ + | +help: use `sub` instead + | +LL - let _ = ptr.offset(-(5)); +LL + let _ = ptr.sub(5); + | + +error: use of `wrapping_offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:32:17 + | +LL | let _ = ptr.wrapping_offset(-(5)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `wrapping_sub` instead + | +LL - let _ = ptr.wrapping_offset(-(5)); +LL + let _ = ptr.wrapping_sub(5); + | + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:36:17 + | +LL | let _ = ptr.offset(2_147_483_647isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `add` instead + | +LL - let _ = ptr.offset(2_147_483_647isize); +LL + let _ = ptr.add(2_147_483_647); + | + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:38:17 + | +LL | let _ = ptr.offset(-2_147_483_648isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `sub` instead + | +LL - let _ = ptr.offset(-2_147_483_648isize); +LL + let _ = ptr.sub(2_147_483_648); + | + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:41:17 + | +LL | let _ = ptr.offset(5_0__isize); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `add` instead + | +LL - let _ = ptr.offset(5_0__isize); +LL + let _ = ptr.add(5_0); + | + +error: use of `offset` with a literal + --> tests/ui/ptr_offset_by_literal.rs:43:17 + | +LL | let _ = ptr.offset(-5_0__isize); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `sub` instead + | +LL - let _ = ptr.offset(-5_0__isize); +LL + let _ = ptr.sub(5_0); + | + +error: aborting due to 12 previous errors + diff --git a/tests/ui/zero_offset.rs b/tests/ui/zero_offset.rs index bedb09536c53..5a9c3ac9248f 100644 --- a/tests/ui/zero_offset.rs +++ b/tests/ui/zero_offset.rs @@ -1,4 +1,4 @@ -#[allow(clippy::borrow_as_ptr)] +#[allow(clippy::borrow_as_ptr, clippy::ptr_offset_by_literal)] fn main() { unsafe { let m = &mut () as *mut (); From 74d12e85983f2e9883c4b577a1f6de6db9e26278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 11 Oct 2025 13:54:57 +0200 Subject: [PATCH 143/585] Move more early buffered lints to dyn lint diagnostics (5/N) --- compiler/rustc_lint/messages.ftl | 8 ---- compiler/rustc_lint/src/early/diagnostics.rs | 18 --------- compiler/rustc_lint/src/lints.rs | 38 ------------------ compiler/rustc_lint_defs/src/lib.rs | 10 +---- compiler/rustc_resolve/messages.ftl | 9 +++++ compiler/rustc_resolve/src/check_unused.rs | 6 ++- compiler/rustc_resolve/src/errors.rs | 41 +++++++++++++++++++- compiler/rustc_resolve/src/lib.rs | 3 +- compiler/rustc_resolve/src/macros.rs | 10 ++--- 9 files changed, 59 insertions(+), 84 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index df04d135600a..82b7b1fd125e 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -257,9 +257,6 @@ lint_expectation = this lint expectation is unfulfilled .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message .rationale = {$rationale} -lint_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition - .suggestion = convert it to a `use` - lint_for_loops_over_fallibles = for loop over {$article} `{$ref_prefix}{$ty}`. This is more readably written as an `if let` statement .suggestion = consider using `if let` to clear intent @@ -467,9 +464,6 @@ lint_lintpass_by_hand = implementing `LintPass` by hand lint_macro_expr_fragment_specifier_2024_migration = the `expr` fragment specifier will accept more expressions in the 2024 edition .suggestion = to keep the existing behavior, use the `expr_2021` fragment specifier -lint_macro_is_private = macro `{$ident}` is private - -lint_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used lint_malformed_attribute = malformed lint attribute input @@ -962,8 +956,6 @@ lint_unused_imports = {$num_snippets -> lint_unused_lifetime = lifetime parameter `{$ident}` never used .suggestion = elide the unused lifetime -lint_unused_macro_definition = unused macro definition: `{$name}` - lint_unused_op = unused {$op} that must be used .label = the {$op} produces a value .suggestion = use `let _ = ...` to ignore the resulting value diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 9029ee044711..16f50933eb0d 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -251,12 +251,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span } => { - let suggestion_span = vis_span.between(ident_span); - let code = if vis_span.is_empty() { "use " } else { " use " }; - - lints::ExternCrateNotIdiomatic { span: suggestion_span, code }.decorate_lint(diag); - } BuiltinLintDiag::AmbiguousGlobImports { diag: ambiguity } => { lints::AmbiguousGlobImports { ambiguity }.decorate_lint(diag); } @@ -332,18 +326,6 @@ pub fn decorate_builtin_lint( lints::PrivateExternCrateReexport { ident, sugg: extern_crate_span.shrink_to_lo() } .decorate_lint(diag); } - BuiltinLintDiag::MacroIsPrivate(ident) => { - lints::MacroIsPrivate { ident }.decorate_lint(diag); - } - BuiltinLintDiag::UnusedMacroDefinition(name) => { - lints::UnusedMacroDefinition { name }.decorate_lint(diag); - } - BuiltinLintDiag::MacroRuleNeverUsed(n, name) => { - lints::MacroRuleNeverUsed { n: n + 1, name }.decorate_lint(diag); - } - BuiltinLintDiag::UnstableFeature(msg) => { - lints::UnstableFeature { msg }.decorate_lint(diag); - } BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag) } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 096299c16e0f..c346e50033a4 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2583,35 +2583,6 @@ pub(crate) struct PrivateExternCrateReexport { pub sugg: Span, } -#[derive(LintDiagnostic)] -#[diag(lint_macro_is_private)] -pub(crate) struct MacroIsPrivate { - pub ident: Ident, -} - -#[derive(LintDiagnostic)] -#[diag(lint_unused_macro_definition)] -pub(crate) struct UnusedMacroDefinition { - pub name: Symbol, -} - -#[derive(LintDiagnostic)] -#[diag(lint_macro_rule_never_used)] -pub(crate) struct MacroRuleNeverUsed { - pub n: usize, - pub name: Symbol, -} - -pub(crate) struct UnstableFeature { - pub msg: DiagMessage, -} - -impl<'a> LintDiagnostic<'a, ()> for UnstableFeature { - fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { - diag.primary_message(self.msg); - } -} - #[derive(LintDiagnostic)] #[diag(lint_unused_crate_dependency)] #[help] @@ -2893,15 +2864,6 @@ pub(crate) struct NamedArgumentUsedPositionally { pub named_arg_name: String, } -#[derive(LintDiagnostic)] -#[diag(lint_extern_crate_not_idiomatic)] -pub(crate) struct ExternCrateNotIdiomatic { - #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")] - pub span: Span, - - pub code: &'static str, -} - // FIXME: make this translatable pub(crate) struct AmbiguousGlobImports { pub ambiguity: AmbiguityErrorDiag, diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index ec26c35ffdc9..657c2671db41 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -6,7 +6,7 @@ use rustc_data_structures::stable_hasher::{ HashStable, StableCompare, StableHasher, ToStableHashKey, }; -use rustc_error_messages::{DiagArgValue, DiagMessage, IntoDiagArg, MultiSpan}; +use rustc_error_messages::{DiagArgValue, IntoDiagArg, MultiSpan}; use rustc_hir_id::{HashStableContext, HirId, ItemLocalId}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::def_id::DefPathHash; @@ -678,10 +678,6 @@ pub enum BuiltinLintDiag { /// Indicates if the named argument is used as a width/precision for formatting is_formatting_arg: bool, }, - ExternCrateNotIdiomatic { - vis_span: Span, - ident_span: Span, - }, AmbiguousGlobImports { diag: AmbiguityErrorDiag, }, @@ -731,10 +727,6 @@ pub enum BuiltinLintDiag { source: Ident, extern_crate_span: Span, }, - MacroIsPrivate(Ident), - UnusedMacroDefinition(Symbol), - MacroRuleNeverUsed(usize, Symbol), - UnstableFeature(DiagMessage), UnusedCrateDependency { extern_crate: Symbol, local_crate: Symbol, diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 1569c175948e..eb49ca33aa74 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -146,6 +146,9 @@ resolve_explicit_unsafe_traits = resolve_extern_crate_loading_macro_not_at_crate_root = an `extern crate` loading macros must be at the crate root +resolve_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition + .suggestion = convert it to a `use` + resolve_extern_crate_self_requires_renaming = `extern crate self;` requires renaming .suggestion = rename the `self` crate to be able to import it @@ -280,6 +283,10 @@ resolve_macro_extern_deprecated = `#[macro_escape]` is a deprecated synonym for `#[macro_use]` .help = try an outer attribute: `#[macro_use]` +resolve_macro_is_private = macro `{$ident}` is private + +resolve_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used + resolve_macro_use_deprecated = applying the `#[macro_use]` attribute to an `extern crate` item is deprecated .help = remove it and import macros at use sites with a `use` item instead @@ -493,6 +500,8 @@ resolve_unused_extern_crate = unused extern crate resolve_unused_label = unused label +resolve_unused_macro_definition = unused macro definition: `{$name}` + resolve_unused_macro_use = unused `#[macro_use]` import resolve_variable_bound_with_different_mode = diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 3f793bb01389..0aaea96348b5 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -228,11 +228,15 @@ fn report_unused_extern_crate_items( .span .find_ancestor_inside(extern_crate.span) .unwrap_or(extern_crate.ident.span); + self.r.lint_buffer.buffer_lint( UNUSED_EXTERN_CRATES, extern_crate.id, extern_crate.span, - BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span }, + crate::errors::ExternCrateNotIdiomatic { + span: vis_span.between(ident_span), + code: if vis_span.is_empty() { "use " } else { " use " }, + }, ); } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index eace729473e2..99f88357d93b 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,7 +1,7 @@ use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ElidedLifetimeInPathSubdiag, EmissionGuarantee, IntoDiagArg, MultiSpan, - Subdiagnostic, + Applicability, Diag, DiagMessage, ElidedLifetimeInPathSubdiag, EmissionGuarantee, IntoDiagArg, + LintDiagnostic, MultiSpan, Subdiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -1359,3 +1359,40 @@ pub(crate) struct ReexportPrivateDependency { #[diag(resolve_macro_use_deprecated)] #[help] pub(crate) struct MacroUseDeprecated; + +#[derive(LintDiagnostic)] +#[diag(resolve_macro_is_private)] +pub(crate) struct MacroIsPrivate { + pub ident: Ident, +} + +#[derive(LintDiagnostic)] +#[diag(resolve_unused_macro_definition)] +pub(crate) struct UnusedMacroDefinition { + pub name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(resolve_macro_rule_never_used)] +pub(crate) struct MacroRuleNeverUsed { + pub n: usize, + pub name: Symbol, +} + +pub(crate) struct UnstableFeature { + pub msg: DiagMessage, +} + +impl<'a> LintDiagnostic<'a, ()> for UnstableFeature { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + diag.primary_message(self.msg); + } +} + +#[derive(LintDiagnostic)] +#[diag(resolve_extern_crate_not_idiomatic)] +pub(crate) struct ExternCrateNotIdiomatic { + #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")] + pub span: Span, + pub code: &'static str, +} diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 16eeb9229c97..ed47f3124f93 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -73,7 +73,6 @@ ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility, }; use rustc_query_system::ich::StableHashingContext; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; @@ -2067,7 +2066,7 @@ fn record_use_inner( PRIVATE_MACRO_USE, import.root_id, ident.span, - BuiltinLintDiag::MacroIsPrivate(ident), + errors::MacroIsPrivate { ident }, ); } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 1222b40d8b36..8ec551c3cab7 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -340,7 +340,7 @@ fn check_unused_macros(&mut self) { UNUSED_MACROS, node_id, ident.span, - BuiltinLintDiag::UnusedMacroDefinition(ident.name), + errors::UnusedMacroDefinition { name: ident.name }, ); // Do not report unused individual rules if the entire macro is unused self.unused_macro_rules.swap_remove(&node_id); @@ -361,7 +361,7 @@ fn check_unused_macros(&mut self) { UNUSED_MACRO_RULES, node_id, rule_span, - BuiltinLintDiag::MacroRuleNeverUsed(arm_i, ident.name), + errors::MacroRuleNeverUsed { n: arm_i + 1, name: ident.name }, ); } } @@ -1031,10 +1031,8 @@ fn check_stability_and_deprecation( lint, node_id, span, - BuiltinLintDiag::UnstableFeature( - // FIXME make this translatable - msg.into(), - ), + // FIXME make this translatable + errors::UnstableFeature { msg: msg.into() }, ) }; stability::report_unstable( From 3ad6359f543ca608e720f172d4b07caaed898a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 11 Oct 2025 15:52:36 +0200 Subject: [PATCH 144/585] Move more early buffered lints to dyn lint diagnostics (6/N) --- compiler/rustc_lint/messages.ftl | 14 ------ compiler/rustc_lint/src/early/diagnostics.rs | 18 ------- compiler/rustc_lint/src/lints.rs | 50 -------------------- compiler/rustc_lint_defs/src/lib.rs | 18 ------- compiler/rustc_resolve/messages.ftl | 14 ++++++ compiler/rustc_resolve/src/errors.rs | 49 +++++++++++++++++++ compiler/rustc_resolve/src/imports.rs | 12 +++-- compiler/rustc_resolve/src/macros.rs | 23 ++++----- 8 files changed, 82 insertions(+), 116 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 82b7b1fd125e..bf721154d73b 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -642,10 +642,6 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass lint_opaque_hidden_inferred_bound_sugg = add this bound -lint_out_of_scope_macro_calls = cannot find macro `{$path}` in the current scope when looking from {$location} - .label = not found from {$location} - .help = import `macro_rules` with `use` to make it callable above its definition - lint_overflowing_bin_hex = literal out of range for `{$ty}` .negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` .negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}` @@ -681,9 +677,6 @@ lint_pattern_in_bodiless = patterns aren't allowed in functions without bodies lint_pattern_in_foreign = patterns aren't allowed in foreign function declarations .label = pattern not allowed in foreign function -lint_private_extern_crate_reexport = extern crate `{$ident}` is private and cannot be re-exported - .suggestion = consider making the `extern crate` item publicly accessible - lint_query_instability = using `{$query}` can result in unstable query results .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale @@ -709,10 +702,6 @@ lint_redundant_import = the item `{$ident}` is imported redundantly .label_imported_prelude = the item `{$ident}` is already imported by the extern prelude .label_defined_prelude = the item `{$ident}` is already defined by the extern prelude -lint_redundant_import_visibility = glob import doesn't reexport anything with visibility `{$import_vis}` because no imported item is public enough - .note = the most public imported item is `{$max_vis}` - .help = reduce the glob import's visibility or increase visibility of imported items - lint_redundant_semicolons = unnecessary trailing {$multiple -> [true] semicolons @@ -872,9 +861,6 @@ lint_unicode_text_flow = unicode codepoint changing visible direction of text pr lint_unit_bindings = binding has unit type `()` .label = this pattern is inferred to be the unit type `()` -lint_unknown_diagnostic_attribute = unknown diagnostic attribute -lint_unknown_diagnostic_attribute_typo_sugg = an attribute with a similar name exists - lint_unknown_gated_lint = unknown lint: `{$name}` .note = the `{$name}` lint is unstable diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 16f50933eb0d..34bb3989008e 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -311,21 +311,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::RedundantImportVisibility { max_vis, span: vis_span, import_vis } => { - lints::RedundantImportVisibility { span: vis_span, help: (), max_vis, import_vis } - .decorate_lint(diag); - } - BuiltinLintDiag::UnknownDiagnosticAttribute { span: typo_span, typo_name } => { - let typo = typo_name.map(|typo_name| lints::UnknownDiagnosticAttributeTypoSugg { - span: typo_span, - typo_name, - }); - lints::UnknownDiagnosticAttribute { typo }.decorate_lint(diag); - } - BuiltinLintDiag::PrivateExternCrateReexport { source: ident, extern_crate_span } => { - lints::PrivateExternCrateReexport { ident, sugg: extern_crate_span.shrink_to_lo() } - .decorate_lint(diag); - } BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag) } @@ -340,8 +325,5 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag) } - BuiltinLintDiag::OutOfScopeMacroCalls { span, path, location } => { - lints::OutOfScopeMacroCalls { span, path, location }.decorate_lint(diag) - } } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c346e50033a4..43786db8bdce 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2575,14 +2575,6 @@ pub(crate) enum CargoHelp { } } -#[derive(LintDiagnostic)] -#[diag(lint_private_extern_crate_reexport, code = E0365)] -pub(crate) struct PrivateExternCrateReexport { - pub ident: Ident, - #[suggestion(code = "pub ", style = "verbose", applicability = "maybe-incorrect")] - pub sugg: Span, -} - #[derive(LintDiagnostic)] #[diag(lint_unused_crate_dependency)] #[help] @@ -2602,26 +2594,6 @@ pub(crate) struct IllFormedAttributeInput { pub docs: &'static str, } -#[derive(LintDiagnostic)] -#[diag(lint_unknown_diagnostic_attribute)] -pub(crate) struct UnknownDiagnosticAttribute { - #[subdiagnostic] - pub typo: Option, -} - -#[derive(Subdiagnostic)] -#[suggestion( - lint_unknown_diagnostic_attribute_typo_sugg, - style = "verbose", - code = "{typo_name}", - applicability = "machine-applicable" -)] -pub(crate) struct UnknownDiagnosticAttributeTypoSugg { - #[primary_span] - pub span: Span, - pub typo_name: Symbol, -} - #[derive(LintDiagnostic)] #[diag(lint_unicode_text_flow)] #[note] @@ -2921,18 +2893,6 @@ pub(crate) struct AssociatedConstElidedLifetime { pub lifetimes_in_scope: MultiSpan, } -#[derive(LintDiagnostic)] -#[diag(lint_redundant_import_visibility)] -pub(crate) struct RedundantImportVisibility { - #[note] - pub span: Span, - #[help] - pub help: (), - - pub import_vis: String, - pub max_vis: String, -} - #[derive(LintDiagnostic)] #[diag(lint_unsafe_attr_outside_unsafe)] pub(crate) struct UnsafeAttrOutsideUnsafe { @@ -2954,16 +2914,6 @@ pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { pub right: Span, } -#[derive(LintDiagnostic)] -#[diag(lint_out_of_scope_macro_calls)] -#[help] -pub(crate) struct OutOfScopeMacroCalls { - #[label] - pub span: Span, - pub path: String, - pub location: String, -} - #[derive(LintDiagnostic)] #[diag(lint_static_mut_refs_lint)] pub(crate) struct RefOfMutStatic<'a> { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 657c2671db41..8acb5eb31991 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -714,19 +714,6 @@ pub enum BuiltinLintDiag { span: Span, lifetimes_in_scope: MultiSpan, }, - RedundantImportVisibility { - span: Span, - max_vis: String, - import_vis: String, - }, - UnknownDiagnosticAttribute { - span: Span, - typo_name: Option, - }, - PrivateExternCrateReexport { - source: Ident, - extern_crate_span: Span, - }, UnusedCrateDependency { extern_crate: Symbol, local_crate: Symbol, @@ -735,11 +722,6 @@ pub enum BuiltinLintDiag { suggestions: Vec, docs: Option<&'static str>, }, - OutOfScopeMacroCalls { - span: Span, - path: String, - location: String, - }, } pub type RegisteredTools = FxIndexSet; diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index eb49ca33aa74..4a980b2bd747 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -342,6 +342,10 @@ resolve_note_and_refers_to_the_item_defined_here = } } +resolve_out_of_scope_macro_calls = cannot find macro `{$path}` in the current scope when looking from {$location} + .label = not found from {$location} + .help = import `macro_rules` with `use` to make it callable above its definition + resolve_outer_ident_is_not_publicly_reexported = {$outer_ident_descr} `{$outer_ident}` is not publicly re-exported @@ -362,12 +366,19 @@ resolve_param_in_ty_of_const_param = resolve_pattern_doesnt_bind_name = pattern doesn't bind `{$name}` +resolve_private_extern_crate_reexport = extern crate `{$ident}` is private and cannot be re-exported + .suggestion = consider making the `extern crate` item publicly accessible + resolve_proc_macro_derive_resolution_fallback = cannot find {$ns_descr} `{$ident}` in this scope .label = names from parent modules are not accessible without an explicit import resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it .help = you can define integration tests in a directory named `tests` +resolve_redundant_import_visibility = glob import doesn't reexport anything with visibility `{$import_vis}` because no imported item is public enough + .note = the most public imported item is `{$max_vis}` + .help = reduce the glob import's visibility or increase visibility of imported items + resolve_reexport_of_crate_public = re-export of crate public `{$ident}` @@ -473,6 +484,9 @@ resolve_unexpected_res_change_ty_to_const_param_sugg = resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg = if you meant to collect the rest of the slice in `{$ident}`, use the at operator +resolve_unknown_diagnostic_attribute = unknown diagnostic attribute +resolve_unknown_diagnostic_attribute_typo_sugg = an attribute with a similar name exists + resolve_unnamed_crate_root_import = crate root imports need to be explicitly named: `use crate as name;` diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 99f88357d93b..fe1f0d253a12 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -812,6 +812,14 @@ pub(crate) struct CannotBeReexportedCratePublicNS { pub(crate) ident: Ident, } +#[derive(LintDiagnostic)] +#[diag(resolve_private_extern_crate_reexport, code = E0365)] +pub(crate) struct PrivateExternCrateReexport { + pub ident: Ident, + #[suggestion(code = "pub ", style = "verbose", applicability = "maybe-incorrect")] + pub sugg: Span, +} + #[derive(Subdiagnostic)] #[help(resolve_consider_adding_macro_export)] pub(crate) struct ConsiderAddingMacroExport { @@ -1396,3 +1404,44 @@ pub(crate) struct ExternCrateNotIdiomatic { pub span: Span, pub code: &'static str, } + +#[derive(LintDiagnostic)] +#[diag(resolve_out_of_scope_macro_calls)] +#[help] +pub(crate) struct OutOfScopeMacroCalls { + #[label] + pub span: Span, + pub path: String, + pub location: String, +} + +#[derive(LintDiagnostic)] +#[diag(resolve_redundant_import_visibility)] +pub(crate) struct RedundantImportVisibility { + #[note] + pub span: Span, + #[help] + pub help: (), + pub import_vis: String, + pub max_vis: String, +} + +#[derive(LintDiagnostic)] +#[diag(resolve_unknown_diagnostic_attribute)] +pub(crate) struct UnknownDiagnosticAttribute { + #[subdiagnostic] + pub typo: Option, +} + +#[derive(Subdiagnostic)] +#[suggestion( + resolve_unknown_diagnostic_attribute_typo_sugg, + style = "verbose", + code = "{typo_name}", + applicability = "machine-applicable" +)] +pub(crate) struct UnknownDiagnosticAttributeTypoSugg { + #[primary_span] + pub span: Span, + pub typo_name: Symbol, +} diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index f98aaecea18c..f844e7b9cc12 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1095,10 +1095,11 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option) -> Option( OUT_OF_SCOPE_MACRO_CALLS, path.span, node_id, - BuiltinLintDiag::OutOfScopeMacroCalls { + errors::OutOfScopeMacroCalls { span: path.span, path: pprust::path_to_string(path), + // FIXME: Make this translatable. location, }, ); From d706368b7006146cd43eb1774b79d481cddb0d30 Mon Sep 17 00:00:00 2001 From: Aliaksei Semianiuk Date: Sun, 30 Nov 2025 15:56:32 +0500 Subject: [PATCH 145/585] Changelog for Clippy 1.92 --- CHANGELOG.md | 83 ++++++++++++++++++++++++++++++++- clippy_lints/src/methods/mod.rs | 4 +- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78b81b5b74d6..cf619d254cec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,88 @@ document. ## Unreleased / Beta / In Rust Nightly -[e9b7045...master](https://github.com/rust-lang/rust-clippy/compare/e9b7045...master) +[d9fb15c...master](https://github.com/rust-lang/rust-clippy/compare/d9fb15c...master) + +## Rust 1.92 + +Current stable, released 2025-12-11 + +[View all 124 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-09-05T18%3A24%3A03Z..2025-10-16T14%3A13%3A43Z+base%3Amaster) + +### New Lints + +* Added [`unnecessary_option_map_or_else`] to `suspicious` + [#14662](https://github.com/rust-lang/rust-clippy/pull/14662) +* Added [`replace_box`] to `perf` + [#14953](https://github.com/rust-lang/rust-clippy/pull/14953) +* Added [`volatile_composites`] to `nursery` + [#15686](https://github.com/rust-lang/rust-clippy/pull/15686) +* Added [`self_only_used_in_recursion`] to `pedantic` + [#14787](https://github.com/rust-lang/rust-clippy/pull/14787) +* Added [`redundant_iter_cloned`] to `perf` + [#15277](https://github.com/rust-lang/rust-clippy/pull/15277) + +### Moves and Deprecations + +* Renamed [`unchecked_duration_subtraction`] to [`unchecked_time_subtraction`] + [#13800](https://github.com/rust-lang/rust-clippy/pull/13800) + +### Enhancements + +* [`mutex_atomic`] and [`mutex_integer`] overhauled to only lint definitions, not uses; added suggestions + and better help messages + [#15632](https://github.com/rust-lang/rust-clippy/pull/15632) +* [`manual_rotate`] now recognizes non-const rotation amounts + [#15402](https://github.com/rust-lang/rust-clippy/pull/15402) +* [`multiple_inherent_impl`] added `inherent-impl-lint-scope` config option (`module`, `file`, + or `crate`) + [#15843](https://github.com/rust-lang/rust-clippy/pull/15843) +* [`use_self`] now checks structs and enums + [#15566](https://github.com/rust-lang/rust-clippy/pull/15566) +* [`while_let_loop`] extended to lint on `loop { let else }` + [#15701](https://github.com/rust-lang/rust-clippy/pull/15701) +* [`mut_mut`] overhauled with structured suggestions and improved documentation + [#15417](https://github.com/rust-lang/rust-clippy/pull/15417) +* [`nonstandard_macro_braces`] now suggests trailing semicolon when needed + [#15593](https://github.com/rust-lang/rust-clippy/pull/15593) +* [`ptr_offset_with_cast`] now respects MSRV when suggesting fix, and lints more cases + [#15613](https://github.com/rust-lang/rust-clippy/pull/15613) +* [`cast_sign_loss`] and [`cast_possible_wrap`] added suggestions using `cast_{un,}signed()` methods + (MSRV 1.87+) + [#15384](https://github.com/rust-lang/rust-clippy/pull/15384) +* [`unchecked_time_subtraction`] extended to include `Duration - Duration` operations + [#13800](https://github.com/rust-lang/rust-clippy/pull/13800) +* [`filter_next`] now suggests replacing `filter().next_back()` with `rfind()` for + `DoubleEndedIterator` + [#15748](https://github.com/rust-lang/rust-clippy/pull/15748) + +### False Positive Fixes + +* [`unnecessary_safety_comment`] fixed FPs with comments above attributes + [#15678](https://github.com/rust-lang/rust-clippy/pull/15678) +* [`manual_unwrap_or`] fixed FP edge case + [#15812](https://github.com/rust-lang/rust-clippy/pull/15812) +* [`needless_continue`] fixed FP when match type is not unit or never + [#15547](https://github.com/rust-lang/rust-clippy/pull/15547) +* [`if_then_some_else_none`] fixed FP when return exists in block expr + [#15783](https://github.com/rust-lang/rust-clippy/pull/15783) +* [`new_without_default`] fixed to copy `#[cfg]` onto `impl Default` and fixed FP on private type + with trait impl + [#15720](https://github.com/rust-lang/rust-clippy/pull/15720) + [#15782](https://github.com/rust-lang/rust-clippy/pull/15782) +* [`question_mark`] fixed FP on variables used after + [#15644](https://github.com/rust-lang/rust-clippy/pull/15644) +* [`needless_return`] fixed FP with `cfg`d code after `return` + [#15669](https://github.com/rust-lang/rust-clippy/pull/15669) +* [`useless_attribute`] fixed FP on `deprecated_in_future` + [#15645](https://github.com/rust-lang/rust-clippy/pull/15645) +* [`double_parens`] fixed FP when macros are involved + [#15420](https://github.com/rust-lang/rust-clippy/pull/15420) + +### ICE Fixes + +* [`len_zero`] fixed ICE when fn len has a return type without generic type params + [#15660](https://github.com/rust-lang/rust-clippy/pull/15660) ## Rust 1.91 diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c22b0a548e3d..089e32d1e430 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4635,7 +4635,7 @@ /// let x = vec![String::new()]; /// let _ = x.iter().map(|x| x.len()); /// ``` - #[clippy::version = "1.90.0"] + #[clippy::version = "1.92.0"] pub REDUNDANT_ITER_CLONED, perf, "detects redundant calls to `Iterator::cloned`" @@ -4659,7 +4659,7 @@ /// let x: Option = Some(4); /// let y = x.unwrap_or_else(|| 2 * k); /// ``` - #[clippy::version = "1.88.0"] + #[clippy::version = "1.92.0"] pub UNNECESSARY_OPTION_MAP_OR_ELSE, suspicious, "making no use of the \"map closure\" when calling `.map_or_else(|| 2 * k, |n| n)`" From 2da3314f394fcfcbd64bfcbf4d74859df8c82619 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 30 Nov 2025 13:12:37 -0500 Subject: [PATCH 146/585] Use fallback sysroot directory if we cannot find libgccjit.so in the explicit directory --- src/lib.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 662e303f94f2..c1506ee6176f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,6 +71,7 @@ use std::any::Any; use std::ffi::CString; use std::fmt::Debug; +use std::fs; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -180,14 +181,18 @@ pub struct GccCodegenBackend { static LTO_SUPPORTED: AtomicBool = AtomicBool::new(false); +fn libgccjit_path(sysroot_path: &Path) -> PathBuf { + let sysroot_lib_dir = sysroot_path.join("lib"); + sysroot_lib_dir.join("libgccjit.so") +} + fn load_libgccjit_if_needed(sysroot_path: &Path) { if gccjit::is_loaded() { // Do not load a libgccjit second time. return; } - let sysroot_lib_dir = sysroot_path.join("lib"); - let libgccjit_target_lib_file = sysroot_lib_dir.join("libgccjit.so"); + let libgccjit_target_lib_file = libgccjit_path(sysroot_path); let path = libgccjit_target_lib_file.to_str().expect("libgccjit path"); let string = CString::new(path).expect("string to libgccjit path"); @@ -207,7 +212,16 @@ fn name(&self) -> &'static str { } fn init(&self, sess: &Session) { - load_libgccjit_if_needed(sess.opts.sysroot.path()); + // We use all_paths() instead of only path() in case the path specified by --sysroot is + // invalid. + // This is the case for instance in Rust for Linux where they specify --sysroot=/dev/null. + for path in sess.opts.sysroot.all_paths() { + let libgccjit_target_lib_file = libgccjit_path(path); + if let Ok(true) = fs::exists(libgccjit_target_lib_file) { + load_libgccjit_if_needed(path); + break; + } + } #[cfg(feature = "master")] { From 14830bfd0c8ed9fadb8bb31ff4c654810138664e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Nov 2025 12:58:01 +0100 Subject: [PATCH 147/585] ThreadId generation fallback path: avoid spurious yields --- library/std/src/thread/id.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/std/src/thread/id.rs b/library/std/src/thread/id.rs index ba7024327881..3da0825db604 100644 --- a/library/std/src/thread/id.rs +++ b/library/std/src/thread/id.rs @@ -70,7 +70,9 @@ fn exhausted() -> ! { // Acquire lock. let mut spin = 0; - while COUNTER_LOCKED.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() { + // Miri doesn't like it when we yield here as it interferes with deterministically + // scheduling threads, so avoid `compare_exchange_weak` to avoid spurious yields. + while COUNTER_LOCKED.swap(true, Ordering::Acquire) { if spin <= 3 { for _ in 0..(1 << spin) { spin_loop(); @@ -80,6 +82,7 @@ fn exhausted() -> ! { } spin += 1; } + // This was `false` before the swap, so we got the lock. // SAFETY: we have an exclusive lock on the counter. unsafe { From 2cf9b7f5e5713dfe318832f316d38c91687a0843 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 27 Nov 2025 19:50:38 +0000 Subject: [PATCH 148/585] Fix `name()` functions for local defs in rustc_public The `name()` function specifies that it returns absolute path of items, however it wasn't including the crate name for local items. This change fixes that. This was reported here: https://github.com/rust-lang/project-stable-mir/issues/109 --- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- .../rustc_public_bridge/src/context/impls.rs | 7 ++-- tests/ui-fulldeps/rustc_public/check_abi.rs | 10 ++--- .../rustc_public/check_allocation.rs | 10 ++--- .../rustc_public/check_assoc_items.rs | 2 +- .../rustc_public/check_attribute.rs | 11 ++--- .../rustc_public/check_coroutine_body.rs | 19 +++------ .../rustc_public/check_crate_defs.rs | 19 +++++---- .../ui-fulldeps/rustc_public/check_def_ty.rs | 12 +++--- tests/ui-fulldeps/rustc_public/check_defs.rs | 32 +++++++------- .../ui-fulldeps/rustc_public/check_foreign.rs | 4 +- .../rustc_public/check_item_kind.rs | 2 +- .../rustc_public/check_trait_queries.rs | 19 +++++---- .../rustc_public/check_transform.rs | 2 +- .../ui-fulldeps/rustc_public/check_variant.rs | 2 +- .../rustc_public/closure-generic-body.rs | 2 +- .../ui-fulldeps/rustc_public/closure_body.rs | 2 +- tests/ui-fulldeps/rustc_public/crate-info.rs | 42 +++++++++---------- tests/ui-fulldeps/rustc_public/projections.rs | 4 +- 19 files changed, 99 insertions(+), 104 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 06744ae6e242..6a4122ad6717 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -105,7 +105,7 @@ pub fn $name() -> bool { /// /// Overrides `with_crate_prefix`. - // This function is not currently used in-tree, but it's used by a downstream rustc-driver in + // This function is used by `rustc_public` and downstream rustc-driver in // Ferrocene. Please check with them before removing it. fn with_resolve_crate_name(CrateNamePrefixGuard, SHOULD_PREFIX_WITH_CRATE_NAME); /// Adds the `crate::` prefix to paths where appropriate. diff --git a/compiler/rustc_public_bridge/src/context/impls.rs b/compiler/rustc_public_bridge/src/context/impls.rs index cbb00d64e096..1047bbbef69e 100644 --- a/compiler/rustc_public_bridge/src/context/impls.rs +++ b/compiler/rustc_public_bridge/src/context/impls.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, GlobalAlloc, Scalar}; use rustc_middle::mir::{BinOp, Body, Const as MirConst, ConstValue, UnOp}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; -use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; +use rustc_middle::ty::print::{with_forced_trimmed_paths, with_resolve_crate_name}; use rustc_middle::ty::util::Discr; use rustc_middle::ty::{ AdtDef, AdtKind, AssocItem, Binder, ClosureKind, CoroutineArgsExt, EarlyBinder, @@ -264,7 +264,8 @@ pub fn def_name(&self, def_id: DefId, trimmed: bool) -> String { if trimmed { with_forced_trimmed_paths!(self.tcx.def_path_str(def_id)) } else { - with_no_trimmed_paths!(self.tcx.def_path_str(def_id)) + // For local definitions, we need to prepend with crate name. + with_resolve_crate_name!(self.tcx.def_path_str(def_id)) } } @@ -724,7 +725,7 @@ pub fn instance_name(&self, instance: ty::Instance<'tcx>, trimmed: bool) -> Stri self.tcx.def_path_str_with_args(instance.def_id(), instance.args) ) } else { - with_no_trimmed_paths!( + with_resolve_crate_name!( self.tcx.def_path_str_with_args(instance.def_id(), instance.args) ) } diff --git a/tests/ui-fulldeps/rustc_public/check_abi.rs b/tests/ui-fulldeps/rustc_public/check_abi.rs index 57c8377ea367..b3519a2c60ed 100644 --- a/tests/ui-fulldeps/rustc_public/check_abi.rs +++ b/tests/ui-fulldeps/rustc_public/check_abi.rs @@ -9,10 +9,10 @@ #![feature(assert_matches)] #![feature(ascii_char, ascii_char_variants)] -extern crate rustc_hir; -extern crate rustc_middle; extern crate rustc_driver; +extern crate rustc_hir; extern crate rustc_interface; +extern crate rustc_middle; #[macro_use] extern crate rustc_public; @@ -39,7 +39,7 @@ fn test_stable_mir() -> ControlFlow<()> { let items = rustc_public::all_local_items(); // Test fn_abi - let target_fn = *get_item(&items, (ItemKind::Fn, "fn_abi")).unwrap(); + let target_fn = *get_item(&items, (ItemKind::Fn, "input::fn_abi")).unwrap(); let instance = Instance::try_from(target_fn).unwrap(); let fn_abi = instance.fn_abi().unwrap(); assert_eq!(fn_abi.conv, CallConvention::Rust); @@ -51,11 +51,11 @@ fn test_stable_mir() -> ControlFlow<()> { check_result(&fn_abi.ret); // Test variadic function. - let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap(); + let variadic_fn = *get_item(&items, (ItemKind::Fn, "input::variadic_fn")).unwrap(); check_variadic(variadic_fn); // Extract function pointers. - let fn_ptr_holder = *get_item(&items, (ItemKind::Fn, "fn_ptr_holder")).unwrap(); + let fn_ptr_holder = *get_item(&items, (ItemKind::Fn, "input::fn_ptr_holder")).unwrap(); let fn_ptr_holder_instance = Instance::try_from(fn_ptr_holder).unwrap(); let body = fn_ptr_holder_instance.body().unwrap(); let args = body.arg_locals(); diff --git a/tests/ui-fulldeps/rustc_public/check_allocation.rs b/tests/ui-fulldeps/rustc_public/check_allocation.rs index 70e4ee3fe347..3a0a2382be72 100644 --- a/tests/ui-fulldeps/rustc_public/check_allocation.rs +++ b/tests/ui-fulldeps/rustc_public/check_allocation.rs @@ -40,11 +40,11 @@ fn test_stable_mir() -> ControlFlow<()> { // Find items in the local crate. let items = rustc_public::all_local_items(); - check_foo(*get_item(&items, (ItemKind::Static, "FOO")).unwrap()); - check_bar(*get_item(&items, (ItemKind::Static, "BAR")).unwrap()); - check_len(*get_item(&items, (ItemKind::Static, "LEN")).unwrap()); - check_cstr(*get_item(&items, (ItemKind::Static, "C_STR")).unwrap()); - check_other_consts(*get_item(&items, (ItemKind::Fn, "other_consts")).unwrap()); + check_foo(*get_item(&items, (ItemKind::Static, "input::FOO")).unwrap()); + check_bar(*get_item(&items, (ItemKind::Static, "input::BAR")).unwrap()); + check_len(*get_item(&items, (ItemKind::Static, "input::LEN")).unwrap()); + check_cstr(*get_item(&items, (ItemKind::Static, "input::C_STR")).unwrap()); + check_other_consts(*get_item(&items, (ItemKind::Fn, "input::other_consts")).unwrap()); ControlFlow::Continue(()) } diff --git a/tests/ui-fulldeps/rustc_public/check_assoc_items.rs b/tests/ui-fulldeps/rustc_public/check_assoc_items.rs index 1557991f8cab..194d6be88a76 100644 --- a/tests/ui-fulldeps/rustc_public/check_assoc_items.rs +++ b/tests/ui-fulldeps/rustc_public/check_assoc_items.rs @@ -77,7 +77,7 @@ fn test_assoc_items() -> ControlFlow<()> { /// Note that order doesn't matter. fn check_items(items: &[T], expected: &[&str]) { let expected: HashSet<_> = expected.iter().map(|s| s.to_string()).collect(); - let item_names: HashSet<_> = items.iter().map(|item| item.name()).collect(); + let item_names: HashSet<_> = items.iter().map(|item| item.trimmed_name()).collect(); assert_eq!(item_names, expected); } diff --git a/tests/ui-fulldeps/rustc_public/check_attribute.rs b/tests/ui-fulldeps/rustc_public/check_attribute.rs index 0c34ac4dfe95..393ff4c63c5a 100644 --- a/tests/ui-fulldeps/rustc_public/check_attribute.rs +++ b/tests/ui-fulldeps/rustc_public/check_attribute.rs @@ -38,16 +38,13 @@ fn test_tool(items: &CrateItems) { assert_eq!(rustfmt_attrs[0].as_str(), "#[rustfmt::skip]\n"); let clippy_fn = *get_item(&items, "complex_fn").unwrap(); - let clippy_attrs = clippy_fn.tool_attrs(&["clippy".to_string(), - "cyclomatic_complexity".to_string()]); + let clippy_attrs = + clippy_fn.tool_attrs(&["clippy".to_string(), "cyclomatic_complexity".to_string()]); assert_eq!(clippy_attrs[0].as_str(), "#[clippy::cyclomatic_complexity = \"100\"]\n"); } -fn get_item<'a>( - items: &'a CrateItems, - name: &str, -) -> Option<&'a rustc_public::CrateItem> { - items.iter().find(|crate_item| crate_item.name() == name) +fn get_item<'a>(items: &'a CrateItems, name: &str) -> Option<&'a rustc_public::CrateItem> { + items.iter().find(|crate_item| crate_item.trimmed_name() == name) } /// This test will generate and analyze a dummy crate using the stable mir. diff --git a/tests/ui-fulldeps/rustc_public/check_coroutine_body.rs b/tests/ui-fulldeps/rustc_public/check_coroutine_body.rs index 725b538b0fe5..75f4f1f5bf4c 100644 --- a/tests/ui-fulldeps/rustc_public/check_coroutine_body.rs +++ b/tests/ui-fulldeps/rustc_public/check_coroutine_body.rs @@ -29,11 +29,7 @@ fn test_coroutine_body() -> ControlFlow<()> { if let Some(body) = crate_items.iter().find_map(|item| { let item_ty = item.ty(); if let TyKind::RigidTy(RigidTy::Coroutine(def, ..)) = &item_ty.kind() { - if def.0.name() == "gbc::{closure#0}".to_string() { - def.body() - } else { - None - } + if def.0.trimmed_name() == "gbc::{closure#0}".to_string() { def.body() } else { None } } else { None } @@ -51,26 +47,23 @@ fn check_coroutine_body(body: Body) { let local_3 = &body.locals()[3].ty; let local_4 = &body.locals()[4].ty; - let TyKind::RigidTy(RigidTy::Adt(def, ..)) = &ret_ty.kind() - else { + let TyKind::RigidTy(RigidTy::Adt(def, ..)) = &ret_ty.kind() else { panic!("Expected RigidTy::Adt, got: {:#?}", ret_ty); }; assert_eq!("std::task::Poll", def.0.name()); - let TyKind::RigidTy(RigidTy::Coroutine(def, ..)) = &local_3.kind() - else { + let TyKind::RigidTy(RigidTy::Coroutine(def, ..)) = &local_3.kind() else { panic!("Expected RigidTy::Coroutine, got: {:#?}", local_3); }; - assert_eq!("gbc::{closure#0}::{closure#0}", def.0.name()); + assert_eq!("crate_coroutine_body::gbc::{closure#0}::{closure#0}", def.0.name()); - let TyKind::RigidTy(RigidTy::Coroutine(def, ..)) = &local_4.kind() - else { + let TyKind::RigidTy(RigidTy::Coroutine(def, ..)) = &local_4.kind() else { panic!("Expected RigidTy::Coroutine, got: {:#?}", local_4); }; - assert_eq!("gbc::{closure#0}::{closure#0}", def.0.name()); + assert_eq!("crate_coroutine_body::gbc::{closure#0}::{closure#0}", def.0.name()); } fn main() { diff --git a/tests/ui-fulldeps/rustc_public/check_crate_defs.rs b/tests/ui-fulldeps/rustc_public/check_crate_defs.rs index 3ca8b66e58dc..7d949eae3910 100644 --- a/tests/ui-fulldeps/rustc_public/check_crate_defs.rs +++ b/tests/ui-fulldeps/rustc_public/check_crate_defs.rs @@ -27,17 +27,20 @@ fn test_stable_mir() -> ControlFlow<()> { // Find items in the local crate. let local = rustc_public::local_crate(); - check_items(&local.statics(), &["PRIVATE_STATIC", "dummy::PUBLIC_STATIC"]); + check_items( + &local.statics(), + &["crate_defs::PRIVATE_STATIC", "crate_defs::dummy::PUBLIC_STATIC"], + ); check_items( &local.fn_defs(), &[ - "top_level", - "dummy::public_fn", - "dummy::private_fn", - "dummy::PrivateStruct::new", - "::drop", - "DummyTrait::method", - "::method", + "crate_defs::top_level", + "crate_defs::dummy::public_fn", + "crate_defs::dummy::private_fn", + "crate_defs::dummy::PrivateStruct::new", + "::drop", + "crate_defs::DummyTrait::method", + "::method", ], ); diff --git a/tests/ui-fulldeps/rustc_public/check_def_ty.rs b/tests/ui-fulldeps/rustc_public/check_def_ty.rs index 4a45bb6daa5f..242b06dcd229 100644 --- a/tests/ui-fulldeps/rustc_public/check_def_ty.rs +++ b/tests/ui-fulldeps/rustc_public/check_def_ty.rs @@ -16,7 +16,7 @@ extern crate rustc_interface; extern crate rustc_public; -use rustc_public::ty::{Ty, ForeignItemKind}; +use rustc_public::ty::{ForeignItemKind, Ty}; use rustc_public::*; use std::io::Write; use std::ops::ControlFlow; @@ -29,11 +29,11 @@ fn test_def_tys() -> ControlFlow<()> { for item in &items { // Type from crate items. let ty = item.ty(); - match item.name().as_str() { + match item.trimmed_name().as_str() { "STATIC_STR" => assert!(ty.kind().is_ref()), "CONST_U32" => assert!(ty.kind().is_integral()), - "main" => { check_fn_def(ty) } - _ => unreachable!("Unexpected item: `{item:?}`") + "main" => check_fn_def(ty), + _ => unreachable!("Unexpected item: `{item:?}`"), } } @@ -42,7 +42,7 @@ fn test_def_tys() -> ControlFlow<()> { // Type from foreign items. let ty = item.ty(); let item_kind = item.kind(); - let name = item.name(); + let name = item.trimmed_name(); match item_kind { ForeignItemKind::Fn(fn_def) => { assert_eq!(&name, "extern_fn"); @@ -54,7 +54,7 @@ fn test_def_tys() -> ControlFlow<()> { assert_eq!(ty, def.ty()); assert!(ty.kind().is_integral()) } - _ => unreachable!("Unexpected kind: {item_kind:?}") + _ => unreachable!("Unexpected kind: {item_kind:?}"), }; } diff --git a/tests/ui-fulldeps/rustc_public/check_defs.rs b/tests/ui-fulldeps/rustc_public/check_defs.rs index 0c45859a132a..e6f9fb9972b0 100644 --- a/tests/ui-fulldeps/rustc_public/check_defs.rs +++ b/tests/ui-fulldeps/rustc_public/check_defs.rs @@ -15,11 +15,11 @@ extern crate rustc_interface; extern crate rustc_public; -use std::assert_matches::assert_matches; -use mir::{mono::Instance, TerminatorKind::*}; +use mir::{TerminatorKind::*, mono::Instance}; use rustc_public::mir::mono::InstanceKind; -use rustc_public::ty::{RigidTy, TyKind, Ty, UintTy}; +use rustc_public::ty::{RigidTy, Ty, TyKind, UintTy}; use rustc_public::*; +use std::assert_matches::assert_matches; use std::io::Write; use std::ops::ControlFlow; @@ -29,7 +29,7 @@ fn test_stable_mir() -> ControlFlow<()> { let entry = rustc_public::entry_fn().unwrap(); let main_fn = Instance::try_from(entry).unwrap(); - assert_eq!(main_fn.name(), "main"); + assert_eq!(main_fn.name(), "input::main"); assert_eq!(main_fn.trimmed_name(), "main"); let instances = get_instances(main_fn.body().unwrap()); @@ -65,10 +65,8 @@ fn test_fn(instance: Instance, expected_trimmed: &str, expected_qualified: &str, fn extract_elem_ty(ty: Ty) -> Ty { match ty.kind() { - TyKind::RigidTy(RigidTy::Adt(_, args)) => { - *args.0[0].expect_ty() - } - _ => unreachable!("Expected Vec ADT, but found: {ty:?}") + TyKind::RigidTy(RigidTy::Adt(_, args)) => *args.0[0].expect_ty(), + _ => unreachable!("Expected Vec ADT, but found: {ty:?}"), } } @@ -89,19 +87,19 @@ fn test_vec_new(instance: mir::mono::Instance) { /// Inspect the instance body fn get_instances(body: mir::Body) -> Vec { - body.blocks.iter().filter_map(|bb| { - match &bb.terminator.kind { + body.blocks + .iter() + .filter_map(|bb| match &bb.terminator.kind { Call { func, .. } => { - let TyKind::RigidTy(ty) = func.ty(body.locals()).unwrap().kind() else { unreachable! - () }; + let TyKind::RigidTy(ty) = func.ty(body.locals()).unwrap().kind() else { + unreachable!() + }; let RigidTy::FnDef(def, args) = ty else { unreachable!() }; Instance::resolve(def, &args).ok() } - _ => { - None - } - } - }).collect::>() + _ => None, + }) + .collect::>() } /// This test will generate and analyze a dummy crate using the stable mir. diff --git a/tests/ui-fulldeps/rustc_public/check_foreign.rs b/tests/ui-fulldeps/rustc_public/check_foreign.rs index 78b62594c618..bd34fb5cf8a8 100644 --- a/tests/ui-fulldeps/rustc_public/check_foreign.rs +++ b/tests/ui-fulldeps/rustc_public/check_foreign.rs @@ -13,8 +13,8 @@ extern crate rustc_driver; extern crate rustc_interface; -extern crate rustc_span; extern crate rustc_public; +extern crate rustc_span; use rustc_public::{ ty::{Abi, ForeignItemKind}, @@ -40,7 +40,7 @@ fn test_foreign() -> ControlFlow<()> { assert_eq!(c_items.len(), 3); for item in c_items { let kind = item.kind(); - match item.name().as_str() { + match item.trimmed_name().as_str() { "foo" => assert_matches!(kind, ForeignItemKind::Fn(..)), "bar" => assert_matches!(kind, ForeignItemKind::Static(..)), "Baz" => assert_matches!(kind, ForeignItemKind::Type(..)), diff --git a/tests/ui-fulldeps/rustc_public/check_item_kind.rs b/tests/ui-fulldeps/rustc_public/check_item_kind.rs index b759628f1a42..c687b3af1c63 100644 --- a/tests/ui-fulldeps/rustc_public/check_item_kind.rs +++ b/tests/ui-fulldeps/rustc_public/check_item_kind.rs @@ -27,7 +27,7 @@ fn test_item_kind() -> ControlFlow<()> { assert_eq!(items.len(), 4); // Constructor item. for item in items { - let expected_kind = match item.name().as_str() { + let expected_kind = match item.trimmed_name().as_str() { "Dummy" => ItemKind::Ctor(CtorKind::Fn), "dummy" => ItemKind::Fn, "unit" => ItemKind::Fn, diff --git a/tests/ui-fulldeps/rustc_public/check_trait_queries.rs b/tests/ui-fulldeps/rustc_public/check_trait_queries.rs index 0dd13044fcce..5603add82f59 100644 --- a/tests/ui-fulldeps/rustc_public/check_trait_queries.rs +++ b/tests/ui-fulldeps/rustc_public/check_trait_queries.rs @@ -28,19 +28,20 @@ fn test_traits() -> ControlFlow<()> { let local_crate = rustc_public::local_crate(); let local_traits = local_crate.trait_decls(); assert_eq!(local_traits.len(), 1, "Expected `Max` trait, but found {:?}", local_traits); - assert_eq!(&local_traits[0].name(), "Max"); + assert_eq!(&local_traits[0].trimmed_name(), "Max"); let local_impls = local_crate.trait_impls(); - let impl_names = local_impls.iter().map(|trait_impl| trait_impl.name()).collect::>(); + let impl_names = + local_impls.iter().map(|trait_impl| trait_impl.trimmed_name()).collect::>(); assert_impl(&impl_names, ""); - assert_impl(&impl_names, ""); - assert_impl(&impl_names, ""); - assert_impl(&impl_names, ""); - assert_impl(&impl_names, ""); - assert_impl(&impl_names, ""); - assert_impl(&impl_names, ">"); + assert_impl(&impl_names, ""); + assert_impl(&impl_names, ""); + assert_impl(&impl_names, ""); + assert_impl(&impl_names, ""); + assert_impl(&impl_names, ""); + assert_impl(&impl_names, ">"); assert_impl(&impl_names, ""); - assert_impl(&impl_names, " for u64>"); + assert_impl(&impl_names, " for u64>"); let all_traits = rustc_public::all_trait_decls(); assert!(all_traits.len() > local_traits.len()); diff --git a/tests/ui-fulldeps/rustc_public/check_transform.rs b/tests/ui-fulldeps/rustc_public/check_transform.rs index b30d98c3b26f..900bb4014d54 100644 --- a/tests/ui-fulldeps/rustc_public/check_transform.rs +++ b/tests/ui-fulldeps/rustc_public/check_transform.rs @@ -34,7 +34,7 @@ fn test_transform() -> ControlFlow<()> { let items = rustc_public::all_local_items(); // Test fn_abi - let target_fn = *get_item(&items, (ItemKind::Fn, "dummy")).unwrap(); + let target_fn = *get_item(&items, (ItemKind::Fn, "input::dummy")).unwrap(); let instance = Instance::try_from(target_fn).unwrap(); let body = instance.body().unwrap(); check_msg(&body, "oops"); diff --git a/tests/ui-fulldeps/rustc_public/check_variant.rs b/tests/ui-fulldeps/rustc_public/check_variant.rs index 9ed16f2357c0..9bdd0c9d80ba 100644 --- a/tests/ui-fulldeps/rustc_public/check_variant.rs +++ b/tests/ui-fulldeps/rustc_public/check_variant.rs @@ -97,7 +97,7 @@ fn check_adt_poly2() { } fn get_fn(name: &str) -> CrateItem { - rustc_public::all_local_items().into_iter().find(|it| it.name().eq(name)).unwrap() + rustc_public::all_local_items().into_iter().find(|it| it.trimmed_name().eq(name)).unwrap() } fn check_statement_is_aggregate_assign( diff --git a/tests/ui-fulldeps/rustc_public/closure-generic-body.rs b/tests/ui-fulldeps/rustc_public/closure-generic-body.rs index e5f910fbda11..46aeca76ba65 100644 --- a/tests/ui-fulldeps/rustc_public/closure-generic-body.rs +++ b/tests/ui-fulldeps/rustc_public/closure-generic-body.rs @@ -52,7 +52,7 @@ fn check_incr_closure_body(body: Body) { panic!("expected FnDef"); }; - assert_eq!(def_id.name(), "id"); + assert_eq!(def_id.trimmed_name(), "id"); } fn main() { diff --git a/tests/ui-fulldeps/rustc_public/closure_body.rs b/tests/ui-fulldeps/rustc_public/closure_body.rs index f5f9f23ad126..43cbca8baab8 100644 --- a/tests/ui-fulldeps/rustc_public/closure_body.rs +++ b/tests/ui-fulldeps/rustc_public/closure_body.rs @@ -52,7 +52,7 @@ fn check_incr_closure_body(body: Body) { panic!("expected FnDef"); }; - assert_eq!(def_id.name(), "incr"); + assert_eq!(def_id.name(), "crate_closure_body::incr"); } fn main() { diff --git a/tests/ui-fulldeps/rustc_public/crate-info.rs b/tests/ui-fulldeps/rustc_public/crate-info.rs index 19082d7394ab..06cbbfcd69ec 100644 --- a/tests/ui-fulldeps/rustc_public/crate-info.rs +++ b/tests/ui-fulldeps/rustc_public/crate-info.rs @@ -38,12 +38,12 @@ fn test_stable_mir() -> ControlFlow<()> { // Find items in the local crate. let items = rustc_public::all_local_items(); - assert!(get_item(&items, (DefKind::Fn, "foo::bar")).is_some()); + assert!(get_item(&items, (DefKind::Fn, "input::foo::bar")).is_some()); // Find the `std` crate and assert that there is only one of it. assert!(rustc_public::find_crates("std").len() == 1); - let bar = get_item(&items, (DefKind::Fn, "bar")).unwrap(); + let bar = get_item(&items, (DefKind::Fn, "input::bar")).unwrap(); let body = bar.expect_body(); assert_eq!(body.locals().len(), 2); assert_eq!(body.blocks.len(), 1); @@ -58,7 +58,7 @@ fn test_stable_mir() -> ControlFlow<()> { other => panic!("{other:?}"), } - let foo_bar = get_item(&items, (DefKind::Fn, "foo_bar")).unwrap(); + let foo_bar = get_item(&items, (DefKind::Fn, "input::foo_bar")).unwrap(); let body = foo_bar.expect_body(); assert_eq!(body.locals().len(), 5); assert_eq!(body.blocks.len(), 4); @@ -68,7 +68,7 @@ fn test_stable_mir() -> ControlFlow<()> { other => panic!("{other:?}"), } - let types = get_item(&items, (DefKind::Fn, "types")).unwrap(); + let types = get_item(&items, (DefKind::Fn, "input::types")).unwrap(); let body = types.expect_body(); assert_eq!(body.locals().len(), 6); assert_matches!( @@ -85,15 +85,15 @@ fn test_stable_mir() -> ControlFlow<()> { ); assert_matches!( body.locals()[3].ty.kind(), - rustc_public::ty::TyKind::RigidTy( - rustc_public::ty::RigidTy::Int(rustc_public::ty::IntTy::I32) - ) + rustc_public::ty::TyKind::RigidTy(rustc_public::ty::RigidTy::Int( + rustc_public::ty::IntTy::I32 + )) ); assert_matches!( body.locals()[4].ty.kind(), - rustc_public::ty::TyKind::RigidTy( - rustc_public::ty::RigidTy::Uint(rustc_public::ty::UintTy::U64) - ) + rustc_public::ty::TyKind::RigidTy(rustc_public::ty::RigidTy::Uint( + rustc_public::ty::UintTy::U64 + )) ); assert_matches!( body.locals()[5].ty.kind(), @@ -102,7 +102,7 @@ fn test_stable_mir() -> ControlFlow<()> { )) ); - let drop = get_item(&items, (DefKind::Fn, "drop")).unwrap(); + let drop = get_item(&items, (DefKind::Fn, "input::drop")).unwrap(); let body = drop.expect_body(); assert_eq!(body.blocks.len(), 2); let block = &body.blocks[0]; @@ -111,7 +111,7 @@ fn test_stable_mir() -> ControlFlow<()> { other => panic!("{other:?}"), } - let assert = get_item(&items, (DefKind::Fn, "assert")).unwrap(); + let assert = get_item(&items, (DefKind::Fn, "input::assert")).unwrap(); let body = assert.expect_body(); assert_eq!(body.blocks.len(), 2); let block = &body.blocks[0]; @@ -120,7 +120,7 @@ fn test_stable_mir() -> ControlFlow<()> { other => panic!("{other:?}"), } - let monomorphic = get_item(&items, (DefKind::Fn, "monomorphic")).unwrap(); + let monomorphic = get_item(&items, (DefKind::Fn, "input::monomorphic")).unwrap(); let instance = Instance::try_from(monomorphic.clone()).unwrap(); for block in instance.body().unwrap().blocks { match &block.terminator.kind { @@ -140,11 +140,11 @@ fn test_stable_mir() -> ControlFlow<()> { } } - let foo_const = get_item(&items, (DefKind::Const, "FOO")).unwrap(); + let foo_const = get_item(&items, (DefKind::Const, "input::FOO")).unwrap(); // Ensure we don't panic trying to get the body of a constant. foo_const.expect_body(); - let locals_fn = get_item(&items, (DefKind::Fn, "locals")).unwrap(); + let locals_fn = get_item(&items, (DefKind::Fn, "input::locals")).unwrap(); let body = locals_fn.expect_body(); assert_eq!(body.locals().len(), 4); assert_matches!( @@ -154,15 +154,15 @@ fn test_stable_mir() -> ControlFlow<()> { assert_eq!(body.arg_locals().len(), 2); assert_matches!( body.arg_locals()[0].ty.kind(), - rustc_public::ty::TyKind::RigidTy( - rustc_public::ty::RigidTy::Int(rustc_public::ty::IntTy::I32) - ) + rustc_public::ty::TyKind::RigidTy(rustc_public::ty::RigidTy::Int( + rustc_public::ty::IntTy::I32 + )) ); assert_matches!( body.arg_locals()[1].ty.kind(), - rustc_public::ty::TyKind::RigidTy( - rustc_public::ty::RigidTy::Uint(rustc_public::ty::UintTy::U64) - ) + rustc_public::ty::TyKind::RigidTy(rustc_public::ty::RigidTy::Uint( + rustc_public::ty::UintTy::U64 + )) ); assert_eq!(body.inner_locals().len(), 1); // If conditions have an extra inner local to hold their results diff --git a/tests/ui-fulldeps/rustc_public/projections.rs b/tests/ui-fulldeps/rustc_public/projections.rs index e0213b4253c7..c1cdb5374d46 100644 --- a/tests/ui-fulldeps/rustc_public/projections.rs +++ b/tests/ui-fulldeps/rustc_public/projections.rs @@ -136,7 +136,9 @@ fn get_item<'a>( items: &'a rustc_public::CrateItems, item: (ItemKind, &str), ) -> Option<&'a rustc_public::CrateItem> { - items.iter().find(|crate_item| crate_item.kind() == item.0 && crate_item.name() == item.1) + items + .iter() + .find(|crate_item| crate_item.kind() == item.0 && crate_item.trimmed_name() == item.1) } /// This test will generate and analyze a dummy crate using the stable mir. From bb2bfc3f3fd3fdda775dc5e2e20e85d0b18b3b24 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Fri, 28 Nov 2025 19:29:14 +0000 Subject: [PATCH 149/585] Fix name and pretty print now uses trimmed_name --- compiler/rustc_public/src/lib.rs | 2 +- compiler/rustc_public/src/mir/pretty.rs | 2 +- compiler/rustc_public/src/ty.rs | 3 ++ .../rustc_public_bridge/src/context/impls.rs | 10 ++++--- .../rustc_public/check_def_parent.rs | 30 +++++++++++-------- .../ui-fulldeps/rustc_public/check_def_ty.rs | 14 ++++++++- .../async-closure.stdout | 4 +-- .../ui/rustc_public-ir-print/operands.stdout | 16 +++++----- 8 files changed, 51 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_public/src/lib.rs b/compiler/rustc_public/src/lib.rs index f470eebc8b38..5da79196dd4e 100644 --- a/compiler/rustc_public/src/lib.rs +++ b/compiler/rustc_public/src/lib.rs @@ -178,7 +178,7 @@ pub fn is_foreign_item(&self) -> bool { pub fn emit_mir(&self, w: &mut W) -> io::Result<()> { self.body() .ok_or_else(|| io::Error::other(format!("No body found for `{}`", self.name())))? - .dump(w, &self.name()) + .dump(w, &self.trimmed_name()) } } diff --git a/compiler/rustc_public/src/mir/pretty.rs b/compiler/rustc_public/src/mir/pretty.rs index d80e227f5a9c..08e4e0c7e0f9 100644 --- a/compiler/rustc_public/src/mir/pretty.rs +++ b/compiler/rustc_public/src/mir/pretty.rs @@ -412,7 +412,7 @@ fn pretty_aggregate( } AggregateKind::Adt(def, var, _, _, _) => { if def.kind() == AdtKind::Enum { - write!(writer, "{}::{}", def.name(), def.variant(*var).unwrap().name())?; + write!(writer, "{}::{}", def.trimmed_name(), def.variant(*var).unwrap().name())?; } else { write!(writer, "{}", def.variant(*var).unwrap().name())?; } diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index f24d98f7e552..14656a2e594a 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -876,6 +876,9 @@ pub struct VariantDef { } impl VariantDef { + /// The name of the variant, struct or union. + /// + /// This will not include the name of the enum or qualified path. pub fn name(&self) -> Symbol { with(|cx| cx.variant_name(*self)) } diff --git a/compiler/rustc_public_bridge/src/context/impls.rs b/compiler/rustc_public_bridge/src/context/impls.rs index 1047bbbef69e..26728a34b84a 100644 --- a/compiler/rustc_public_bridge/src/context/impls.rs +++ b/compiler/rustc_public_bridge/src/context/impls.rs @@ -10,7 +10,9 @@ use rustc_middle::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, GlobalAlloc, Scalar}; use rustc_middle::mir::{BinOp, Body, Const as MirConst, ConstValue, UnOp}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; -use rustc_middle::ty::print::{with_forced_trimmed_paths, with_resolve_crate_name}; +use rustc_middle::ty::print::{ + with_forced_trimmed_paths, with_no_trimmed_paths, with_resolve_crate_name, +}; use rustc_middle::ty::util::Discr; use rustc_middle::ty::{ AdtDef, AdtKind, AssocItem, Binder, ClosureKind, CoroutineArgsExt, EarlyBinder, @@ -265,7 +267,7 @@ pub fn def_name(&self, def_id: DefId, trimmed: bool) -> String { with_forced_trimmed_paths!(self.tcx.def_path_str(def_id)) } else { // For local definitions, we need to prepend with crate name. - with_resolve_crate_name!(self.tcx.def_path_str(def_id)) + with_resolve_crate_name!(with_no_trimmed_paths!(self.tcx.def_path_str(def_id))) } } @@ -725,9 +727,9 @@ pub fn instance_name(&self, instance: ty::Instance<'tcx>, trimmed: bool) -> Stri self.tcx.def_path_str_with_args(instance.def_id(), instance.args) ) } else { - with_resolve_crate_name!( + with_resolve_crate_name!(with_no_trimmed_paths!( self.tcx.def_path_str_with_args(instance.def_id(), instance.args) - ) + )) } } diff --git a/tests/ui-fulldeps/rustc_public/check_def_parent.rs b/tests/ui-fulldeps/rustc_public/check_def_parent.rs index 192ad471de33..7f633a627b19 100644 --- a/tests/ui-fulldeps/rustc_public/check_def_parent.rs +++ b/tests/ui-fulldeps/rustc_public/check_def_parent.rs @@ -47,44 +47,47 @@ fn set_once(slot: &mut Option, val: T) { let krate = rustc_public::local_crate(); for it in rustc_public::all_local_items() { match &*it.0.name() { - "wrapper_mod::CONST_ITEM" => { + "input::wrapper_mod::CONST_ITEM" => { set_once(&mut const_item, it.0); } - "wrapper_mod::STATIC_ITEM" => { + "input::wrapper_mod::STATIC_ITEM" => { set_once(&mut static_item, it.0); } - "::trait_method" => { + "::trait_method" => { set_once(&mut trait_method, it.0); } - "::trait_method::trait_method_helper" => { + "::trait_method::trait_method_helper" => + { set_once(&mut trait_method_helper, it.0); } - "wrapper_mod::MyStruct::inherent_method" => { + "input::wrapper_mod::MyStruct::inherent_method" => { set_once(&mut inherent_method, it.0); } - "wrapper_mod::MyStruct::inherent_method::inherent_method_helper" => { + "input::wrapper_mod::MyStruct::inherent_method::inherent_method_helper" => { set_once(&mut inherent_method_helper, it.0); } - "main" => { + "input::main" => { set_once(&mut main, it.0); } - "wrapper_mod::MyStruct" => { + "input::wrapper_mod::MyStruct" => { set_once(&mut mystruct_ctor, it.0); mystruct_ctor_ty = Some(it.ty()); } - _ => (), + name => panic!("Unexpected item: `{name}`"), } } for it in krate.trait_decls() { match &*it.0.name() { - "wrapper_mod::MyTrait" => set_once(&mut trait_decl, it.0), + "input::wrapper_mod::MyTrait" => set_once(&mut trait_decl, it.0), _ => (), } } for it in krate.trait_impls() { match &*it.0.name() { - "" => set_once(&mut trait_impl, it.0), - _ => (), + "" => { + set_once(&mut trait_impl, it.0) + } + name => panic!("Unexpected trait impl: `{name}`"), } } @@ -106,9 +109,10 @@ fn set_once(slot: &mut Option, val: T) { let inherent_impl = inherent_method.parent().unwrap(); let wrapper_mod = const_item.parent().unwrap(); let crate_root = wrapper_mod.parent().unwrap(); - assert_eq!(&*wrapper_mod.name(), "wrapper_mod"); + assert_eq!(&*wrapper_mod.name(), "input::wrapper_mod"); // Check that each def-id has the correct parent + assert_eq!(crate_root.name(), "input"); assert_eq!(crate_root.parent(), None); assert_eq!(inherent_impl.parent(), Some(wrapper_mod)); assert_eq!(const_item.parent(), Some(wrapper_mod)); diff --git a/tests/ui-fulldeps/rustc_public/check_def_ty.rs b/tests/ui-fulldeps/rustc_public/check_def_ty.rs index 242b06dcd229..5984d6f8821a 100644 --- a/tests/ui-fulldeps/rustc_public/check_def_ty.rs +++ b/tests/ui-fulldeps/rustc_public/check_def_ty.rs @@ -15,9 +15,12 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate rustc_public; +extern crate rustc_public_bridge; -use rustc_public::ty::{ForeignItemKind, Ty}; +use rustc_public::ty::VariantIdx; +use rustc_public::ty::{ForeignItemKind, RigidTy, Ty}; use rustc_public::*; +use rustc_public_bridge::IndexedVal; use std::io::Write; use std::ops::ControlFlow; @@ -32,6 +35,14 @@ fn test_def_tys() -> ControlFlow<()> { match item.trimmed_name().as_str() { "STATIC_STR" => assert!(ty.kind().is_ref()), "CONST_U32" => assert!(ty.kind().is_integral()), + "NONE" => { + let RigidTy::Adt(adt, _) = *ty.kind().rigid().unwrap() else { panic!() }; + // Definition names include the entire path. + assert_eq!(adt.name(), "std::option::Option"); + // Variant name only includes the actual variant name. + // I know, probably not the best name schema. o.O + assert_eq!(adt.variant(VariantIdx::to_val(0)).unwrap().name(), "None"); + } "main" => check_fn_def(ty), _ => unreachable!("Unexpected item: `{item:?}`"), } @@ -92,6 +103,7 @@ fn generate_input(path: &str) -> std::io::Result<()> { r#" static STATIC_STR: &str = "foo"; const CONST_U32: u32 = 0u32; + static NONE: Option = Option::None; fn main() {{ let _c = core::char::from_u32(99); diff --git a/tests/ui/rustc_public-ir-print/async-closure.stdout b/tests/ui/rustc_public-ir-print/async-closure.stdout index 3ec816b657f4..8df31e2f680a 100644 --- a/tests/ui/rustc_public-ir-print/async-closure.stdout +++ b/tests/ui/rustc_public-ir-print/async-closure.stdout @@ -56,7 +56,7 @@ fn foo::{closure#0}::{closure#0}(_1: Pin<&mut {async closure body@$DIR/async-clo _3 = (*_4); _5 = (); StorageDead(_3); - _0 = std::task::Poll::Ready(move _5); + _0 = Poll::Ready(move _5); discriminant((*_7)) = 1; return; } @@ -88,7 +88,7 @@ fn foo::{closure#0}::{synthetic#0}(_1: Pin<&mut {async closure body@$DIR/async-c _3 = (*_4); _5 = (); StorageDead(_3); - _0 = std::task::Poll::Ready(move _5); + _0 = Poll::Ready(move _5); discriminant((*_7)) = 1; return; } diff --git a/tests/ui/rustc_public-ir-print/operands.stdout b/tests/ui/rustc_public-ir-print/operands.stdout index b7775416af85..58f229be2e6e 100644 --- a/tests/ui/rustc_public-ir-print/operands.stdout +++ b/tests/ui/rustc_public-ir-print/operands.stdout @@ -206,7 +206,7 @@ fn operands(_1: u8) -> () { StorageDead(_19); StorageDead(_18); StorageLive(_21); - _21 = core::panicking::AssertKind::Eq; + _21 = AssertKind::Eq; StorageLive(_22); StorageLive(_23); _23 = move _21; @@ -219,7 +219,7 @@ fn operands(_1: u8) -> () { _27 = &(*_16); _26 = &(*_27); StorageLive(_28); - _28 = std::option::Option::None; + _28 = Option::None; _22 = core::panicking::assert_failed::(move _23, move _24, move _26, move _28) -> unwind unreachable; } bb6: { @@ -268,7 +268,7 @@ fn operands(_1: u8) -> () { StorageDead(_39); StorageDead(_38); StorageLive(_41); - _41 = core::panicking::AssertKind::Eq; + _41 = AssertKind::Eq; StorageLive(_42); StorageLive(_43); _43 = move _41; @@ -281,7 +281,7 @@ fn operands(_1: u8) -> () { _47 = &(*_36); _46 = &(*_47); StorageLive(_48); - _48 = std::option::Option::None; + _48 = Option::None; _42 = core::panicking::assert_failed::(move _43, move _44, move _46, move _48) -> unwind unreachable; } bb8: { @@ -305,7 +305,7 @@ fn operands(_1: u8) -> () { StorageDead(_62); StorageDead(_61); StorageLive(_64); - _64 = core::panicking::AssertKind::Eq; + _64 = AssertKind::Eq; StorageLive(_65); StorageLive(_66); _66 = move _64; @@ -318,7 +318,7 @@ fn operands(_1: u8) -> () { _70 = &(*_59); _69 = &(*_70); StorageLive(_71); - _71 = std::option::Option::None; + _71 = Option::None; _65 = core::panicking::assert_failed::(move _66, move _67, move _69, move _71) -> unwind unreachable; } bb10: { @@ -380,7 +380,7 @@ fn operands(_1: u8) -> () { StorageDead(_86); StorageDead(_85); StorageLive(_88); - _88 = core::panicking::AssertKind::Eq; + _88 = AssertKind::Eq; StorageLive(_89); StorageLive(_90); _90 = move _88; @@ -393,7 +393,7 @@ fn operands(_1: u8) -> () { _94 = &(*_83); _93 = &(*_94); StorageLive(_95); - _95 = std::option::Option::None; + _95 = Option::None; _89 = core::panicking::assert_failed::(move _90, move _91, move _93, move _95) -> unwind unreachable; } } From c5e928d5ac9a65e237aa8158a30c0cca35d30356 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 1 Dec 2025 04:28:14 +0000 Subject: [PATCH 150/585] Prepare for merging from rust-lang/rust This updates the rust-version file to dfe1b8c97bcde283102f706d5dcdc3649e5e12e3. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index bddb68a06b02..7a84872f266d 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -1be6b13be73dc12e98e51b403add4c41a0b77759 +dfe1b8c97bcde283102f706d5dcdc3649e5e12e3 From b111aed11ff1ad640b978b4f4480f56b898bf9f5 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Mon, 24 Nov 2025 14:45:52 +0800 Subject: [PATCH 151/585] fudge infer vars in cause code intentionally --- compiler/rustc_infer/src/traits/mod.rs | 2 + .../src/solve/fulfill/derive_errors.rs | 4 ++ .../leaking-vars-in-cause-code-1.rs | 43 +++++++++++++++++++ .../leaking-vars-in-cause-code-1.stderr | 35 +++++++++++++++ .../leaking-vars-in-cause-code-2.rs | 31 +++++++++++++ .../leaking-vars-in-cause-code-2.stderr | 37 ++++++++++++++++ 6 files changed, 152 insertions(+) create mode 100644 tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.rs create mode 100644 tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.stderr create mode 100644 tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.rs create mode 100644 tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 79a4859f286f..0536a6c90950 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -37,6 +37,8 @@ #[derive(Clone, TypeFoldable, TypeVisitable)] pub struct Obligation<'tcx, T> { /// The reason we have to prove this thing. + /// FIXME: we shouldn't ignore the cause but instead change the affected visitors + /// to only visit predicates manually. #[type_foldable(identity)] #[type_visitable(ignore)] pub cause: ObligationCause<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 8482c8a2972d..eef8b870a5b8 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -177,7 +177,11 @@ fn find_best_leaf_obligation<'tcx>( ) .break_value() .ok_or(()) + // walk around the fact that the cause in `Obligation` is ignored by folders so that + // we can properly fudge the infer vars in cause code. + .map(|o| (o.cause.clone(), o)) }) + .map(|(cause, o)| PredicateObligation { cause, ..o }) .unwrap_or(obligation); deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation) } diff --git a/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.rs b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.rs new file mode 100644 index 000000000000..76a44dbe1abb --- /dev/null +++ b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.rs @@ -0,0 +1,43 @@ +//@ compile-flags: -Znext-solver +//@ edition: 2024 +// +// A regression test for the ICE variant in trait-system-refactor-initiative#245. +// We'll meet regions that're already popped off when using parent predicate in cause code. +// `cause` in `Obligation` is ignored by folders/visitors. +// In this case, `fudge_inference_if_ok` doesn't fudge a region var in cause code. +// +// The old solver doesn't trigger ICE because regions in the predicate are replaced with +// placeholders when checking generator witness. Besides, the old solver doesn't eagerly +// resolves vars before canonicalizing the predicate in `predicate_must_hold_modulo_regions`. + +trait AsyncFn: Send + 'static { + type Fut: Future + Send; + + fn call(&self) -> Self::Fut; +} + +async fn wrap_call(filter: &P) { + filter.call().await; +} + +fn get_boxed_fn() -> Box { + todo!() +} + +async fn cursed_fut() { + wrap_call(get_boxed_fn().as_ref()).await; +} + +fn observe_fut_not_send() { + assert_send(cursed_fut()); + //~^ ERROR: `dyn AsyncFn + Send>>>` cannot be shared between threads safely [E0277] +} + +fn assert_send(t: T) -> T { + t +} + +pub type BoxFuture<'a, T> = std::pin::Pin + Send + 'a>>; +type DynAsyncFnBoxed = dyn AsyncFn>; + +fn main() {} diff --git a/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.stderr b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.stderr new file mode 100644 index 000000000000..a0951863f8a5 --- /dev/null +++ b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.stderr @@ -0,0 +1,35 @@ +error[E0277]: `dyn AsyncFn + Send>>>` cannot be shared between threads safely + --> $DIR/leaking-vars-in-cause-code-1.rs:32:17 + | +LL | assert_send(cursed_fut()); + | ----------- ^^^^^^^^^^^^ `dyn AsyncFn + Send>>>` cannot be shared between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Sync` is not implemented for `dyn AsyncFn + Send>>>` + = note: required for `&dyn AsyncFn + Send>>>` to implement `Send` +note: required because it's used within this `async` fn body + --> $DIR/leaking-vars-in-cause-code-1.rs:19:53 + | +LL | async fn wrap_call(filter: &P) { + | _____________________________________________________^ +LL | | filter.call().await; +LL | | } + | |_^ +note: required because it's used within this `async` fn body + --> $DIR/leaking-vars-in-cause-code-1.rs:27:23 + | +LL | async fn cursed_fut() { + | _______________________^ +LL | | wrap_call(get_boxed_fn().as_ref()).await; +LL | | } + | |_^ +note: required by a bound in `assert_send` + --> $DIR/leaking-vars-in-cause-code-1.rs:36:19 + | +LL | fn assert_send(t: T) -> T { + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.rs b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.rs new file mode 100644 index 000000000000..4dd170c60113 --- /dev/null +++ b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -Znext-solver + +// The `cause` in `Obligation` is ignored by type folders. So infer vars in cause code is not +// fudged. +// Check the comments of +// `leaking-vars-in-cause-code-1.rs` for more details. +trait Trait {} +struct A(T); +struct B(T); + +trait IncompleteGuidance {} + +impl Trait<()> for A +where + T: IncompleteGuidance, +{ +} + +impl Trait<()> for B +//~^ ERROR: the type parameter `U` is not constrained by the impl trait, self type, or predicates +where + A: Trait, +{ +} + +fn impls_trait>() {} + +fn main() { + impls_trait::>(); + //~^ ERROR: the trait bound `(): IncompleteGuidance` is not satisfied +} diff --git a/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr new file mode 100644 index 000000000000..9e8194b46c04 --- /dev/null +++ b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr @@ -0,0 +1,37 @@ +error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates + --> $DIR/leaking-vars-in-cause-code-2.rs:19:9 + | +LL | impl Trait<()> for B + | ^ unconstrained type parameter + +error[E0277]: the trait bound `(): IncompleteGuidance` is not satisfied + --> $DIR/leaking-vars-in-cause-code-2.rs:29:19 + | +LL | impls_trait::>(); + | ^^^^^ the trait `IncompleteGuidance` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/leaking-vars-in-cause-code-2.rs:11:1 + | +LL | trait IncompleteGuidance {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: required for `A<()>` to implement `Trait<()>` + --> $DIR/leaking-vars-in-cause-code-2.rs:13:9 + | +LL | impl Trait<()> for A + | ^^^^^^^^^ ^^^^ +LL | where +LL | T: IncompleteGuidance, + | ------------------ unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `B<()>` to implement `Trait<()>` +note: required by a bound in `impls_trait` + --> $DIR/leaking-vars-in-cause-code-2.rs:26:19 + | +LL | fn impls_trait>() {} + | ^^^^^^^^^ required by this bound in `impls_trait` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0207, E0277. +For more information about an error, try `rustc --explain E0207`. From ae7fa32e5bb2057d92fc8e5e58bc17cf4f045609 Mon Sep 17 00:00:00 2001 From: MolecularPilot Date: Sat, 8 Nov 2025 22:17:55 +1100 Subject: [PATCH 152/585] Implement `clamp_magnitude` for floats & signed integers Added feature gate, documentation and tests also. --- library/core/src/num/f128.rs | 32 ++++ library/core/src/num/f16.rs | 32 ++++ library/core/src/num/f32.rs | 29 ++++ library/core/src/num/f64.rs | 29 ++++ library/core/src/num/int_macros.rs | 27 ++++ library/coretests/tests/lib.rs | 1 + .../coretests/tests/num/clamp_magnitude.rs | 139 ++++++++++++++++++ 7 files changed, 289 insertions(+) create mode 100644 library/coretests/tests/num/clamp_magnitude.rs diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index e7101537b298..f51b561cabf8 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1276,6 +1276,38 @@ pub const fn clamp(mut self, min: f128, max: f128) -> f128 { self } + /// Clamps this number to a symmetric range centered around zero. + /// + /// The method clamps the number's magnitude (absolute value) to be at most `limit`. + /// + /// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more + /// explicit about the intent. + /// + /// # Panics + /// + /// Panics if `limit` is negative or NaN, as this indicates a logic error. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// #![feature(clamp_magnitude)] + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// assert_eq!(5.0f128.clamp_magnitude(3.0), 3.0); + /// assert_eq!((-5.0f128).clamp_magnitude(3.0), -3.0); + /// assert_eq!(2.0f128.clamp_magnitude(3.0), 2.0); + /// assert_eq!((-2.0f128).clamp_magnitude(3.0), -2.0); + /// # } + /// ``` + #[inline] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[must_use = "this returns the clamped value and does not modify the original"] + pub fn clamp_magnitude(self, limit: f128) -> f128 { + assert!(limit >= 0.0, "limit must be non-negative"); + let limit = limit.abs(); // Canonicalises -0.0 to 0.0 + self.clamp(-limit, limit) + } + /// Computes the absolute value of `self`. /// /// This function always returns the precise result. diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index aa8342a22ad5..318c9599ccea 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1254,6 +1254,38 @@ pub const fn clamp(mut self, min: f16, max: f16) -> f16 { self } + /// Clamps this number to a symmetric range centered around zero. + /// + /// The method clamps the number's magnitude (absolute value) to be at most `limit`. + /// + /// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more + /// explicit about the intent. + /// + /// # Panics + /// + /// Panics if `limit` is negative or NaN, as this indicates a logic error. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// #![feature(clamp_magnitude)] + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// assert_eq!(5.0f16.clamp_magnitude(3.0), 3.0); + /// assert_eq!((-5.0f16).clamp_magnitude(3.0), -3.0); + /// assert_eq!(2.0f16.clamp_magnitude(3.0), 2.0); + /// assert_eq!((-2.0f16).clamp_magnitude(3.0), -2.0); + /// # } + /// ``` + #[inline] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[must_use = "this returns the clamped value and does not modify the original"] + pub fn clamp_magnitude(self, limit: f16) -> f16 { + assert!(limit >= 0.0, "limit must be non-negative"); + let limit = limit.abs(); // Canonicalises -0.0 to 0.0 + self.clamp(-limit, limit) + } + /// Computes the absolute value of `self`. /// /// This function always returns the precise result. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 3070e1dedbe4..91e276c5bc8e 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1431,6 +1431,35 @@ pub const fn clamp(mut self, min: f32, max: f32) -> f32 { self } + /// Clamps this number to a symmetric range centered around zero. + /// + /// The method clamps the number's magnitude (absolute value) to be at most `limit`. + /// + /// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more + /// explicit about the intent. + /// + /// # Panics + /// + /// Panics if `limit` is negative or NaN, as this indicates a logic error. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp_magnitude)] + /// assert_eq!(5.0f32.clamp_magnitude(3.0), 3.0); + /// assert_eq!((-5.0f32).clamp_magnitude(3.0), -3.0); + /// assert_eq!(2.0f32.clamp_magnitude(3.0), 2.0); + /// assert_eq!((-2.0f32).clamp_magnitude(3.0), -2.0); + /// ``` + #[must_use = "this returns the clamped value and does not modify the original"] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[inline] + pub fn clamp_magnitude(self, limit: f32) -> f32 { + assert!(limit >= 0.0, "limit must be non-negative"); + let limit = limit.abs(); // Canonicalises -0.0 to 0.0 + self.clamp(-limit, limit) + } + /// Computes the absolute value of `self`. /// /// This function always returns the precise result. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index dc8ccc551b2d..a4b2979c37d0 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1429,6 +1429,35 @@ pub const fn clamp(mut self, min: f64, max: f64) -> f64 { self } + /// Clamps this number to a symmetric range centered around zero. + /// + /// The method clamps the number's magnitude (absolute value) to be at most `limit`. + /// + /// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more + /// explicit about the intent. + /// + /// # Panics + /// + /// Panics if `limit` is negative or NaN, as this indicates a logic error. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp_magnitude)] + /// assert_eq!(5.0f64.clamp_magnitude(3.0), 3.0); + /// assert_eq!((-5.0f64).clamp_magnitude(3.0), -3.0); + /// assert_eq!(2.0f64.clamp_magnitude(3.0), 2.0); + /// assert_eq!((-2.0f64).clamp_magnitude(3.0), -2.0); + /// ``` + #[must_use = "this returns the clamped value and does not modify the original"] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[inline] + pub fn clamp_magnitude(self, limit: f64) -> f64 { + assert!(limit >= 0.0, "limit must be non-negative"); + let limit = limit.abs(); // Canonicalises -0.0 to 0.0 + self.clamp(-limit, limit) + } + /// Computes the absolute value of `self`. /// /// This function always returns the precise result. diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 7d395eb78034..9134d37636f0 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -3855,5 +3855,32 @@ pub const fn min_value() -> Self { pub const fn max_value() -> Self { Self::MAX } + + /// Clamps this number to a symmetric range centred around zero. + /// + /// The method clamps the number's magnitude (absolute value) to be at most `limit`. + /// + /// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more + /// explicit about the intent. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp_magnitude)] + #[doc = concat!("assert_eq!(120", stringify!($SelfT), ".clamp_magnitude(100), 100);")] + #[doc = concat!("assert_eq!(-120", stringify!($SelfT), ".clamp_magnitude(100), -100);")] + #[doc = concat!("assert_eq!(80", stringify!($SelfT), ".clamp_magnitude(100), 80);")] + #[doc = concat!("assert_eq!(-80", stringify!($SelfT), ".clamp_magnitude(100), -80);")] + /// ``` + #[must_use = "this returns the clamped value and does not modify the original"] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[inline] + pub fn clamp_magnitude(self, limit: $UnsignedT) -> Self { + if let Ok(limit) = core::convert::TryInto::<$SelfT>::try_into(limit) { + self.clamp(-limit, limit) + } else { + self + } + } } } diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 80b62038c40e..124a8cf69385 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -15,6 +15,7 @@ #![feature(cfg_target_has_reliable_f16_f128)] #![feature(char_internals)] #![feature(char_max_len)] +#![feature(clamp_magnitude)] #![feature(clone_to_uninit)] #![feature(const_cell_traits)] #![feature(const_cmp)] diff --git a/library/coretests/tests/num/clamp_magnitude.rs b/library/coretests/tests/num/clamp_magnitude.rs new file mode 100644 index 000000000000..0f96e55f6914 --- /dev/null +++ b/library/coretests/tests/num/clamp_magnitude.rs @@ -0,0 +1,139 @@ +macro_rules! check_int_clamp { + ($t:ty, $ut:ty) => { + let min = <$t>::MIN; + let max = <$t>::MAX; + let max_u = <$ut>::MAX; + + // Basic clamping + assert_eq!((100 as $t).clamp_magnitude(50), 50); + assert_eq!((-100 as $t).clamp_magnitude(50), -50); + assert_eq!((30 as $t).clamp_magnitude(50), 30); + assert_eq!((-30 as $t).clamp_magnitude(50), -30); + + // Exact boundary + assert_eq!((50 as $t).clamp_magnitude(50), 50); + assert_eq!((-50 as $t).clamp_magnitude(50), -50); + + // Zero cases + assert_eq!((0 as $t).clamp_magnitude(100), 0); + assert_eq!((0 as $t).clamp_magnitude(0), 0); + assert_eq!((100 as $t).clamp_magnitude(0), 0); + assert_eq!((-100 as $t).clamp_magnitude(0), 0); + + // MIN/MAX values + // Symmetric range [-MAX, MAX] + assert_eq!(max.clamp_magnitude(max as $ut), max); + assert_eq!(min.clamp_magnitude(max as $ut), -max); + + // Full range (limit covers MIN) + let min_abs = min.unsigned_abs(); + assert_eq!(min.clamp_magnitude(min_abs), min); + + // Limit larger than type max (uN > iN::MAX) + assert_eq!(max.clamp_magnitude(max_u), max); + assert_eq!(min.clamp_magnitude(max_u), min); + }; +} + +#[test] +fn test_clamp_magnitude_i8() { + check_int_clamp!(i8, u8); +} + +#[test] +fn test_clamp_magnitude_i16() { + check_int_clamp!(i16, u16); +} + +#[test] +fn test_clamp_magnitude_i32() { + check_int_clamp!(i32, u32); +} + +#[test] +fn test_clamp_magnitude_i64() { + check_int_clamp!(i64, u64); +} + +#[test] +fn test_clamp_magnitude_i128() { + check_int_clamp!(i128, u128); +} + +#[test] +fn test_clamp_magnitude_isize() { + check_int_clamp!(isize, usize); +} + +macro_rules! check_float_clamp { + ($t:ty) => { + // Basic clamping + assert_eq!((5.0 as $t).clamp_magnitude(3.0), 3.0); + assert_eq!((-5.0 as $t).clamp_magnitude(3.0), -3.0); + assert_eq!((2.0 as $t).clamp_magnitude(3.0), 2.0); + assert_eq!((-2.0 as $t).clamp_magnitude(3.0), -2.0); + + // Exact boundary + assert_eq!((3.0 as $t).clamp_magnitude(3.0), 3.0); + assert_eq!((-3.0 as $t).clamp_magnitude(3.0), -3.0); + + // Zero cases + assert_eq!((0.0 as $t).clamp_magnitude(1.0), 0.0); + assert_eq!((-0.0 as $t).clamp_magnitude(1.0), 0.0); + assert_eq!((5.0 as $t).clamp_magnitude(0.0), 0.0); + assert_eq!((-5.0 as $t).clamp_magnitude(0.0), 0.0); + + // Special values - Infinity + let inf = <$t>::INFINITY; + let neg_inf = <$t>::NEG_INFINITY; + assert_eq!(inf.clamp_magnitude(100.0), 100.0); + assert_eq!(neg_inf.clamp_magnitude(100.0), -100.0); + assert_eq!(inf.clamp_magnitude(inf), inf); + + // Value with infinite limit + assert_eq!((1.0 as $t).clamp_magnitude(inf), 1.0); + assert_eq!((-1.0 as $t).clamp_magnitude(inf), -1.0); + + // MIN and MAX + let max = <$t>::MAX; + let min = <$t>::MIN; + // Large limit + let huge = 1e30; + assert_eq!(max.clamp_magnitude(huge), huge); + assert_eq!(min.clamp_magnitude(huge), -huge); + }; +} + +#[test] +fn test_clamp_magnitude_f32() { + check_float_clamp!(f32); +} + +#[test] +fn test_clamp_magnitude_f64() { + check_float_clamp!(f64); +} + +#[test] +#[should_panic(expected = "limit must be non-negative")] +fn test_clamp_magnitude_f32_panic_negative_limit() { + let _ = 1.0f32.clamp_magnitude(-1.0); +} + +#[test] +#[should_panic(expected = "limit must be non-negative")] +fn test_clamp_magnitude_f64_panic_negative_limit() { + let _ = 1.0f64.clamp_magnitude(-1.0); +} + +#[test] +#[should_panic] +fn test_clamp_magnitude_f32_panic_nan_limit() { + let _ = 1.0f32.clamp_magnitude(f32::NAN); +} + +#[test] +#[should_panic] +fn test_clamp_magnitude_f64_panic_nan_limit() { + let _ = 1.0f64.clamp_magnitude(f64::NAN); +} From 77afccf73b0a6eed56ed08768de17434f625ff4a Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sun, 30 Nov 2025 14:14:35 +0900 Subject: [PATCH 153/585] moved and delete test tests/ui/invalid-module-declaration/invalid-module-declaration.rs duplicated of tests/ui/modules/missing_non_modrs_mod_inline.rs --- tests/ui/README.md | 26 ------------------- .../explicit-call-to-dtor.fixed | 0 .../explicit-call-to-dtor.rs | 0 .../explicit-call-to-dtor.stderr | 0 .../explicit-call-to-supertrait-dtor.fixed | 0 .../explicit-call-to-supertrait-dtor.rs | 0 .../explicit-call-to-supertrait-dtor.stderr | 0 .../auxiliary/foo/bar.rs | 1 - .../auxiliary/foo/mod.rs | 1 - .../invalid-module-declaration.rs | 7 ----- .../invalid-module-declaration.stderr | 12 --------- .../explicit-self-lifetime-mismatch.rs | 0 .../explicit-self-lifetime-mismatch.stderr | 0 .../bare-fn-start.rs | 0 .../bare-fn-start.stderr | 0 .../invalid-self-argument.rs} | 0 .../invalid-self-argument.stderr} | 0 .../trait-fn.rs | 0 .../trait-fn.stderr | 0 .../catch-unwind-cell-interior-mut.rs} | 0 .../catch-unwind-cell-interior-mut.stderr} | 0 21 files changed, 47 deletions(-) rename tests/ui/{explicit => drop}/explicit-call-to-dtor.fixed (100%) rename tests/ui/{explicit => drop}/explicit-call-to-dtor.rs (100%) rename tests/ui/{explicit => drop}/explicit-call-to-dtor.stderr (100%) rename tests/ui/{explicit => drop}/explicit-call-to-supertrait-dtor.fixed (100%) rename tests/ui/{explicit => drop}/explicit-call-to-supertrait-dtor.rs (100%) rename tests/ui/{explicit => drop}/explicit-call-to-supertrait-dtor.stderr (100%) delete mode 100644 tests/ui/invalid-module-declaration/auxiliary/foo/bar.rs delete mode 100644 tests/ui/invalid-module-declaration/auxiliary/foo/mod.rs delete mode 100644 tests/ui/invalid-module-declaration/invalid-module-declaration.rs delete mode 100644 tests/ui/invalid-module-declaration/invalid-module-declaration.stderr rename tests/ui/{explicit => lifetimes}/explicit-self-lifetime-mismatch.rs (100%) rename tests/ui/{explicit => lifetimes}/explicit-self-lifetime-mismatch.stderr (100%) rename tests/ui/{invalid-self-argument => self}/bare-fn-start.rs (100%) rename tests/ui/{invalid-self-argument => self}/bare-fn-start.stderr (100%) rename tests/ui/{invalid-self-argument/bare-fn.rs => self/invalid-self-argument.rs} (100%) rename tests/ui/{invalid-self-argument/bare-fn.stderr => self/invalid-self-argument.stderr} (100%) rename tests/ui/{invalid-self-argument => self}/trait-fn.rs (100%) rename tests/ui/{invalid-self-argument => self}/trait-fn.stderr (100%) rename tests/ui/{interior-mutability/interior-mutability.rs => traits/catch-unwind-cell-interior-mut.rs} (100%) rename tests/ui/{interior-mutability/interior-mutability.stderr => traits/catch-unwind-cell-interior-mut.stderr} (100%) diff --git a/tests/ui/README.md b/tests/ui/README.md index 11003bbef992..344b0b2500df 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -113,12 +113,6 @@ See [Tracking Issue for autodiff #124509](https://github.com/rust-lang/rust/issu Tests for automatic referencing and dereferencing behavior, such as automatically adding reference operations (`&` or `&mut`) to make a value match a method's receiver type. Sometimes abbreviated as "auto-ref" or "auto-deref". -## `tests/ui/auxiliary/`: Auxiliary files for tests directly under `tests/ui`. - -This top-level `auxiliary` subdirectory contains support files for tests immediately under `tests/ui/`. - -**FIXME(#133895)**: tests immediately under `tests/ui/` should be rehomed to more suitable subdirectories, after which this subdirectory can be removed. - ## `tests/ui/backtrace/`: Backtraces Runtime panics and error handling generate backtraces to assist in debugging and diagnostics. @@ -542,12 +536,6 @@ These tests are about very different topics, only unified by the fact that they Accompanies `tests/ui/error-codes/`, exercises the `--explain` cli flag. -## `tests/ui/explicit/`: Errors involving the concept of "explicit" - -This category contains three tests: two which are about the specific error `explicit use of destructor method`, and one which is about explicit annotation of lifetimes: https://doc.rust-lang.org/stable/rust-by-example/scope/lifetime/explicit.html. - -**FIXME**: Rehome the two tests about the destructor method with `drop`-related categories, and rehome the last test with a category related to lifetimes. - ## `tests/ui/explicit-tail-calls/` Exercises `#![feature(explicit_tail_calls)]` and the `become` keyword. See [Explicit Tail Calls #3407](https://github.com/rust-lang/rfcs/pull/3407). @@ -733,10 +721,6 @@ See [Instrument coverage | The rustc book](https://doc.rust-lang.org/rustc/instr See [Tracking issue for `-Z instrument-xray` #102921](https://github.com/rust-lang/rust/issues/102921). -## `tests/ui/interior-mutability/` - -**FIXME**: contains a single test, probably better rehomed. - ## `tests/ui/internal/` Tests for `internal_unstable` and the attribute header `#![feature(allow_internal_unstable)]`, which lets compiler developers mark features as internal to the compiler, and unstable for standard library use. @@ -759,16 +743,6 @@ Various tests related to rejecting invalid inputs. Tests for checking that invalid usage of compiler flags are rejected. -## `tests/ui/invalid-module-declaration/` - -**FIXME**: Consider merging into module/resolve directories. - -## `tests/ui/invalid-self-argument/`: `self` as a function argument incorrectly - -Tests with erroneous ways of using `self`, such as having it not be the first argument, or using it in a non-associated function (no `impl` or `trait`). - -**FIXME**: Maybe merge with `ui/self`. - ## `tests/ui/io-checks/` Contains a single test. The test tries to output a file into an invalid directory with `-o`, then checks that the result is an error, not an internal compiler error. diff --git a/tests/ui/explicit/explicit-call-to-dtor.fixed b/tests/ui/drop/explicit-call-to-dtor.fixed similarity index 100% rename from tests/ui/explicit/explicit-call-to-dtor.fixed rename to tests/ui/drop/explicit-call-to-dtor.fixed diff --git a/tests/ui/explicit/explicit-call-to-dtor.rs b/tests/ui/drop/explicit-call-to-dtor.rs similarity index 100% rename from tests/ui/explicit/explicit-call-to-dtor.rs rename to tests/ui/drop/explicit-call-to-dtor.rs diff --git a/tests/ui/explicit/explicit-call-to-dtor.stderr b/tests/ui/drop/explicit-call-to-dtor.stderr similarity index 100% rename from tests/ui/explicit/explicit-call-to-dtor.stderr rename to tests/ui/drop/explicit-call-to-dtor.stderr diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed b/tests/ui/drop/explicit-call-to-supertrait-dtor.fixed similarity index 100% rename from tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed rename to tests/ui/drop/explicit-call-to-supertrait-dtor.fixed diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs b/tests/ui/drop/explicit-call-to-supertrait-dtor.rs similarity index 100% rename from tests/ui/explicit/explicit-call-to-supertrait-dtor.rs rename to tests/ui/drop/explicit-call-to-supertrait-dtor.rs diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr b/tests/ui/drop/explicit-call-to-supertrait-dtor.stderr similarity index 100% rename from tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr rename to tests/ui/drop/explicit-call-to-supertrait-dtor.stderr diff --git a/tests/ui/invalid-module-declaration/auxiliary/foo/bar.rs b/tests/ui/invalid-module-declaration/auxiliary/foo/bar.rs deleted file mode 100644 index bcfd7dc0ade7..000000000000 --- a/tests/ui/invalid-module-declaration/auxiliary/foo/bar.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod baz; diff --git a/tests/ui/invalid-module-declaration/auxiliary/foo/mod.rs b/tests/ui/invalid-module-declaration/auxiliary/foo/mod.rs deleted file mode 100644 index 46f285ca47d6..000000000000 --- a/tests/ui/invalid-module-declaration/auxiliary/foo/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod bar; diff --git a/tests/ui/invalid-module-declaration/invalid-module-declaration.rs b/tests/ui/invalid-module-declaration/invalid-module-declaration.rs deleted file mode 100644 index 1c6c282f4b7e..000000000000 --- a/tests/ui/invalid-module-declaration/invalid-module-declaration.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod auxiliary { - mod foo; -} - -fn main() {} - -//~? ERROR file not found for module `baz` diff --git a/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr b/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr deleted file mode 100644 index a8f65883d636..000000000000 --- a/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0583]: file not found for module `baz` - --> $DIR/auxiliary/foo/bar.rs:1:1 - | -LL | pub mod baz; - | ^^^^^^^^^^^^ - | - = help: to create the module `baz`, create file "$DIR/auxiliary/foo/bar/baz.rs" or "$DIR/auxiliary/foo/bar/baz/mod.rs" - = note: if there is a `mod baz` elsewhere in the crate already, import it with `use crate::...` instead - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0583`. diff --git a/tests/ui/explicit/explicit-self-lifetime-mismatch.rs b/tests/ui/lifetimes/explicit-self-lifetime-mismatch.rs similarity index 100% rename from tests/ui/explicit/explicit-self-lifetime-mismatch.rs rename to tests/ui/lifetimes/explicit-self-lifetime-mismatch.rs diff --git a/tests/ui/explicit/explicit-self-lifetime-mismatch.stderr b/tests/ui/lifetimes/explicit-self-lifetime-mismatch.stderr similarity index 100% rename from tests/ui/explicit/explicit-self-lifetime-mismatch.stderr rename to tests/ui/lifetimes/explicit-self-lifetime-mismatch.stderr diff --git a/tests/ui/invalid-self-argument/bare-fn-start.rs b/tests/ui/self/bare-fn-start.rs similarity index 100% rename from tests/ui/invalid-self-argument/bare-fn-start.rs rename to tests/ui/self/bare-fn-start.rs diff --git a/tests/ui/invalid-self-argument/bare-fn-start.stderr b/tests/ui/self/bare-fn-start.stderr similarity index 100% rename from tests/ui/invalid-self-argument/bare-fn-start.stderr rename to tests/ui/self/bare-fn-start.stderr diff --git a/tests/ui/invalid-self-argument/bare-fn.rs b/tests/ui/self/invalid-self-argument.rs similarity index 100% rename from tests/ui/invalid-self-argument/bare-fn.rs rename to tests/ui/self/invalid-self-argument.rs diff --git a/tests/ui/invalid-self-argument/bare-fn.stderr b/tests/ui/self/invalid-self-argument.stderr similarity index 100% rename from tests/ui/invalid-self-argument/bare-fn.stderr rename to tests/ui/self/invalid-self-argument.stderr diff --git a/tests/ui/invalid-self-argument/trait-fn.rs b/tests/ui/self/trait-fn.rs similarity index 100% rename from tests/ui/invalid-self-argument/trait-fn.rs rename to tests/ui/self/trait-fn.rs diff --git a/tests/ui/invalid-self-argument/trait-fn.stderr b/tests/ui/self/trait-fn.stderr similarity index 100% rename from tests/ui/invalid-self-argument/trait-fn.stderr rename to tests/ui/self/trait-fn.stderr diff --git a/tests/ui/interior-mutability/interior-mutability.rs b/tests/ui/traits/catch-unwind-cell-interior-mut.rs similarity index 100% rename from tests/ui/interior-mutability/interior-mutability.rs rename to tests/ui/traits/catch-unwind-cell-interior-mut.rs diff --git a/tests/ui/interior-mutability/interior-mutability.stderr b/tests/ui/traits/catch-unwind-cell-interior-mut.stderr similarity index 100% rename from tests/ui/interior-mutability/interior-mutability.stderr rename to tests/ui/traits/catch-unwind-cell-interior-mut.stderr From 968376d507d86e935cc0f61da9c206fbf9633bdb Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Sun, 30 Nov 2025 22:03:21 +0300 Subject: [PATCH 154/585] Add label rib when visiting delegation body, add test --- compiler/rustc_resolve/src/late.rs | 6 +++++- tests/ui/delegation/ice-issue-148889.rs | 18 ++++++++++++++++++ tests/ui/delegation/ice-issue-148889.stderr | 13 +++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/ui/delegation/ice-issue-148889.rs create mode 100644 tests/ui/delegation/ice-issue-148889.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index df620ddb6652..b689765bf6fa 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3689,7 +3689,11 @@ fn resolve_delegation(&mut self, delegation: &'ast Delegation) { let ident = Ident::new(kw::SelfLower, span.normalize_to_macro_rules()); let res = Res::Local(delegation.id); this.innermost_rib_bindings(ValueNS).insert(ident, res); - this.visit_block(body); + + //As we lower target_expr_template body to a body of a function we need a label rib (#148889) + this.with_label_rib(RibKind::FnOrCoroutine, |this| { + this.visit_block(body); + }); }); } diff --git a/tests/ui/delegation/ice-issue-148889.rs b/tests/ui/delegation/ice-issue-148889.rs new file mode 100644 index 000000000000..e5f9fa1cf493 --- /dev/null +++ b/tests/ui/delegation/ice-issue-148889.rs @@ -0,0 +1,18 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +trait Trait { + fn static_method2(x: i32, y: i32) -> i32 { + x + y + } +} + +struct S; +impl Trait for S {} + +pub fn main() { + 'foo: loop { + reuse ::static_method2 { loop { break 'foo; } } + //~^ ERROR use of unreachable label `'foo` + } +} diff --git a/tests/ui/delegation/ice-issue-148889.stderr b/tests/ui/delegation/ice-issue-148889.stderr new file mode 100644 index 000000000000..2ebc7b3ec14e --- /dev/null +++ b/tests/ui/delegation/ice-issue-148889.stderr @@ -0,0 +1,13 @@ +error[E0767]: use of unreachable label `'foo` + --> $DIR/ice-issue-148889.rs:15:59 + | +LL | 'foo: loop { + | ---- unreachable label defined here +LL | reuse ::static_method2 { loop { break 'foo; } } + | ^^^^ unreachable label `'foo` + | + = note: labels are unreachable through functions, closures, async blocks and modules + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0767`. From 18d0c379048a59966c22af0b602c924498d517bb Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Mon, 1 Dec 2025 18:55:14 +0900 Subject: [PATCH 155/585] moved tests --- tests/ui/{issues/issue-3290.rs => box/self-assignment.rs} | 0 .../break-continue-in-loop-while-condition-1.rs} | 0 .../break-continue-in-loop-while-condition-1.stderr} | 0 .../break-continue-in-loop-while-condition-2.rs} | 0 .../break-continue-in-loop-while-condition-2.stderr} | 0 .../issue-3680.rs => match/match-option-result-mismatch.rs} | 0 .../match-option-result-mismatch.stderr} | 0 tests/ui/{issues/issue-3091.rs => numeric/ref-int.rs} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-3290.rs => box/self-assignment.rs} (100%) rename tests/ui/{issues/issue-37576.rs => for-loop-while/break-continue-in-loop-while-condition-1.rs} (100%) rename tests/ui/{issues/issue-37576.stderr => for-loop-while/break-continue-in-loop-while-condition-1.stderr} (100%) rename tests/ui/{issues/issue-50802.rs => for-loop-while/break-continue-in-loop-while-condition-2.rs} (100%) rename tests/ui/{issues/issue-50802.stderr => for-loop-while/break-continue-in-loop-while-condition-2.stderr} (100%) rename tests/ui/{issues/issue-3680.rs => match/match-option-result-mismatch.rs} (100%) rename tests/ui/{issues/issue-3680.stderr => match/match-option-result-mismatch.stderr} (100%) rename tests/ui/{issues/issue-3091.rs => numeric/ref-int.rs} (100%) diff --git a/tests/ui/issues/issue-3290.rs b/tests/ui/box/self-assignment.rs similarity index 100% rename from tests/ui/issues/issue-3290.rs rename to tests/ui/box/self-assignment.rs diff --git a/tests/ui/issues/issue-37576.rs b/tests/ui/for-loop-while/break-continue-in-loop-while-condition-1.rs similarity index 100% rename from tests/ui/issues/issue-37576.rs rename to tests/ui/for-loop-while/break-continue-in-loop-while-condition-1.rs diff --git a/tests/ui/issues/issue-37576.stderr b/tests/ui/for-loop-while/break-continue-in-loop-while-condition-1.stderr similarity index 100% rename from tests/ui/issues/issue-37576.stderr rename to tests/ui/for-loop-while/break-continue-in-loop-while-condition-1.stderr diff --git a/tests/ui/issues/issue-50802.rs b/tests/ui/for-loop-while/break-continue-in-loop-while-condition-2.rs similarity index 100% rename from tests/ui/issues/issue-50802.rs rename to tests/ui/for-loop-while/break-continue-in-loop-while-condition-2.rs diff --git a/tests/ui/issues/issue-50802.stderr b/tests/ui/for-loop-while/break-continue-in-loop-while-condition-2.stderr similarity index 100% rename from tests/ui/issues/issue-50802.stderr rename to tests/ui/for-loop-while/break-continue-in-loop-while-condition-2.stderr diff --git a/tests/ui/issues/issue-3680.rs b/tests/ui/match/match-option-result-mismatch.rs similarity index 100% rename from tests/ui/issues/issue-3680.rs rename to tests/ui/match/match-option-result-mismatch.rs diff --git a/tests/ui/issues/issue-3680.stderr b/tests/ui/match/match-option-result-mismatch.stderr similarity index 100% rename from tests/ui/issues/issue-3680.stderr rename to tests/ui/match/match-option-result-mismatch.stderr diff --git a/tests/ui/issues/issue-3091.rs b/tests/ui/numeric/ref-int.rs similarity index 100% rename from tests/ui/issues/issue-3091.rs rename to tests/ui/numeric/ref-int.rs From a4a79500b5e8e848bb9a0db67604d03e9de38ad9 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sun, 30 Nov 2025 14:36:05 +0900 Subject: [PATCH 156/585] Cleaned up some tests fix explicit-call-to-dtor.rs fix explicit-call-to-supertrait-dtor.rs merge issues/issue-17740.rs with lifetimes/explicit-self-lifetime-mismatch.rs merge bare-fn-start.rs and trait-fn.rs into invalid-self-argument.rs add comment tests/ui/traits/catch-unwind-cell-interior-mut --- tests/ui/drop/explicit-call-to-dtor.fixed | 4 +- tests/ui/drop/explicit-call-to-dtor.rs | 4 +- .../explicit-call-to-supertrait-dtor.fixed | 4 +- .../drop/explicit-call-to-supertrait-dtor.rs | 4 +- tests/ui/issues/issue-17740.rs | 20 ------ tests/ui/issues/issue-17740.stderr | 41 ----------- .../explicit-self-lifetime-mismatch.rs | 45 ++++++++---- .../explicit-self-lifetime-mismatch.stderr | 72 ++++++++++++++----- tests/ui/self/bare-fn-start.rs | 6 -- tests/ui/self/bare-fn-start.stderr | 10 --- tests/ui/self/invalid-self-argument.rs | 21 +++++- tests/ui/self/invalid-self-argument.stderr | 20 +++++- tests/ui/self/trait-fn.rs | 11 --- tests/ui/self/trait-fn.stderr | 8 --- .../traits/catch-unwind-cell-interior-mut.rs | 1 + .../catch-unwind-cell-interior-mut.stderr | 4 +- 16 files changed, 134 insertions(+), 141 deletions(-) delete mode 100644 tests/ui/issues/issue-17740.rs delete mode 100644 tests/ui/issues/issue-17740.stderr delete mode 100644 tests/ui/self/bare-fn-start.rs delete mode 100644 tests/ui/self/bare-fn-start.stderr delete mode 100644 tests/ui/self/trait-fn.rs delete mode 100644 tests/ui/self/trait-fn.stderr diff --git a/tests/ui/drop/explicit-call-to-dtor.fixed b/tests/ui/drop/explicit-call-to-dtor.fixed index 4c4142c79811..167f557a6125 100644 --- a/tests/ui/drop/explicit-call-to-dtor.fixed +++ b/tests/ui/drop/explicit-call-to-dtor.fixed @@ -1,6 +1,6 @@ //@ run-rustfix struct Foo { - x: isize + x: isize, } impl Drop for Foo { @@ -12,5 +12,5 @@ impl Drop for Foo { fn main() { let x = Foo { x: 3 }; println!("{}", x.x); - drop(x); //~ ERROR explicit use of destructor method + drop(x); //~ ERROR explicit use of destructor method } diff --git a/tests/ui/drop/explicit-call-to-dtor.rs b/tests/ui/drop/explicit-call-to-dtor.rs index 262dde54c7f6..2c4e013f5c94 100644 --- a/tests/ui/drop/explicit-call-to-dtor.rs +++ b/tests/ui/drop/explicit-call-to-dtor.rs @@ -1,6 +1,6 @@ //@ run-rustfix struct Foo { - x: isize + x: isize, } impl Drop for Foo { @@ -12,5 +12,5 @@ fn drop(&mut self) { fn main() { let x = Foo { x: 3 }; println!("{}", x.x); - x.drop(); //~ ERROR explicit use of destructor method + x.drop(); //~ ERROR explicit use of destructor method } diff --git a/tests/ui/drop/explicit-call-to-supertrait-dtor.fixed b/tests/ui/drop/explicit-call-to-supertrait-dtor.fixed index 57cb858aa089..1526f7b46ea1 100644 --- a/tests/ui/drop/explicit-call-to-supertrait-dtor.fixed +++ b/tests/ui/drop/explicit-call-to-supertrait-dtor.fixed @@ -4,7 +4,7 @@ #![allow(dropping_references)] struct Foo { - x: isize + x: isize, } #[allow(drop_bounds)] @@ -20,7 +20,7 @@ impl Drop for Foo { impl Bar for Foo { fn blah(&self) { - drop(self); //~ ERROR explicit use of destructor method + drop(self); //~ ERROR explicit use of destructor method } } diff --git a/tests/ui/drop/explicit-call-to-supertrait-dtor.rs b/tests/ui/drop/explicit-call-to-supertrait-dtor.rs index bb29e4952420..2de3d008aaae 100644 --- a/tests/ui/drop/explicit-call-to-supertrait-dtor.rs +++ b/tests/ui/drop/explicit-call-to-supertrait-dtor.rs @@ -4,7 +4,7 @@ #![allow(dropping_references)] struct Foo { - x: isize + x: isize, } #[allow(drop_bounds)] @@ -20,7 +20,7 @@ fn drop(&mut self) { impl Bar for Foo { fn blah(&self) { - self.drop(); //~ ERROR explicit use of destructor method + self.drop(); //~ ERROR explicit use of destructor method } } diff --git a/tests/ui/issues/issue-17740.rs b/tests/ui/issues/issue-17740.rs deleted file mode 100644 index 20a73756ea3e..000000000000 --- a/tests/ui/issues/issue-17740.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ dont-require-annotations: NOTE - -struct Foo<'a> { - data: &'a[u8], -} - -impl <'a> Foo<'a>{ - fn bar(self: &mut Foo) { - //~^ ERROR mismatched `self` parameter type - //~| NOTE expected struct `Foo<'a>` - //~| NOTE found struct `Foo<'_>` - //~| NOTE lifetime mismatch - //~| ERROR mismatched `self` parameter type - //~| NOTE expected struct `Foo<'a>` - //~| NOTE found struct `Foo<'_>` - //~| NOTE lifetime mismatch - } -} - -fn main() {} diff --git a/tests/ui/issues/issue-17740.stderr b/tests/ui/issues/issue-17740.stderr deleted file mode 100644 index 198d7d5b37cc..000000000000 --- a/tests/ui/issues/issue-17740.stderr +++ /dev/null @@ -1,41 +0,0 @@ -error[E0308]: mismatched `self` parameter type - --> $DIR/issue-17740.rs:8:18 - | -LL | fn bar(self: &mut Foo) { - | ^^^^^^^^ lifetime mismatch - | - = note: expected struct `Foo<'a>` - found struct `Foo<'_>` -note: the anonymous lifetime defined here... - --> $DIR/issue-17740.rs:8:23 - | -LL | fn bar(self: &mut Foo) { - | ^^^ -note: ...does not necessarily outlive the lifetime `'a` as defined here - --> $DIR/issue-17740.rs:7:7 - | -LL | impl <'a> Foo<'a>{ - | ^^ - -error[E0308]: mismatched `self` parameter type - --> $DIR/issue-17740.rs:8:18 - | -LL | fn bar(self: &mut Foo) { - | ^^^^^^^^ lifetime mismatch - | - = note: expected struct `Foo<'a>` - found struct `Foo<'_>` -note: the lifetime `'a` as defined here... - --> $DIR/issue-17740.rs:7:7 - | -LL | impl <'a> Foo<'a>{ - | ^^ -note: ...does not necessarily outlive the anonymous lifetime defined here - --> $DIR/issue-17740.rs:8:23 - | -LL | fn bar(self: &mut Foo) { - | ^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lifetimes/explicit-self-lifetime-mismatch.rs b/tests/ui/lifetimes/explicit-self-lifetime-mismatch.rs index aa5e352b6ebe..88b9d86a9fdf 100644 --- a/tests/ui/lifetimes/explicit-self-lifetime-mismatch.rs +++ b/tests/ui/lifetimes/explicit-self-lifetime-mismatch.rs @@ -1,22 +1,41 @@ //@ dont-require-annotations: NOTE +//! regression test for -struct Foo<'a,'b> { +struct Foo<'a, 'b> { x: &'a isize, y: &'b isize, } -impl<'a,'b> Foo<'a,'b> { - fn bar(self: - Foo<'b,'a> - //~^ ERROR mismatched `self` parameter type - //~| NOTE expected struct `Foo<'a, 'b>` - //~| NOTE found struct `Foo<'b, 'a>` - //~| NOTE lifetime mismatch - //~| ERROR mismatched `self` parameter type - //~| NOTE expected struct `Foo<'a, 'b>` - //~| NOTE found struct `Foo<'b, 'a>` - //~| NOTE lifetime mismatch - ) {} +impl<'a, 'b> Foo<'a, 'b> { + fn bar( + self: Foo<'b, 'a>, + //~^ ERROR mismatched `self` parameter type + //~| NOTE expected struct `Foo<'a, 'b>` + //~| NOTE found struct `Foo<'b, 'a>` + //~| NOTE lifetime mismatch + //~| ERROR mismatched `self` parameter type + //~| NOTE expected struct `Foo<'a, 'b>` + //~| NOTE found struct `Foo<'b, 'a>` + //~| NOTE lifetime mismatch + ) { + } +} + +struct Bar<'a> { + data: &'a [u8], +} + +impl<'a> Bar<'a> { + fn bar(self: &mut Bar) { + //~^ ERROR mismatched `self` parameter type + //~| NOTE expected struct `Bar<'a>` + //~| NOTE found struct `Bar<'_>` + //~| NOTE lifetime mismatch + //~| ERROR mismatched `self` parameter type + //~| NOTE expected struct `Bar<'a>` + //~| NOTE found struct `Bar<'_>` + //~| NOTE lifetime mismatch + } } fn main() {} diff --git a/tests/ui/lifetimes/explicit-self-lifetime-mismatch.stderr b/tests/ui/lifetimes/explicit-self-lifetime-mismatch.stderr index a20901e8c74d..ebd6383cb4de 100644 --- a/tests/ui/lifetimes/explicit-self-lifetime-mismatch.stderr +++ b/tests/ui/lifetimes/explicit-self-lifetime-mismatch.stderr @@ -1,41 +1,79 @@ error[E0308]: mismatched `self` parameter type - --> $DIR/explicit-self-lifetime-mismatch.rs:10:12 + --> $DIR/explicit-self-lifetime-mismatch.rs:11:15 | -LL | Foo<'b,'a> - | ^^^^^^^^^^ lifetime mismatch +LL | self: Foo<'b, 'a>, + | ^^^^^^^^^^^ lifetime mismatch | = note: expected struct `Foo<'a, 'b>` found struct `Foo<'b, 'a>` note: the lifetime `'b` as defined here... - --> $DIR/explicit-self-lifetime-mismatch.rs:8:9 + --> $DIR/explicit-self-lifetime-mismatch.rs:9:10 | -LL | impl<'a,'b> Foo<'a,'b> { - | ^^ +LL | impl<'a, 'b> Foo<'a, 'b> { + | ^^ note: ...does not necessarily outlive the lifetime `'a` as defined here - --> $DIR/explicit-self-lifetime-mismatch.rs:8:6 + --> $DIR/explicit-self-lifetime-mismatch.rs:9:6 | -LL | impl<'a,'b> Foo<'a,'b> { +LL | impl<'a, 'b> Foo<'a, 'b> { | ^^ error[E0308]: mismatched `self` parameter type - --> $DIR/explicit-self-lifetime-mismatch.rs:10:12 + --> $DIR/explicit-self-lifetime-mismatch.rs:11:15 | -LL | Foo<'b,'a> - | ^^^^^^^^^^ lifetime mismatch +LL | self: Foo<'b, 'a>, + | ^^^^^^^^^^^ lifetime mismatch | = note: expected struct `Foo<'a, 'b>` found struct `Foo<'b, 'a>` note: the lifetime `'a` as defined here... - --> $DIR/explicit-self-lifetime-mismatch.rs:8:6 + --> $DIR/explicit-self-lifetime-mismatch.rs:9:6 | -LL | impl<'a,'b> Foo<'a,'b> { +LL | impl<'a, 'b> Foo<'a, 'b> { | ^^ note: ...does not necessarily outlive the lifetime `'b` as defined here - --> $DIR/explicit-self-lifetime-mismatch.rs:8:9 + --> $DIR/explicit-self-lifetime-mismatch.rs:9:10 | -LL | impl<'a,'b> Foo<'a,'b> { - | ^^ +LL | impl<'a, 'b> Foo<'a, 'b> { + | ^^ -error: aborting due to 2 previous errors +error[E0308]: mismatched `self` parameter type + --> $DIR/explicit-self-lifetime-mismatch.rs:29:18 + | +LL | fn bar(self: &mut Bar) { + | ^^^^^^^^ lifetime mismatch + | + = note: expected struct `Bar<'a>` + found struct `Bar<'_>` +note: the anonymous lifetime defined here... + --> $DIR/explicit-self-lifetime-mismatch.rs:29:23 + | +LL | fn bar(self: &mut Bar) { + | ^^^ +note: ...does not necessarily outlive the lifetime `'a` as defined here + --> $DIR/explicit-self-lifetime-mismatch.rs:28:6 + | +LL | impl<'a> Bar<'a> { + | ^^ + +error[E0308]: mismatched `self` parameter type + --> $DIR/explicit-self-lifetime-mismatch.rs:29:18 + | +LL | fn bar(self: &mut Bar) { + | ^^^^^^^^ lifetime mismatch + | + = note: expected struct `Bar<'a>` + found struct `Bar<'_>` +note: the lifetime `'a` as defined here... + --> $DIR/explicit-self-lifetime-mismatch.rs:28:6 + | +LL | impl<'a> Bar<'a> { + | ^^ +note: ...does not necessarily outlive the anonymous lifetime defined here + --> $DIR/explicit-self-lifetime-mismatch.rs:29:23 + | +LL | fn bar(self: &mut Bar) { + | ^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/self/bare-fn-start.rs b/tests/ui/self/bare-fn-start.rs deleted file mode 100644 index 7c580bc5a5de..000000000000 --- a/tests/ui/self/bare-fn-start.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn a(&self) { } -//~^ ERROR `self` parameter is only allowed in associated functions -//~| NOTE not semantically valid as function parameter -//~| NOTE associated functions are those in `impl` or `trait` definitions - -fn main() { } diff --git a/tests/ui/self/bare-fn-start.stderr b/tests/ui/self/bare-fn-start.stderr deleted file mode 100644 index bf7160bcd2d3..000000000000 --- a/tests/ui/self/bare-fn-start.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: `self` parameter is only allowed in associated functions - --> $DIR/bare-fn-start.rs:1:6 - | -LL | fn a(&self) { } - | ^^^^^ not semantically valid as function parameter - | - = note: associated functions are those in `impl` or `trait` definitions - -error: aborting due to 1 previous error - diff --git a/tests/ui/self/invalid-self-argument.rs b/tests/ui/self/invalid-self-argument.rs index 342bdc31a7c8..fef687e194cb 100644 --- a/tests/ui/self/invalid-self-argument.rs +++ b/tests/ui/self/invalid-self-argument.rs @@ -1,5 +1,22 @@ -fn b(foo: u32, &mut self) { } +//! regression test for + +fn a(&self) {} +//~^ ERROR `self` parameter is only allowed in associated functions +//~| NOTE not semantically valid as function parameter +//~| NOTE associated functions are those in `impl` or `trait` definitions + +fn b(foo: u32, &mut self) {} //~^ ERROR unexpected `self` parameter in function //~| NOTE must be the first parameter of an associated function -fn main() { } +struct Foo {} + +impl Foo { + fn c(foo: u32, self) {} + //~^ ERROR unexpected `self` parameter in function + //~| NOTE must be the first parameter of an associated function + + fn good(&mut self, foo: u32) {} +} + +fn main() {} diff --git a/tests/ui/self/invalid-self-argument.stderr b/tests/ui/self/invalid-self-argument.stderr index 7abb56602d4b..c92e5b2492bf 100644 --- a/tests/ui/self/invalid-self-argument.stderr +++ b/tests/ui/self/invalid-self-argument.stderr @@ -1,8 +1,22 @@ error: unexpected `self` parameter in function - --> $DIR/bare-fn.rs:1:16 + --> $DIR/invalid-self-argument.rs:8:16 | -LL | fn b(foo: u32, &mut self) { } +LL | fn b(foo: u32, &mut self) {} | ^^^^^^^^^ must be the first parameter of an associated function -error: aborting due to 1 previous error +error: unexpected `self` parameter in function + --> $DIR/invalid-self-argument.rs:15:20 + | +LL | fn c(foo: u32, self) {} + | ^^^^ must be the first parameter of an associated function + +error: `self` parameter is only allowed in associated functions + --> $DIR/invalid-self-argument.rs:3:6 + | +LL | fn a(&self) {} + | ^^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions + +error: aborting due to 3 previous errors diff --git a/tests/ui/self/trait-fn.rs b/tests/ui/self/trait-fn.rs deleted file mode 100644 index 5ccea589561c..000000000000 --- a/tests/ui/self/trait-fn.rs +++ /dev/null @@ -1,11 +0,0 @@ -struct Foo {} - -impl Foo { - fn c(foo: u32, self) {} - //~^ ERROR unexpected `self` parameter in function - //~| NOTE must be the first parameter of an associated function - - fn good(&mut self, foo: u32) {} -} - -fn main() { } diff --git a/tests/ui/self/trait-fn.stderr b/tests/ui/self/trait-fn.stderr deleted file mode 100644 index c9d0a338ef42..000000000000 --- a/tests/ui/self/trait-fn.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: unexpected `self` parameter in function - --> $DIR/trait-fn.rs:4:20 - | -LL | fn c(foo: u32, self) {} - | ^^^^ must be the first parameter of an associated function - -error: aborting due to 1 previous error - diff --git a/tests/ui/traits/catch-unwind-cell-interior-mut.rs b/tests/ui/traits/catch-unwind-cell-interior-mut.rs index 7e4fe76852d7..cfc52322399f 100644 --- a/tests/ui/traits/catch-unwind-cell-interior-mut.rs +++ b/tests/ui/traits/catch-unwind-cell-interior-mut.rs @@ -1,3 +1,4 @@ +//! related issue: //@ compile-flags: -Zwrite-long-types-to-disk=yes use std::cell::Cell; use std::panic::catch_unwind; diff --git a/tests/ui/traits/catch-unwind-cell-interior-mut.stderr b/tests/ui/traits/catch-unwind-cell-interior-mut.stderr index b307d608a1fd..6f58c880554a 100644 --- a/tests/ui/traits/catch-unwind-cell-interior-mut.stderr +++ b/tests/ui/traits/catch-unwind-cell-interior-mut.stderr @@ -1,5 +1,5 @@ error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferable across a catch_unwind boundary - --> $DIR/interior-mutability.rs:6:18 + --> $DIR/catch-unwind-cell-interior-mut.rs:7:18 | LL | catch_unwind(|| { x.set(23); }); | ------------ ^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferable across a catch_unwind boundary @@ -11,7 +11,7 @@ note: required because it appears within the type `Cell` --> $SRC_DIR/core/src/cell.rs:LL:COL = note: required for `&Cell` to implement `UnwindSafe` note: required because it's used within this closure - --> $DIR/interior-mutability.rs:6:18 + --> $DIR/catch-unwind-cell-interior-mut.rs:7:18 | LL | catch_unwind(|| { x.set(23); }); | ^^ From 97f93df9c77ffbdd938e88943754298bf510ac99 Mon Sep 17 00:00:00 2001 From: lapla Date: Mon, 1 Dec 2025 09:32:06 +0900 Subject: [PATCH 157/585] Don't suggest unwrap for Result in const --- .../src/fn_ctxt/suggestions.rs | 18 +++++++------- .../rustc_hir_typeck/src/method/suggest.rs | 18 +++++++------- .../const-result-no-expect-suggestion.rs | 15 ++++++++++++ .../const-result-no-expect-suggestion.stderr | 24 +++++++++++++++++++ 4 files changed, 59 insertions(+), 16 deletions(-) create mode 100644 tests/ui/consts/const-result-no-expect-suggestion.rs create mode 100644 tests/ui/consts/const-result-no-expect-suggestion.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1d16c3af7fb7..1adcd91cc3ee 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2106,14 +2106,16 @@ pub(crate) fn suggest_missing_unwrap_expect( )), ); - let (article, kind, variant, sugg_operator) = - if self.tcx.is_diagnostic_item(sym::Result, adt.did()) { - ("a", "Result", "Err", ret_ty_matches(sym::Result)) - } else if self.tcx.is_diagnostic_item(sym::Option, adt.did()) { - ("an", "Option", "None", ret_ty_matches(sym::Option)) - } else { - return false; - }; + let (article, kind, variant, sugg_operator) = if self.tcx.is_diagnostic_item(sym::Result, adt.did()) + // Do not suggest `.expect()` in const context where it's not available. rust-lang/rust#149316 + && !self.tcx.hir_is_inside_const_context(expr.hir_id) + { + ("a", "Result", "Err", ret_ty_matches(sym::Result)) + } else if self.tcx.is_diagnostic_item(sym::Option, adt.did()) { + ("an", "Option", "None", ret_ty_matches(sym::Option)) + } else { + return false; + }; if is_ctor || !self.may_coerce(args.type_at(0), expected) { return false; } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 9a657ab15903..4b9ad345210d 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3041,14 +3041,16 @@ fn suggest_unwrapping_inner_self( tcx.def_span(pick.item.def_id), format!("the method `{item_name}` exists on the type `{self_ty}`"), ); - let (article, kind, variant, question) = - if tcx.is_diagnostic_item(sym::Result, kind.did()) { - ("a", "Result", "Err", ret_ty_matches(sym::Result)) - } else if tcx.is_diagnostic_item(sym::Option, kind.did()) { - ("an", "Option", "None", ret_ty_matches(sym::Option)) - } else { - return; - }; + let (article, kind, variant, question) = if tcx.is_diagnostic_item(sym::Result, kind.did()) + // Do not suggest `.expect()` in const context where it's not available. rust-lang/rust#149316 + && !tcx.hir_is_inside_const_context(expr.hir_id) + { + ("a", "Result", "Err", ret_ty_matches(sym::Result)) + } else if tcx.is_diagnostic_item(sym::Option, kind.did()) { + ("an", "Option", "None", ret_ty_matches(sym::Option)) + } else { + return; + }; if question { err.span_suggestion_verbose( expr.span.shrink_to_hi(), diff --git a/tests/ui/consts/const-result-no-expect-suggestion.rs b/tests/ui/consts/const-result-no-expect-suggestion.rs new file mode 100644 index 000000000000..cd725d9cee0e --- /dev/null +++ b/tests/ui/consts/const-result-no-expect-suggestion.rs @@ -0,0 +1,15 @@ +const fn f(value: u32) -> Result { + Ok(value) +} + +const TEST: u32 = f(2); +//~^ ERROR: mismatched types + +const fn g() -> Result { + Ok(String::new()) +} + +const TEST2: usize = g().len(); +//~^ ERROR: no method named `len` found for enum `Result` + +fn main() {} diff --git a/tests/ui/consts/const-result-no-expect-suggestion.stderr b/tests/ui/consts/const-result-no-expect-suggestion.stderr new file mode 100644 index 000000000000..70aa306ae3c8 --- /dev/null +++ b/tests/ui/consts/const-result-no-expect-suggestion.stderr @@ -0,0 +1,24 @@ +error[E0308]: mismatched types + --> $DIR/const-result-no-expect-suggestion.rs:5:19 + | +LL | const TEST: u32 = f(2); + | ^^^^ expected `u32`, found `Result` + | + = note: expected type `u32` + found enum `Result` + +error[E0599]: no method named `len` found for enum `Result` in the current scope + --> $DIR/const-result-no-expect-suggestion.rs:12:26 + | +LL | const TEST2: usize = g().len(); + | ^^^ + | +note: the method `len` exists on the type `String` + --> $SRC_DIR/alloc/src/string.rs:LL:COL +help: there is a method `le` with a similar name, but with different arguments + --> $SRC_DIR/core/src/cmp.rs:LL:COL + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0599. +For more information about an error, try `rustc --explain E0308`. From 95491661695dacdc3cd92c5d739695a15fe3cfea Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 1 Dec 2025 12:47:18 +0100 Subject: [PATCH 158/585] add test --- ...und-unsatisfied-item-bounds-mit-opt-ice.rs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/ui/where-clauses/projection-bound-unsatisfied-item-bounds-mit-opt-ice.rs diff --git a/tests/ui/where-clauses/projection-bound-unsatisfied-item-bounds-mit-opt-ice.rs b/tests/ui/where-clauses/projection-bound-unsatisfied-item-bounds-mit-opt-ice.rs new file mode 100644 index 000000000000..80eec709eecb --- /dev/null +++ b/tests/ui/where-clauses/projection-bound-unsatisfied-item-bounds-mit-opt-ice.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Copt-level=3 --crate-type=rlib +//@ build-pass + +// A regression test for #149081. The environment of `size` and `align` +// currently means that the item bound of`T::Assoc` doesn't hold. This can +// result in normalization failures and ICE during MIR optimizations. +// +// This will no longer be an issue once #149283 is implemented. + +pub fn align, U>() -> usize { + std::mem::align_of::>() +} + +pub fn size, U>() -> usize { + std::mem::size_of::>() +} + +pub struct Wrapper { + assoc2: ::Assoc, + value: T, +} + +pub trait WithAssoc { + type Assoc: WithAssoc; +} From 02d84c8d23e3e5cf61ab0ce11cf756625b8180a8 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 1 Dec 2025 12:48:18 +0100 Subject: [PATCH 159/585] generic normalization errors to `TooGeneric` --- .../src/interpret/eval_context.rs | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 0e4a98f0941a..d23369caffa4 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -11,7 +11,9 @@ self, FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout, }; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance}; +use rustc_middle::ty::{ + self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingEnv, Variance, +}; use rustc_middle::{mir, span_bug}; use rustc_span::Span; use rustc_target::callconv::FnAbi; @@ -84,10 +86,31 @@ fn layout_tcx_at_span(&self) -> Span { #[inline] fn handle_layout_err( &self, - err: LayoutError<'tcx>, + mut err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>, ) -> InterpErrorKind<'tcx> { + // FIXME(#149283): This is really hacky and is only used to hide type + // system bugs. We use it as a temporary fix for #149081. + // + // While it's expected that we sometimes get ambiguity errors when + // entering another generic environment while the current environment + // itself is still generic, we should never fail to entirely prove + // something. + match err { + LayoutError::NormalizationFailure(ty, _) => { + if ty.has_non_region_param() { + err = LayoutError::TooGeneric(ty); + } + } + + LayoutError::Unknown(_) + | LayoutError::SizeOverflow(_) + | LayoutError::InvalidSimd { .. } + | LayoutError::TooGeneric(_) + | LayoutError::ReferencesError(_) + | LayoutError::Cycle(_) => {} + } err_inval!(Layout(err)) } } @@ -112,7 +135,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// 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 { + pub fn layout_of(&self, ty: Ty<'tcx>) -> Result, InterpErrorKind<'tcx>> { let _trace = enter_trace_span!(M, layouting::layout_of, ty = ?ty.kind()); LayoutOf::layout_of(self, ty) } From 62fe6a01438ae919a04e2d91d22e4ffa632f5971 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Mon, 1 Dec 2025 15:30:53 +0300 Subject: [PATCH 160/585] Rename added test --- .../{ice-issue-148889.rs => unreachable-label-ice-148889.rs} | 0 ...-issue-148889.stderr => unreachable-label-ice-148889.stderr} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/ui/delegation/{ice-issue-148889.rs => unreachable-label-ice-148889.rs} (100%) rename tests/ui/delegation/{ice-issue-148889.stderr => unreachable-label-ice-148889.stderr} (90%) diff --git a/tests/ui/delegation/ice-issue-148889.rs b/tests/ui/delegation/unreachable-label-ice-148889.rs similarity index 100% rename from tests/ui/delegation/ice-issue-148889.rs rename to tests/ui/delegation/unreachable-label-ice-148889.rs diff --git a/tests/ui/delegation/ice-issue-148889.stderr b/tests/ui/delegation/unreachable-label-ice-148889.stderr similarity index 90% rename from tests/ui/delegation/ice-issue-148889.stderr rename to tests/ui/delegation/unreachable-label-ice-148889.stderr index 2ebc7b3ec14e..214196260918 100644 --- a/tests/ui/delegation/ice-issue-148889.stderr +++ b/tests/ui/delegation/unreachable-label-ice-148889.stderr @@ -1,5 +1,5 @@ error[E0767]: use of unreachable label `'foo` - --> $DIR/ice-issue-148889.rs:15:59 + --> $DIR/unreachable-label-ice-148889.rs:15:59 | LL | 'foo: loop { | ---- unreachable label defined here From 31106eb75252ef0bb8c2be5ef62af75b78746158 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Mon, 1 Dec 2025 21:49:40 +0900 Subject: [PATCH 161/585] Update the comment in the add_typo_suggestion function --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 2f4a18f9cfa6..c8e5fd3a21f8 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1900,7 +1900,7 @@ pub(crate) fn add_typo_suggestion( if span.overlaps(def_span) { // Don't suggest typo suggestion for itself like in the following: // error[E0423]: expected function, tuple struct or tuple variant, found struct `X` - // --> $DIR/issue-64792-bad-unicode-ctor.rs:3:14 + // --> $DIR/unicode-string-literal-syntax-error-64792.rs:4:14 // | // LL | struct X {} // | ----------- `X` defined here From b03a65543fbbfbac8eb0c861f3147f7e9c6e473a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 29 Nov 2025 17:29:49 +1100 Subject: [PATCH 162/585] Prepare ignore/only conditions once in advance, without a macro --- src/tools/compiletest/src/directives.rs | 12 +- src/tools/compiletest/src/directives/cfg.rs | 485 +++++++++----------- 2 files changed, 217 insertions(+), 280 deletions(-) diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 8e9c28e69ea7..fed30415de56 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -34,12 +34,18 @@ mod tests; pub struct DirectivesCache { + /// "Conditions" used by `ignore-*` and `only-*` directives, prepared in + /// advance so that they don't have to be evaluated repeatedly. + cfg_conditions: cfg::PreparedConditions, needs: CachedNeedsConditions, } impl DirectivesCache { pub fn load(config: &Config) -> Self { - Self { needs: CachedNeedsConditions::load(config) } + Self { + cfg_conditions: cfg::prepare_conditions(config), + needs: CachedNeedsConditions::load(config), + } } } @@ -1058,8 +1064,8 @@ macro_rules! decision { }; } - decision!(cfg::handle_ignore(config, ln)); - decision!(cfg::handle_only(config, ln)); + decision!(cfg::handle_ignore(&cache.cfg_conditions, ln)); + decision!(cfg::handle_only(&cache.cfg_conditions, ln)); decision!(needs::handle_needs(&cache.needs, config, ln)); decision!(ignore_llvm(config, ln)); decision!(ignore_backends(config, ln)); diff --git a/src/tools/compiletest/src/directives/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs index 13c85bc3972a..62d10f14b98f 100644 --- a/src/tools/compiletest/src/directives/cfg.rs +++ b/src/tools/compiletest/src/directives/cfg.rs @@ -1,5 +1,5 @@ -use std::collections::HashSet; -use std::sync::LazyLock; +use std::collections::{HashMap, HashSet}; +use std::sync::{Arc, LazyLock}; use crate::common::{CompareMode, Config, Debugger}; use crate::directives::{DirectiveLine, IgnoreDecision}; @@ -20,8 +20,11 @@ pub(crate) static EXTERNAL_IGNORES_SET: LazyLock> = LazyLock::new(|| EXTERNAL_IGNORES_LIST.iter().copied().collect()); -pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { - let parsed = parse_cfg_name_directive(config, line, "ignore-"); +pub(super) fn handle_ignore( + conditions: &PreparedConditions, + line: &DirectiveLine<'_>, +) -> IgnoreDecision { + let parsed = parse_cfg_name_directive(conditions, line, "ignore-"); let line = line.display(); match parsed.outcome { @@ -37,8 +40,11 @@ pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> Ignore } } -pub(super) fn handle_only(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { - let parsed = parse_cfg_name_directive(config, line, "only-"); +pub(super) fn handle_only( + conditions: &PreparedConditions, + line: &DirectiveLine<'_>, +) -> IgnoreDecision { + let parsed = parse_cfg_name_directive(conditions, line, "only-"); let line = line.display(); match parsed.outcome { @@ -59,7 +65,7 @@ pub(super) fn handle_only(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDe /// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86` /// or `only-windows`. fn parse_cfg_name_directive<'a>( - config: &Config, + conditions: &PreparedConditions, line: &'a DirectiveLine<'a>, prefix: &str, ) -> ParsedNameDirective<'a> { @@ -74,230 +80,186 @@ fn parse_cfg_name_directive<'a>( // FIXME(Zalathar): This currently allows either a space or a colon, and // treats any "value" after a colon as though it were a remark. // We should instead forbid the colon syntax for these directives. - let comment = line.remark_after_space().or_else(|| line.value_after_colon()); + let comment = line + .remark_after_space() + .or_else(|| line.value_after_colon()) + .map(|c| c.trim().trim_start_matches('-').trim()); - // Some of the matchers might be "" depending on what the target information is. To avoid - // problems we outright reject empty directives. - if name.is_empty() { - return ParsedNameDirective::not_handled_here(); + if let Some(cond) = conditions.conds.get(name) { + ParsedNameDirective { + pretty_reason: Some(Arc::clone(&cond.message_when_ignored)), + comment, + outcome: if cond.value { MatchOutcome::Match } else { MatchOutcome::NoMatch }, + } + } else { + ParsedNameDirective { pretty_reason: None, comment, outcome: MatchOutcome::Invalid } + } +} + +/// Uses information about the current target (and all targets) to pre-compute +/// a value (true or false) for a number of "conditions". Those conditions can +/// then be used by `ignore-*` and `only-*` directives. +pub(crate) fn prepare_conditions(config: &Config) -> PreparedConditions { + let cfgs = config.target_cfgs(); + let current = &cfgs.current; + + let mut builder = ConditionsBuilder::new(); + + // Some condition names overlap (e.g. "macabi" is both an env and an ABI), + // so the order in which conditions are added is significant. + // Whichever condition registers that name _first_ will take precedence. + // (See `ConditionsBuilder::build`.) + + builder.cond("test", true, "always"); + builder.cond("auxiliary", true, "used by another main test file"); + + for target in &cfgs.all_targets { + builder.cond(target, *target == config.target, &format!("when the target is {target}")); + } + for os in &cfgs.all_oses { + builder.cond(os, *os == current.os, &format!("when the operating system is {os}")); + } + for env in &cfgs.all_envs { + builder.cond(env, *env == current.env, &format!("when the target environment is {env}")); + } + for os_and_env in &cfgs.all_oses_and_envs { + builder.cond( + os_and_env, + *os_and_env == current.os_and_env(), + &format!("when the operating system and target environment are {os_and_env}"), + ); + } + for abi in &cfgs.all_abis { + builder.cond(abi, *abi == current.abi, &format!("when the ABI is {abi}")); + } + for arch in cfgs.all_archs.iter().map(String::as_str).chain(EXTRA_ARCHS.iter().copied()) { + builder.cond(arch, *arch == current.arch, &format!("when the architecture is {arch}")); + } + for n_bit in &cfgs.all_pointer_widths { + builder.cond( + n_bit, + *n_bit == format!("{}bit", current.pointer_width), + &format!("when the pointer width is {n_bit}"), + ); + } + for family in &cfgs.all_families { + builder.cond( + family, + current.families.contains(family), + &format!("when the target family is {family}"), + ) } - let mut outcome = MatchOutcome::Invalid; - let mut message = None; - - macro_rules! condition { - ( - name: $name:expr, - $(allowed_names: $allowed_names:expr,)? - $(condition: $condition:expr,)? - message: $($message:tt)* - ) => {{ - // This is not inlined to avoid problems with macro repetitions. - let format_message = || format!($($message)*); - - if outcome != MatchOutcome::Invalid { - // Ignore all other matches if we already found one - } else if $name.custom_matches(name) { - message = Some(format_message()); - if true $(&& $condition)? { - outcome = MatchOutcome::Match; - } else { - outcome = MatchOutcome::NoMatch; - } - } - $(else if $allowed_names.custom_contains(name) { - message = Some(format_message()); - outcome = MatchOutcome::NoMatch; - })? - }}; - } - - let target_cfgs = config.target_cfgs(); - let target_cfg = config.target_cfg(); - - condition! { - name: "test", - message: "always" - } - condition! { - name: "auxiliary", - message: "used by another main test file" - } - condition! { - name: &config.target, - allowed_names: &target_cfgs.all_targets, - message: "when the target is {name}" - } - condition! { - name: &target_cfg.os, - allowed_names: &target_cfgs.all_oses, - message: "when the operating system is {name}" - } - condition! { - name: &target_cfg.env, - allowed_names: &target_cfgs.all_envs, - message: "when the target environment is {name}" - } - condition! { - name: &target_cfg.os_and_env(), - allowed_names: &target_cfgs.all_oses_and_envs, - message: "when the operating system and target environment are {name}" - } - condition! { - name: &target_cfg.abi, - allowed_names: &target_cfgs.all_abis, - message: "when the ABI is {name}" - } - condition! { - name: &target_cfg.arch, - allowed_names: ContainsEither { a: &target_cfgs.all_archs, b: &EXTRA_ARCHS }, - message: "when the architecture is {name}" - } - condition! { - name: format!("{}bit", target_cfg.pointer_width), - allowed_names: &target_cfgs.all_pointer_widths, - message: "when the pointer width is {name}" - } - condition! { - name: &*target_cfg.families, - allowed_names: &target_cfgs.all_families, - message: "when the target family is {name}" - } - - condition! { - name: "thumb", - condition: config.target.starts_with("thumb"), - message: "when the architecture is part of the Thumb family" - } + builder.cond( + "thumb", + config.target.starts_with("thumb"), + "when the architecture is part of the Thumb family", + ); // The "arch" of `i586-` targets is "x86", so for more specific matching // we have to resort to a string-prefix check. - condition! { - name: "i586", - condition: config.matches_arch("i586"), - message: "when the subarchitecture is i586", - } - - condition! { - name: "apple", - condition: config.target.contains("apple"), - message: "when the target vendor is Apple" - } - - condition! { - name: "elf", - condition: target_cfg.binary_format == "elf", - message: "when the target binary format is ELF" - } - - condition! { - name: "enzyme", - condition: config.has_enzyme, - message: "when rustc is built with LLVM Enzyme" - } + builder.cond("i586", config.matches_arch("i586"), "when the subarchitecture is i586"); + // FIXME(Zalathar): Use proper target vendor information instead? + builder.cond("apple", config.target.contains("apple"), "when the target vendor is Apple"); + // FIXME(Zalathar): Support all known binary formats, not just ELF? + builder.cond("elf", current.binary_format == "elf", "when the target binary format is ELF"); + builder.cond("enzyme", config.has_enzyme, "when rustc is built with LLVM Enzyme"); // Technically the locally built compiler uses the "dev" channel rather than the "nightly" // channel, even though most people don't know or won't care about it. To avoid confusion, we // treat the "dev" channel as the "nightly" channel when processing the directive. - condition! { - name: if config.channel == "dev" { "nightly" } else { &config.channel }, - allowed_names: &["stable", "beta", "nightly"], - message: "when the release channel is {name}", + for channel in ["stable", "beta", "nightly"] { + let curr_channel = match config.channel.as_str() { + "dev" => "nightly", + ch => ch, + }; + builder.cond( + channel, + channel == curr_channel, + &format!("when the release channel is {channel}"), + ); } - condition! { - name: "cross-compile", - condition: config.target != config.host, - message: "when cross-compiling" + builder.cond("cross-compile", config.target != config.host, "when cross-compiling"); + builder.cond("endian-big", config.is_big_endian(), "on big-endian targets"); + + for stage in ["stage0", "stage1", "stage2"] { + builder.cond( + stage, + stage == format!("stage{}", config.stage), + &format!("when the bootstrapping stage is {stage}"), + ); } - condition! { - name: "endian-big", - condition: config.is_big_endian(), - message: "on big-endian targets", + + builder.cond("remote", config.remote_test_client.is_some(), "when running tests remotely"); + builder.cond( + "rustc-debug-assertions", + config.with_rustc_debug_assertions, + "when rustc is built with debug assertions", + ); + builder.cond( + "std-debug-assertions", + config.with_std_debug_assertions, + "when std is built with debug assertions", + ); + + for &debugger in Debugger::STR_VARIANTS { + builder.cond( + debugger, + Some(debugger) == config.debugger.as_ref().map(Debugger::to_str), + &format!("when the debugger is {debugger}"), + ); } - condition! { - name: format!("stage{}", config.stage).as_str(), - allowed_names: &["stage0", "stage1", "stage2"], - message: "when the bootstrapping stage is {name}", - } - condition! { - name: "remote", - condition: config.remote_test_client.is_some(), - message: "when running tests remotely", - } - condition! { - name: "rustc-debug-assertions", - condition: config.with_rustc_debug_assertions, - message: "when rustc is built with debug assertions", - } - condition! { - name: "std-debug-assertions", - condition: config.with_std_debug_assertions, - message: "when std is built with debug assertions", - } - condition! { - name: config.debugger.as_ref().map(|d| d.to_str()), - allowed_names: &Debugger::STR_VARIANTS, - message: "when the debugger is {name}", - } - condition! { - name: config.compare_mode - .as_ref() - .map(|d| format!("compare-mode-{}", d.to_str())), - allowed_names: ContainsPrefixed { - prefix: "compare-mode-", - inner: CompareMode::STR_VARIANTS, - }, - message: "when comparing with {name}", + + for &compare_mode in CompareMode::STR_VARIANTS { + builder.cond( + &format!("compare-mode-{compare_mode}"), + Some(compare_mode) == config.compare_mode.as_ref().map(CompareMode::to_str), + &format!("when comparing with compare-mode-{compare_mode}"), + ); } + // Coverage tests run the same test file in multiple modes. // If a particular test should not be run in one of the modes, ignore it // with "ignore-coverage-map" or "ignore-coverage-run". - condition! { - name: config.mode.to_str(), - allowed_names: ["coverage-map", "coverage-run"], - message: "when the test mode is {name}", - } - condition! { - name: target_cfg.rustc_abi.as_ref().map(|abi| format!("rustc_abi-{abi}")).unwrap_or_default(), - allowed_names: ContainsPrefixed { - prefix: "rustc_abi-", - inner: target_cfgs.all_rustc_abis.clone(), - }, - message: "when the target `rustc_abi` is {name}", + for test_mode in ["coverage-map", "coverage-run"] { + builder.cond( + test_mode, + test_mode == config.mode.to_str(), + &format!("when the test mode is {test_mode}"), + ); } - condition! { - name: "dist", - condition: std::env::var("COMPILETEST_ENABLE_DIST_TESTS") == Ok("1".to_string()), - message: "when performing tests on dist toolchain" + for rustc_abi in &cfgs.all_rustc_abis { + builder.cond( + &format!("rustc_abi-{rustc_abi}"), + Some(rustc_abi) == current.rustc_abi.as_ref(), + &format!("when the target `rustc_abi` is rustc_abi-{rustc_abi}"), + ); } - ParsedNameDirective { - name: Some(name), - comment: comment.map(|c| c.trim().trim_start_matches('-').trim()), - outcome, - pretty_reason: message, - } + // FIXME(Zalathar): Ideally this should be configured by a command-line + // flag, not an environment variable. + builder.cond( + "dist", + std::env::var("COMPILETEST_ENABLE_DIST_TESTS").as_deref() == Ok("1"), + "when performing tests on dist toolchain", + ); + + builder.build() } /// The result of parse_cfg_name_directive. #[derive(Clone, PartialEq, Debug)] pub(super) struct ParsedNameDirective<'a> { - pub(super) name: Option<&'a str>, - pub(super) pretty_reason: Option, + pub(super) pretty_reason: Option>, pub(super) comment: Option<&'a str>, pub(super) outcome: MatchOutcome, } impl ParsedNameDirective<'_> { fn not_handled_here() -> Self { - Self { - name: None, - pretty_reason: None, - comment: None, - outcome: MatchOutcome::NotHandledHere, - } + Self { pretty_reason: None, comment: None, outcome: MatchOutcome::NotHandledHere } } } @@ -313,86 +275,55 @@ pub(super) enum MatchOutcome { NotHandledHere, } -trait CustomContains { - fn custom_contains(&self, item: &str) -> bool; +#[derive(Debug)] +pub(crate) struct PreparedConditions { + /// Maps the "bare" name of each condition to a structure indicating + /// whether the condition is true or false for the target being tested. + conds: HashMap, Cond>, } -impl CustomContains for HashSet { - fn custom_contains(&self, item: &str) -> bool { - self.contains(item) - } -} - -impl CustomContains for &[&str] { - fn custom_contains(&self, item: &str) -> bool { - self.contains(&item) - } -} - -impl CustomContains for [&str; N] { - fn custom_contains(&self, item: &str) -> bool { - self.contains(&item) - } -} - -struct ContainsPrefixed { - prefix: &'static str, - inner: T, -} - -impl CustomContains for ContainsPrefixed { - fn custom_contains(&self, item: &str) -> bool { - match item.strip_prefix(self.prefix) { - Some(stripped) => self.inner.custom_contains(stripped), - None => false, - } - } -} - -struct ContainsEither<'a, A: CustomContains, B: CustomContains> { - a: &'a A, - b: &'a B, -} - -impl CustomContains for ContainsEither<'_, A, B> { - fn custom_contains(&self, item: &str) -> bool { - self.a.custom_contains(item) || self.b.custom_contains(item) - } -} - -trait CustomMatches { - fn custom_matches(&self, name: &str) -> bool; -} - -impl CustomMatches for &str { - fn custom_matches(&self, name: &str) -> bool { - name == *self - } -} - -impl CustomMatches for String { - fn custom_matches(&self, name: &str) -> bool { - name == self - } -} - -impl CustomMatches for &[T] { - fn custom_matches(&self, name: &str) -> bool { - self.iter().any(|m| m.custom_matches(name)) - } -} - -impl CustomMatches for [T; N] { - fn custom_matches(&self, name: &str) -> bool { - self.iter().any(|m| m.custom_matches(name)) - } -} - -impl CustomMatches for Option { - fn custom_matches(&self, name: &str) -> bool { - match self { - Some(inner) => inner.custom_matches(name), - None => false, - } +#[derive(Debug)] +struct Cond { + /// Bare condition name without an ignore/only prefix, e.g. `aarch64` or `windows`. + bare_name: Arc, + + /// Is this condition true or false for the target being tested, based on + /// the config that was used to prepare these conditions? + /// + /// For example, the condition `windows` is true on Windows targets. + value: bool, + + /// Message fragment to show when a test is ignored based on this condition + /// being true or false, e.g. "when the architecture is aarch64". + message_when_ignored: Arc, +} + +struct ConditionsBuilder { + conds: Vec, +} + +impl ConditionsBuilder { + fn new() -> Self { + Self { conds: vec![] } + } + + fn cond(&mut self, bare_name: &str, value: bool, message_when_ignored: &str) { + self.conds.push(Cond { + bare_name: Arc::::from(bare_name), + value, + message_when_ignored: Arc::::from(message_when_ignored), + }); + } + + fn build(self) -> PreparedConditions { + let conds = self + .conds + .into_iter() + // Build the map in reverse order, so that conditions declared + // earlier have priority over ones declared later. + .rev() + .map(|cond| (Arc::clone(&cond.bare_name), cond)) + .collect::>(); + PreparedConditions { conds } } } From e645e51d97ff550adc6ba3598802f6855a366f20 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 20:13:10 +0100 Subject: [PATCH 163/585] Remove an outdated test This... is a weird test. It has two impls: - `impl From> for Box` (commented out, more on that later), and - `impl Into> for Foo` The idea of that test is to show that the first impl doesn't compile, but the second does, thus `TryFrom` should be using `Into` and not `From` (because `Into` is more general, since the `From` impl doesn't compile). However: 1. The types are different -- `Box` vs `Vec`, which is significant b/c `Box` is fundamental 2. The commented out impl actually compiles! (which wasn't detected b/c it's commented out :\ ) Here is a table for compilation of the impls: | | `Vec` | `Box` | |--------|--------------|----------------| | `From` | since 1.41.0 | never | | `Into` | always | not since 1.28 | [godbolt used to test this](https://godbolt.org/z/T38E3jGKa) Order of events: 1. in `1.28` the `incoherent_fundamental_impls` lint becomes deny by default (this is *not* mentioned in the changelog yay) 2. `1.32` changed absolutely nothing, even though this version is credited in the test 3. the test was added (I'm not exactly sure when) (see https://github.com/rust-lang/rust/pull/56796) 4. in `1.41` coherence was relaxed to allow `From`+`Vec` to compile To conclude: since `1.41` this test does nothing (and before that it was written in a way which did not detect this change). It looks to me like today (since `1.41`) we *could* bound `TryFrom` impl with `From` (but now it'd be a useless breaking change of course). Am I missing anything? Is there a useful version of this test that could be written? --- tests/ui/never_type/try_from.rs | 37 --------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 tests/ui/never_type/try_from.rs diff --git a/tests/ui/never_type/try_from.rs b/tests/ui/never_type/try_from.rs deleted file mode 100644 index acde524e98f5..000000000000 --- a/tests/ui/never_type/try_from.rs +++ /dev/null @@ -1,37 +0,0 @@ -//@ run-pass -// This test relies on `TryFrom` being blanket impl for all `T: Into` -// and `TryInto` being blanket impl for all `U: TryFrom` - -// This test was added to show the motivation for doing this -// over `TryFrom` being blanket impl for all `T: From` - -#![feature(never_type)] - -use std::convert::{TryInto, Infallible}; - -struct Foo { - t: T, -} - -// This fails to compile due to coherence restrictions -// as of Rust version 1.32.x, therefore it could not be used -// instead of the `Into` version of the impl, and serves as -// motivation for a blanket impl for all `T: Into`, instead -// of a blanket impl for all `T: From` -/* -impl From> for Box { - fn from(foo: Foo) -> Box { - Box::new(foo.t) - } -} -*/ - -impl Into> for Foo { - fn into(self) -> Vec { - vec![self.t] - } -} - -pub fn main() { - let _: Result, Infallible> = Foo { t: 10 }.try_into(); -} From 57a1000f137c5ad60e5acabd5faf34ce8fa3030c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Mon, 1 Dec 2025 15:54:58 +0100 Subject: [PATCH 164/585] Mark windows-gnu* as lacking build with assertions --- src/bootstrap/src/core/build_steps/llvm.rs | 4 ++-- src/ci/github-actions/jobs.yml | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index a591be05291f..5dbfd1eb2b08 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -210,7 +210,7 @@ pub(crate) fn is_ci_llvm_available_for_target( ("i686-unknown-linux-gnu", false), ("x86_64-unknown-linux-gnu", true), ("x86_64-apple-darwin", true), - ("x86_64-pc-windows-gnu", true), + ("x86_64-pc-windows-gnu", false), ("x86_64-pc-windows-msvc", true), // tier 2 with host tools ("aarch64-unknown-linux-musl", false), @@ -227,7 +227,7 @@ pub(crate) fn is_ci_llvm_available_for_target( ("powerpc64le-unknown-linux-musl", false), ("riscv64gc-unknown-linux-gnu", false), ("s390x-unknown-linux-gnu", false), - ("x86_64-pc-windows-gnullvm", true), + ("x86_64-pc-windows-gnullvm", false), ("x86_64-unknown-freebsd", false), ("x86_64-unknown-illumos", false), ("x86_64-unknown-linux-musl", false), diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index ee10e36e1c37..e69a65869475 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -612,16 +612,12 @@ auto: env: SCRIPT: make ci-mingw-x RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - # There is no dist-x86_64-mingw-alt, so there is no prebuilt LLVM with assertions - NO_DOWNLOAD_CI_LLVM: 1 <<: *job-windows - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-bootstrap RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - # There is no dist-x86_64-mingw-alt, so there is no prebuilt LLVM with assertions - NO_DOWNLOAD_CI_LLVM: 1 <<: *job-windows - name: dist-x86_64-msvc From 109e5e5999041b85dcf5212f6cad559d3ed1111e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 11 Oct 2025 18:25:10 +0200 Subject: [PATCH 165/585] Move early buffered lint ambigous-glob-imports to a dyn lint diagnostic --- compiler/rustc_errors/src/lib.rs | 16 ------- compiler/rustc_lint/src/early/diagnostics.rs | 3 -- compiler/rustc_lint/src/lints.rs | 13 ------ compiler/rustc_lint_defs/src/lib.rs | 18 -------- compiler/rustc_resolve/src/diagnostics.rs | 41 ++++++++---------- compiler/rustc_resolve/src/errors.rs | 45 +++++++++++++++++++- 6 files changed, 60 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b8dda9ed5743..876a5340d93e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -2049,22 +2049,6 @@ pub fn elided_lifetime_in_path_suggestion( ElidedLifetimeInPathSubdiag { expected, indicate } } -pub fn report_ambiguity_error<'a, G: EmissionGuarantee>( - diag: &mut Diag<'a, G>, - ambiguity: rustc_lint_defs::AmbiguityErrorDiag, -) { - diag.span_label(ambiguity.label_span, ambiguity.label_msg); - diag.note(ambiguity.note_msg); - diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg); - for help_msg in ambiguity.b1_help_msgs { - diag.help(help_msg); - } - diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg); - for help_msg in ambiguity.b2_help_msgs { - diag.help(help_msg); - } -} - /// Grammatical tool for displaying messages to end users in a nice form. /// /// Returns "an" if the given string starts with a vowel, and "a" otherwise. diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 34bb3989008e..e376d7d2ab88 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -251,9 +251,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::AmbiguousGlobImports { diag: ambiguity } => { - lints::AmbiguousGlobImports { ambiguity }.decorate_lint(diag); - } BuiltinLintDiag::AmbiguousGlobReexports { name, namespace, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 43786db8bdce..0687490645d3 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -15,7 +15,6 @@ use rustc_middle::ty::inhabitedness::InhabitedPredicate; use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; -use rustc_session::lint::AmbiguityErrorDiag; use rustc_span::edition::Edition; use rustc_span::{Ident, Span, Symbol, sym}; @@ -2836,18 +2835,6 @@ pub(crate) struct NamedArgumentUsedPositionally { pub named_arg_name: String, } -// FIXME: make this translatable -pub(crate) struct AmbiguousGlobImports { - pub ambiguity: AmbiguityErrorDiag, -} - -impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for AmbiguousGlobImports { - fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) { - diag.primary_message(self.ambiguity.msg.clone()); - rustc_errors::report_ambiguity_error(diag, self.ambiguity); - } -} - #[derive(LintDiagnostic)] #[diag(lint_ambiguous_glob_reexport)] pub(crate) struct AmbiguousGlobReexports { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 8acb5eb31991..326fdaf9cec9 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -593,21 +593,6 @@ fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering { } } -#[derive(Debug)] -pub struct AmbiguityErrorDiag { - pub msg: String, - pub span: Span, - pub label_span: Span, - pub label_msg: String, - pub note_msg: String, - pub b1_span: Span, - pub b1_note_msg: String, - pub b1_help_msgs: Vec, - pub b2_span: Span, - pub b2_note_msg: String, - pub b2_help_msgs: Vec, -} - #[derive(Debug, Clone)] pub enum DeprecatedSinceKind { InEffect, @@ -678,9 +663,6 @@ pub enum BuiltinLintDiag { /// Indicates if the named argument is used as a width/precision for formatting is_formatting_arg: bool, }, - AmbiguousGlobImports { - diag: AmbiguityErrorDiag, - }, AmbiguousGlobReexports { /// The name for which collision(s) have occurred. name: String, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index fe299a6cebca..f6219808945e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -11,7 +11,7 @@ use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle, - report_ambiguity_error, struct_span_code_err, + struct_span_code_err, }; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::attrs::{AttributeKind, CfgEntry, StrippedCfgItem}; @@ -22,16 +22,16 @@ use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS, MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, }; -use rustc_session::lint::{AmbiguityErrorDiag, BuiltinLintDiag}; use rustc_session::utils::was_invoked_from_cargo; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; -use rustc_span::source_map::SourceMap; +use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::{BytePos, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, instrument}; @@ -145,7 +145,8 @@ pub(crate) fn report_errors(&mut self, krate: &Crate) { } for ambiguity_error in &self.ambiguity_errors { - let diag = self.ambiguity_diagnostics(ambiguity_error); + let diag = self.ambiguity_diagnostic(ambiguity_error); + if ambiguity_error.warning { let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else { unreachable!() @@ -153,13 +154,11 @@ pub(crate) fn report_errors(&mut self, krate: &Crate) { self.lint_buffer.buffer_lint( AMBIGUOUS_GLOB_IMPORTS, import.root_id, - ambiguity_error.ident.span, - BuiltinLintDiag::AmbiguousGlobImports { diag }, + diag.ident.span, + diag, ); } else { - let mut err = struct_span_code_err!(self.dcx(), diag.span, E0659, "{}", diag.msg); - report_ambiguity_error(&mut err, diag); - err.emit(); + self.dcx().emit_err(diag); } } @@ -1995,7 +1994,7 @@ fn binding_description(&self, b: NameBinding<'_>, ident: Ident, from_prelude: bo } } - fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'ra>) -> AmbiguityErrorDiag { + fn ambiguity_diagnostic(&self, ambiguity_error: &AmbiguityError<'ra>) -> errors::Ambiguity { let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error; let extern_prelude_ambiguity = || { self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)).is_some_and(|entry| { @@ -2038,8 +2037,7 @@ fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'ra>) -> Ambigu } ( - b.span, - note_msg, + Spanned { node: note_msg, span: b.span }, help_msgs .iter() .enumerate() @@ -2050,20 +2048,15 @@ fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'ra>) -> Ambigu .collect::>(), ) }; - let (b1_span, b1_note_msg, b1_help_msgs) = could_refer_to(b1, misc1, ""); - let (b2_span, b2_note_msg, b2_help_msgs) = could_refer_to(b2, misc2, " also"); + let (b1_note, b1_help_msgs) = could_refer_to(b1, misc1, ""); + let (b2_note, b2_help_msgs) = could_refer_to(b2, misc2, " also"); - AmbiguityErrorDiag { - msg: format!("`{ident}` is ambiguous"), - span: ident.span, - label_span: ident.span, - label_msg: "ambiguous name".to_string(), - note_msg: format!("ambiguous because of {}", kind.descr()), - b1_span, - b1_note_msg, + errors::Ambiguity { + ident, + kind: kind.descr(), + b1_note, b1_help_msgs, - b2_span, - b2_note_msg, + b2_note, b2_help_msgs, } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index fe1f0d253a12..af58d88ec35f 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,9 +1,10 @@ use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagMessage, ElidedLifetimeInPathSubdiag, EmissionGuarantee, IntoDiagArg, - LintDiagnostic, MultiSpan, Subdiagnostic, + Applicability, Diag, DiagCtxtHandle, DiagMessage, Diagnostic, ElidedLifetimeInPathSubdiag, + EmissionGuarantee, IntoDiagArg, Level, LintDiagnostic, MultiSpan, Subdiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_span::source_map::Spanned; use rustc_span::{Ident, Span, Symbol}; use crate::late::PatternSource; @@ -1445,3 +1446,43 @@ pub(crate) struct UnknownDiagnosticAttributeTypoSugg { pub span: Span, pub typo_name: Symbol, } + +// FIXME: Make this properly translatable. +pub(crate) struct Ambiguity { + pub ident: Ident, + pub kind: &'static str, + pub b1_note: Spanned, + pub b1_help_msgs: Vec, + pub b2_note: Spanned, + pub b2_help_msgs: Vec, +} + +impl Ambiguity { + fn decorate<'a>(self, diag: &mut Diag<'a, impl EmissionGuarantee>) { + diag.primary_message(format!("`{}` is ambiguous", self.ident)); + diag.span_label(self.ident.span, "ambiguous name"); + diag.note(format!("ambiguous because of {}", self.kind)); + diag.span_note(self.b1_note.span, self.b1_note.node); + for help_msg in self.b1_help_msgs { + diag.help(help_msg); + } + diag.span_note(self.b2_note.span, self.b2_note.node); + for help_msg in self.b2_help_msgs { + diag.help(help_msg); + } + } +} + +impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for Ambiguity { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { + let mut diag = Diag::new(dcx, level, "").with_span(self.ident.span).with_code(E0659); + self.decorate(&mut diag); + diag + } +} + +impl<'a> LintDiagnostic<'a, ()> for Ambiguity { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + self.decorate(diag); + } +} From a37873d7fb5903f1545b913a14f4aaa0306822a6 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 1 Dec 2025 16:41:39 +0100 Subject: [PATCH 166/585] add a coretest checking `TryInto`/`TryFrom` impls --- library/coretests/tests/convert.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/library/coretests/tests/convert.rs b/library/coretests/tests/convert.rs index f1048f4cf09c..1eb7468e56ea 100644 --- a/library/coretests/tests/convert.rs +++ b/library/coretests/tests/convert.rs @@ -14,3 +14,20 @@ const fn into(x: Vec) -> Vec { const BAR: Vec = into(Vec::new()); assert_eq!(BAR, Vec::::new()); } + +#[test] +fn into_as_try_into() { + struct A; + struct B; + + impl Into for A { + fn into(self) -> B { + B + } + } + + // This wouldn't compile if the `TryInto`/`TryFrom` blanket impls used + // `U: From` instead of `T: Into` + let Ok(B) = A.try_into(); + let Ok(B) = B::try_from(A); +} From 9498f21277ce7deb6ca68184424ee60060a63667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Mon, 1 Dec 2025 13:51:49 +0100 Subject: [PATCH 167/585] Bring back i686-pc-windows-gnullvm target --- src/ci/github-actions/jobs.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index ee10e36e1c37..b0ec2d981908 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -683,15 +683,18 @@ auto: CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows + # i686 has no dedicated job, build it here because this job is fast - name: dist-aarch64-llvm-mingw env: SCRIPT: python x.py dist bootstrap --include-default-paths RUST_CONFIGURE_ARGS: >- --build=aarch64-pc-windows-gnullvm + --target=aarch64-pc-windows-gnullvm,i686-pc-windows-gnullvm --enable-full-tools --enable-profiler DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift + CC_i686_pc_windows_gnullvm: i686-w64-mingw32-clang <<: *job-windows-aarch64 - name: dist-x86_64-llvm-mingw From b55796facaf80bc5f7ba2855672280ca22c1766d Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 1 Dec 2025 16:22:27 +0000 Subject: [PATCH 168/585] Uppper typo Co-authored-by: Santiago Pastorino --- src/doc/rustc-dev-guide/src/hir-typeck/coercions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/hir-typeck/coercions.md b/src/doc/rustc-dev-guide/src/hir-typeck/coercions.md index 384ea9bcf030..158ac0885d32 100644 --- a/src/doc/rustc-dev-guide/src/hir-typeck/coercions.md +++ b/src/doc/rustc-dev-guide/src/hir-typeck/coercions.md @@ -2,7 +2,7 @@ Coercions are implicit operations which transform a value into a different type. A coercion *site* is a position where a coercion is able to be implicitly performed. There are two kinds of coercion sites: - one-to-one -- LUB (Least-Uppper-Bound) +- LUB (Least-Upper-Bound) ```rust let one_to_one_coercion: &u32 = &mut 8; From 919e46f4d41003ce7b927df83be284101d27b8d3 Mon Sep 17 00:00:00 2001 From: bendn Date: Tue, 11 Nov 2025 13:46:52 +0700 Subject: [PATCH 169/585] stabilize [T]::array_windows --- compiler/rustc_ast/src/lib.rs | 2 +- compiler/rustc_data_structures/src/lib.rs | 2 +- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_expand/src/lib.rs | 2 +- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_middle/src/lib.rs | 2 +- compiler/rustc_mir_transform/src/lib.rs | 2 +- compiler/rustc_monomorphize/src/lib.rs | 2 +- compiler/rustc_span/src/lib.rs | 2 +- library/alloc/src/lib.rs | 1 - library/alloc/src/slice.rs | 2 +- library/core/src/slice/iter.rs | 10 ++++------ library/core/src/slice/mod.rs | 5 ++--- library/coretests/tests/lib.rs | 1 - src/tools/clippy/clippy_lints/src/lib.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- 16 files changed, 18 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index e19dccbce02a..cbdc89f9deed 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -5,8 +5,8 @@ //! This API is completely unstable and subject to change. // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(array_windows))] #![doc(test(attr(deny(warnings), allow(internal_features))))] -#![feature(array_windows)] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index b4031973fbc2..41f6292e740b 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -10,9 +10,9 @@ #![allow(internal_features)] #![allow(rustc::default_hash_types)] #![allow(rustc::potential_query_instability)] +#![cfg_attr(bootstrap, feature(array_windows))] #![deny(unsafe_op_in_unsafe_fn)] #![feature(allocator_api)] -#![feature(array_windows)] #![feature(ascii_char)] #![feature(ascii_char_variants)] #![feature(assert_matches)] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b8dda9ed5743..52e532014ca3 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -7,7 +7,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::untranslatable_diagnostic)] -#![feature(array_windows)] +#![cfg_attr(bootstrap, feature(array_windows))] #![feature(assert_matches)] #![feature(associated_type_defaults)] #![feature(box_patterns)] diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index e76fca92c586..5eefa4bcdf6b 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,7 +1,7 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] -#![feature(array_windows)] +#![cfg_attr(bootstrap, feature(array_windows))] #![feature(associated_type_defaults)] #![feature(if_let_guard)] #![feature(macro_metavar_expr)] diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 78b76e083d41..1aac65dbaa77 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -21,7 +21,7 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![feature(array_windows)] +#![cfg_attr(bootstrap, feature(array_windows))] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index ef8326fd038e..5f62d44df6b6 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,8 +29,8 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(array_windows))] #![feature(allocator_api)] -#![feature(array_windows)] #![feature(assert_matches)] #![feature(associated_type_defaults)] #![feature(box_as_ptr)] diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 18b798c01faa..1f6cc2700592 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,5 +1,5 @@ // tidy-alphabetical-start -#![feature(array_windows)] +#![cfg_attr(bootstrap, feature(array_windows))] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(const_type_name)] diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 05683940cba4..8b48cf5a6501 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,5 +1,5 @@ // tidy-alphabetical-start -#![feature(array_windows)] +#![cfg_attr(bootstrap, feature(array_windows))] #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 2e03ccb1aa1a..31f82860b73d 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -17,8 +17,8 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(array_windows))] #![cfg_attr(target_arch = "loongarch64", feature(stdarch_loongarch))] -#![feature(array_windows)] #![feature(cfg_select)] #![feature(core_io_borrowed_buf)] #![feature(if_let_guard)] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3f391fe2c1de..bfb6eeb8dad1 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -89,7 +89,6 @@ #![feature(alloc_layout_extra)] #![feature(allocator_api)] #![feature(array_into_iter_constructors)] -#![feature(array_windows)] #![feature(ascii_char)] #![feature(assert_matches)] #![feature(async_fn_traits)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index a83b51ccb60c..e7d0fc3454ee 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -18,7 +18,7 @@ use core::mem::MaybeUninit; #[cfg(not(no_global_oom_handling))] use core::ptr; -#[unstable(feature = "array_windows", issue = "75027")] +#[stable(feature = "array_windows", since = "CURRENT_RUSTC_VERSION")] pub use core::slice::ArrayWindows; #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] pub use core::slice::EscapeAscii; diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index a2fbf6ead646..0e70be783625 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2187,8 +2187,6 @@ unsafe impl Sync for ChunksExactMut<'_, T> where T: Sync {} /// # Example /// /// ``` -/// #![feature(array_windows)] -/// /// let slice = [0, 1, 2, 3]; /// let mut iter = slice.array_windows::<2>(); /// assert_eq!(iter.next(), Some(&[0, 1])); @@ -2200,7 +2198,7 @@ unsafe impl Sync for ChunksExactMut<'_, T> where T: Sync {} /// [`array_windows`]: slice::array_windows /// [slices]: slice #[derive(Debug, Clone, Copy)] -#[unstable(feature = "array_windows", issue = "75027")] +#[stable(feature = "array_windows", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ArrayWindows<'a, T: 'a, const N: usize> { v: &'a [T], @@ -2213,7 +2211,7 @@ pub(super) const fn new(slice: &'a [T]) -> Self { } } -#[unstable(feature = "array_windows", issue = "75027")] +#[stable(feature = "array_windows", since = "CURRENT_RUSTC_VERSION")] impl<'a, T, const N: usize> Iterator for ArrayWindows<'a, T, N> { type Item = &'a [T; N]; @@ -2250,7 +2248,7 @@ fn last(self) -> Option { } } -#[unstable(feature = "array_windows", issue = "75027")] +#[stable(feature = "array_windows", since = "CURRENT_RUSTC_VERSION")] impl<'a, T, const N: usize> DoubleEndedIterator for ArrayWindows<'a, T, N> { #[inline] fn next_back(&mut self) -> Option<&'a [T; N]> { @@ -2269,7 +2267,7 @@ impl<'a, T, const N: usize> DoubleEndedIterator for ArrayWindows<'a, T, N> { } } -#[unstable(feature = "array_windows", issue = "75027")] +#[stable(feature = "array_windows", since = "CURRENT_RUSTC_VERSION")] impl ExactSizeIterator for ArrayWindows<'_, T, N> { fn is_empty(&self) -> bool { self.v.len() < N diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index f03f2045444d..8b32f00bc861 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -51,7 +51,7 @@ pub use index::SliceIndex; #[unstable(feature = "slice_range", issue = "76393")] pub use index::{range, try_range}; -#[unstable(feature = "array_windows", issue = "75027")] +#[stable(feature = "array_windows", since = "CURRENT_RUSTC_VERSION")] pub use iter::ArrayWindows; #[stable(feature = "slice_group_by", since = "1.77.0")] pub use iter::{ChunkBy, ChunkByMut}; @@ -1626,7 +1626,6 @@ pub const fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_ /// # Examples /// /// ``` - /// #![feature(array_windows)] /// let slice = [0, 1, 2, 3]; /// let mut iter = slice.array_windows(); /// assert_eq!(iter.next().unwrap(), &[0, 1]); @@ -1636,7 +1635,7 @@ pub const fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_ /// ``` /// /// [`windows`]: slice::windows - #[unstable(feature = "array_windows", issue = "75027")] + #[stable(feature = "array_windows", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] #[inline] #[track_caller] diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 436856635c1c..1c22ef23a7b0 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -5,7 +5,6 @@ #![feature(array_ptr_get)] #![feature(array_try_from_fn)] #![feature(array_try_map)] -#![feature(array_windows)] #![feature(ascii_char)] #![feature(ascii_char_variants)] #![feature(async_iter_from_iter)] diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 230d83dacc95..bc62d9b8450c 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(array_windows)] +#![cfg_attr(bootstrap, feature(array_windows))] #![feature(box_patterns)] #![feature(macro_metavar_expr_concat)] #![feature(f128)] diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index ed164fcf371b..409f13013489 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -5,7 +5,7 @@ #![feature(rustc_private)] #![feature(assert_matches)] #![feature(unwrap_infallible)] -#![feature(array_windows)] +#![cfg_attr(bootstrap, feature(array_windows))] #![recursion_limit = "512"] #![allow( clippy::missing_errors_doc, From 3e88c6a639ea28ada59ef63f4b11814d6de5c489 Mon Sep 17 00:00:00 2001 From: bendn Date: Tue, 11 Nov 2025 13:46:52 +0700 Subject: [PATCH 170/585] stabilize [T]::array_windows --- clippy_lints/src/lib.rs | 2 +- clippy_utils/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 230d83dacc95..bc62d9b8450c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(array_windows)] +#![cfg_attr(bootstrap, feature(array_windows))] #![feature(box_patterns)] #![feature(macro_metavar_expr_concat)] #![feature(f128)] diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index ed164fcf371b..409f13013489 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -5,7 +5,7 @@ #![feature(rustc_private)] #![feature(assert_matches)] #![feature(unwrap_infallible)] -#![feature(array_windows)] +#![cfg_attr(bootstrap, feature(array_windows))] #![recursion_limit = "512"] #![allow( clippy::missing_errors_doc, From 37c9b16b1dbe9e06ae5f269104f398887ff08021 Mon Sep 17 00:00:00 2001 From: bendn Date: Tue, 11 Nov 2025 14:02:18 +0700 Subject: [PATCH 171/585] document --- library/core/src/slice/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 8b32f00bc861..dc34d2a21ee9 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1620,8 +1620,11 @@ pub const fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_ /// /// # Panics /// - /// Panics if `N` is zero. This check will most probably get changed to a compile time - /// error before this method gets stabilized. + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. /// /// # Examples /// From 662192a878040ca13b7851baacc567f73feb57df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Mon, 1 Dec 2025 13:59:52 +0100 Subject: [PATCH 172/585] Stop adding MSYS2 to PATH Rust no longer requires MSYS2 tools like make. --- src/ci/scripts/install-mingw.sh | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index 17bedaa7b826..da8e1d55f3ae 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -47,12 +47,6 @@ if isWindows && isKnownToBeMingwBuild; then ;; esac - # Stop /msys64/bin from being prepended to PATH by adding the bin directory manually. - # Note that this intentionally uses a Windows style path instead of the msys2 path to - # avoid being auto-translated into `/usr/bin`, which will not have the desired effect. - msys2Path="c:/msys64" - ciCommandAddPath "${msys2Path}/usr/bin" - case "${mingw_archive}" in *.7z) curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" @@ -73,12 +67,4 @@ if isWindows && isKnownToBeMingwBuild; then esac ciCommandAddPath "$(cygpath -m "$(pwd)/${mingw_dir}/bin")" - - # MSYS2 is not installed on AArch64 runners - if [[ "${CI_JOB_NAME}" != *aarch64-llvm* ]]; then - # Initialize mingw for the user. - # This should be done by github but isn't for some reason. - # (see https://github.com/actions/runner-images/issues/12600) - /c/msys64/usr/bin/bash -lc ' ' - fi fi From 1b76a346e826930d0b1e4901781da6a3038bac99 Mon Sep 17 00:00:00 2001 From: yanglsh Date: Sun, 22 Jun 2025 15:43:06 +0800 Subject: [PATCH 173/585] fix: `large_stack_frames` FP on compiler generated targets --- CHANGELOG.md | 1 + book/src/lint_configuration.md | 10 ++ clippy_config/src/conf.rs | 3 + clippy_lints/src/large_stack_frames.rs | 152 ++++++++++++------ .../large_stack_frames_for_macros/clippy.toml | 1 + .../large_stack_frames.rs | 42 +++++ .../large_stack_frames.stderr | 89 ++++++++++ .../clippy.toml | 2 + .../large_stack_frames.rs | 13 ++ .../toml_unknown_key/conf_unknown_key.stderr | 3 + 10 files changed, 269 insertions(+), 47 deletions(-) create mode 100644 tests/ui-toml/large_stack_frames_for_macros/clippy.toml create mode 100644 tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs create mode 100644 tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.stderr create mode 100644 tests/ui-toml/large_stack_frames_for_special_targets/clippy.toml create mode 100644 tests/ui-toml/large_stack_frames_for_special_targets/large_stack_frames.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7db95c081aa3..d7f663ee9f1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7081,6 +7081,7 @@ Released 2018-09-13 [`allow-expect-in-consts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-consts [`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests [`allow-indexing-slicing-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-indexing-slicing-in-tests +[`allow-large-stack-frames-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-large-stack-frames-in-tests [`allow-mixed-uninlined-format-args`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-mixed-uninlined-format-args [`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings [`allow-panic-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-panic-in-tests diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 6569bdabf115..c2e7e19042c7 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -111,6 +111,16 @@ Whether `indexing_slicing` should be allowed in test functions or `#[cfg(test)]` * [`indexing_slicing`](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing) +## `allow-large-stack-frames-in-tests` +Whether functions inside `#[cfg(test)]` modules or test functions should be checked. + +**Default Value:** `true` + +--- +**Affected lints:** +* [`large_stack_frames`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames) + + ## `allow-mixed-uninlined-format-args` Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 2a042e6c3d85..2cec8a1a2821 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -373,6 +373,9 @@ fn span_from_toml_range(file: &SourceFile, span: Range) -> Span { /// Whether `indexing_slicing` should be allowed in test functions or `#[cfg(test)]` #[lints(indexing_slicing)] allow_indexing_slicing_in_tests: bool = false, + /// Whether functions inside `#[cfg(test)]` modules or test functions should be checked. + #[lints(large_stack_frames)] + allow_large_stack_frames_in_tests: bool = true, /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` #[lints(uninlined_format_args)] allow_mixed_uninlined_format_args: bool = true, diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 5ed948c02bbc..6b0080d04c44 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -2,15 +2,16 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::fn_has_unsatisfiable_preds; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::{HasSession, SpanRangeExt}; +use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_in_test}; +use rustc_errors::Diag; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_lexer::is_ident; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::Span; +use rustc_span::{Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -83,12 +84,14 @@ pub struct LargeStackFrames { maximum_allowed_size: u64, + allow_large_stack_frames_in_tests: bool, } impl LargeStackFrames { pub fn new(conf: &'static Conf) -> Self { Self { maximum_allowed_size: conf.stack_size_threshold, + allow_large_stack_frames_in_tests: conf.allow_large_stack_frames_in_tests, } } } @@ -152,67 +155,122 @@ fn check_fn( let mir = cx.tcx.optimized_mir(def_id); let typing_env = mir.typing_env(cx.tcx); - let sizes_of_locals = || { - mir.local_decls.iter().filter_map(|local| { + let sizes_of_locals = mir + .local_decls + .iter() + .filter_map(|local| { let layout = cx.tcx.layout_of(typing_env.as_query_input(local.ty)).ok()?; Some((local, layout.size.bytes())) }) - }; + .collect::>(); - let frame_size = sizes_of_locals().fold(Space::Used(0), |sum, (_, size)| sum + size); + let frame_size = sizes_of_locals + .iter() + .fold(Space::Used(0), |sum, (_, size)| sum + *size); let limit = self.maximum_allowed_size; if frame_size.exceeds_limit(limit) { // Point at just the function name if possible, because lints that span // the entire body and don't have to are less legible. - let fn_span = match fn_kind { - FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span, - FnKind::Closure => entire_fn_span, + let (fn_span, fn_name) = match fn_kind { + FnKind::ItemFn(ident, _, _) => (ident.span, format!("function `{}`", ident.name)), + FnKind::Method(ident, _) => (ident.span, format!("method `{}`", ident.name)), + FnKind::Closure => (entire_fn_span, "closure".to_string()), }; + // Don't lint inside tests if configured to not do so. + if self.allow_large_stack_frames_in_tests && is_in_test(cx.tcx, cx.tcx.local_def_id_to_hir_id(local_def_id)) + { + return; + } + + let explain_lint = |diag: &mut Diag<'_, ()>, ctxt: SyntaxContext| { + // Point out the largest individual contribution to this size, because + // it is the most likely to be unintentionally large. + if let Some((local, size)) = sizes_of_locals.iter().max_by_key(|&(_, size)| size) + && let local_span = local.source_info.span + && local_span.ctxt() == ctxt + { + let size = Space::Used(*size); // pluralizes for us + let ty = local.ty; + + // TODO: Is there a cleaner, robust way to ask this question? + // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data", + // and that doesn't get us the true name in scope rather than the span text either. + if let Some(name) = local_span.get_source_text(cx) + && is_ident(&name) + { + // If the local is an ordinary named variable, + // print its name rather than relying solely on the span. + diag.span_label( + local_span, + format!("`{name}` is the largest part, at {size} for type `{ty}`"), + ); + } else { + diag.span_label( + local_span, + format!("this is the largest part, at {size} for type `{ty}`"), + ); + } + } + + // Explain why we are linting this and not other functions. + diag.note(format!( + "{frame_size} is larger than Clippy's configured `stack-size-threshold` of {limit}" + )); + + // Explain why the user should care, briefly. + diag.note_once( + "allocating large amounts of stack space can overflow the stack \ + and cause the program to abort", + ); + }; + + if fn_span.from_expansion() { + // Don't lint on the main function generated by `--test` target + if cx.sess().is_test_crate() && is_entrypoint_fn(cx, local_def_id.to_def_id()) { + return; + } + + let is_from_external_macro = fn_span.in_external_macro(cx.sess().source_map()); + span_lint_and_then( + cx, + LARGE_STACK_FRAMES, + fn_span.source_callsite(), + format!( + "{} generated by this macro may allocate a lot of stack space", + if is_from_external_macro { + cx.tcx.def_descr(local_def_id.into()) + } else { + fn_name.as_str() + } + ), + |diag| { + if is_from_external_macro { + return; + } + + diag.span_label( + fn_span, + format!( + "this {} has a stack frame size of {frame_size}", + cx.tcx.def_descr(local_def_id.into()) + ), + ); + + explain_lint(diag, fn_span.ctxt()); + }, + ); + return; + } + span_lint_and_then( cx, LARGE_STACK_FRAMES, fn_span, format!("this function may allocate {frame_size} on the stack"), |diag| { - // Point out the largest individual contribution to this size, because - // it is the most likely to be unintentionally large. - if let Some((local, size)) = sizes_of_locals().max_by_key(|&(_, size)| size) { - let local_span: Span = local.source_info.span; - let size = Space::Used(size); // pluralizes for us - let ty = local.ty; - - // TODO: Is there a cleaner, robust way to ask this question? - // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data", - // and that doesn't get us the true name in scope rather than the span text either. - if let Some(name) = local_span.get_source_text(cx) - && is_ident(&name) - { - // If the local is an ordinary named variable, - // print its name rather than relying solely on the span. - diag.span_label( - local_span, - format!("`{name}` is the largest part, at {size} for type `{ty}`"), - ); - } else { - diag.span_label( - local_span, - format!("this is the largest part, at {size} for type `{ty}`"), - ); - } - } - - // Explain why we are linting this and not other functions. - diag.note(format!( - "{frame_size} is larger than Clippy's configured `stack-size-threshold` of {limit}" - )); - - // Explain why the user should care, briefly. - diag.note_once( - "allocating large amounts of stack space can overflow the stack \ - and cause the program to abort", - ); + explain_lint(diag, SyntaxContext::root()); }, ); } diff --git a/tests/ui-toml/large_stack_frames_for_macros/clippy.toml b/tests/ui-toml/large_stack_frames_for_macros/clippy.toml new file mode 100644 index 000000000000..b6fd0e8a0483 --- /dev/null +++ b/tests/ui-toml/large_stack_frames_for_macros/clippy.toml @@ -0,0 +1 @@ +stack-size-threshold = 0 diff --git a/tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs b/tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs new file mode 100644 index 000000000000..1f6265590f93 --- /dev/null +++ b/tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs @@ -0,0 +1,42 @@ +//@ignore-target: i686 +//@normalize-stderr-test: "\b10000(08|16|32)\b" -> "100$$PTR" +//@normalize-stderr-test: "\b2500(060|120)\b" -> "250$$PTR" + +#![warn(clippy::large_stack_frames)] + +extern crate serde; +use serde::{Deserialize, Serialize}; + +struct ArrayDefault([u8; N]); + +macro_rules! mac { + ($name:ident) => { + fn foo() { + let $name = 1; + println!("macro_name called"); + } + + fn bar() { + let $name = ArrayDefault([0; 1000]); + } + }; +} + +mac!(something); +//~^ large_stack_frames +//~| large_stack_frames + +#[derive(Deserialize, Serialize)] +//~^ large_stack_frames +//~| large_stack_frames +//~| large_stack_frames +//~| large_stack_frames +//~| large_stack_frames +//~| large_stack_frames +//~| large_stack_frames +//~| large_stack_frames +struct S { + a: [u128; 31], +} + +fn main() {} diff --git a/tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.stderr b/tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.stderr new file mode 100644 index 000000000000..bc222f6b1039 --- /dev/null +++ b/tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.stderr @@ -0,0 +1,89 @@ +error: function `foo` generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:25:1 + | +LL | fn foo() { + | --- this function has a stack frame size of 20 bytes +... +LL | mac!(something); + | ^^^^^^^^^^^^^^^ + | + = note: 20 bytes is larger than Clippy's configured `stack-size-threshold` of 0 + = note: allocating large amounts of stack space can overflow the stack and cause the program to abort + = note: `-D clippy::large-stack-frames` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_stack_frames)]` + +error: function `bar` generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:25:1 + | +LL | fn bar() { + | --- this function has a stack frame size of 2000 bytes +LL | let $name = ArrayDefault([0; 1000]); + | --------- this is the largest part, at 1000 bytes for type `[u8; 1000]` +... +LL | mac!(something); + | ^^^^^^^^^^^^^^^ + | + = note: 2000 bytes is larger than Clippy's configured `stack-size-threshold` of 0 + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:10 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: method generated by this macro may allocate a lot of stack space + --> tests/ui-toml/large_stack_frames_for_macros/large_stack_frames.rs:29:23 + | +LL | #[derive(Deserialize, Serialize)] + | ^^^^^^^^^ + +error: aborting due to 10 previous errors + diff --git a/tests/ui-toml/large_stack_frames_for_special_targets/clippy.toml b/tests/ui-toml/large_stack_frames_for_special_targets/clippy.toml new file mode 100644 index 000000000000..02f3bc02dc4b --- /dev/null +++ b/tests/ui-toml/large_stack_frames_for_special_targets/clippy.toml @@ -0,0 +1,2 @@ +stack-size-threshold = 0 +allow-large-stack-frames-in-tests = false diff --git a/tests/ui-toml/large_stack_frames_for_special_targets/large_stack_frames.rs b/tests/ui-toml/large_stack_frames_for_special_targets/large_stack_frames.rs new file mode 100644 index 000000000000..cc01232ca408 --- /dev/null +++ b/tests/ui-toml/large_stack_frames_for_special_targets/large_stack_frames.rs @@ -0,0 +1,13 @@ +// This test checks if `clippy::large_stack_frames` is working correctly when encountering functions +// generated by special compiling targets like `--test`. +//@compile-flags: --test +//@check-pass + +#![warn(clippy::large_stack_frames)] + +#[cfg(test)] +#[expect(clippy::large_stack_frames)] +mod test { + #[test] + fn main_test() {} +} diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 2d9503c5ac53..ac449bc82b9d 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -9,6 +9,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests + allow-large-stack-frames-in-tests allow-mixed-uninlined-format-args allow-one-hash-in-raw-strings allow-panic-in-tests @@ -106,6 +107,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests + allow-large-stack-frames-in-tests allow-mixed-uninlined-format-args allow-one-hash-in-raw-strings allow-panic-in-tests @@ -203,6 +205,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests + allow-large-stack-frames-in-tests allow-mixed-uninlined-format-args allow-one-hash-in-raw-strings allow-panic-in-tests From dc61415746396bc38da4141680b0b24a7b070635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Mon, 1 Dec 2025 15:54:58 +0100 Subject: [PATCH 174/585] Prefer helper functions to identify MinGW targets --- src/bootstrap/src/core/build_steps/dist.rs | 4 ++-- src/bootstrap/src/core/build_steps/llvm.rs | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 0efe0cbbc80f..40149ee09427 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -347,14 +347,14 @@ fn runtime_dll_dist(rust_root: &Path, target: TargetSelection, builder: &Builder let mut rustc_dlls = vec![]; // windows-gnu and windows-gnullvm require different runtime libs - if target.ends_with("windows-gnu") { + if target.is_windows_gnu() { rustc_dlls.push("libwinpthread-1.dll"); if target.starts_with("i686-") { rustc_dlls.push("libgcc_s_dw2-1.dll"); } else { rustc_dlls.push("libgcc_s_seh-1.dll"); } - } else if target.ends_with("windows-gnullvm") { + } else if target.is_windows_gnullvm() { rustc_dlls.push("libunwind.dll"); } else { panic!("Vendoring of runtime DLLs for `{target}` is not supported`"); diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index a591be05291f..4de5184c0e99 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -284,8 +284,7 @@ fn run(self, builder: &Builder<'_>) -> LlvmResult { LlvmBuildStatus::ShouldBuild(m) => m, }; - if builder.llvm_link_shared() && target.is_windows() && !target.ends_with("windows-gnullvm") - { + if builder.llvm_link_shared() && target.is_windows() && !target.is_windows_gnullvm() { panic!("shared linking to LLVM is not currently supported on {}", target.triple); } From 5ac265676a6a62946382a67a32661b94338c15cd Mon Sep 17 00:00:00 2001 From: ceptontech <> Date: Fri, 24 Oct 2025 14:26:04 -0700 Subject: [PATCH 175/585] feat(transmute_ptr_to_ref): Handle a pointer wrapped in a struct Now the program checks for transmutting from a struct containing a single raw pointer to a reference. ```Rust struct Foo(*const i32); fn foo(foo: Foo) -> &i32 { unsafe { transmute(foo) } } ``` changelog: [`transmute_ptr_to_ref`]: now checks for a pointer wrapped in a struct --- clippy_lints/src/transmute/mod.rs | 34 +++++- .../src/transmute/transmute_ptr_to_ref.rs | 3 +- tests/ui/transmute_ptr_to_ref.fixed | 56 ++++++++- tests/ui/transmute_ptr_to_ref.rs | 56 ++++++++- tests/ui/transmute_ptr_to_ref.stderr | 110 ++++++++++++++---- 5 files changed, 230 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index d643f7aea497..839491b082f2 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -18,8 +18,11 @@ use clippy_config::Conf; use clippy_utils::is_in_const_context; use clippy_utils::msrvs::Msrv; +use clippy_utils::sugg::Sugg; +use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; @@ -490,6 +493,32 @@ impl Transmute { pub fn new(conf: &'static Conf) -> Self { Self { msrv: conf.msrv } } + + /// When transmuting, a struct containing a single field works like the field. + /// This function extracts the field type and the expression to get the field. + fn extract_struct_field<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + outer_type: Ty<'tcx>, + outer: &'tcx Expr<'tcx>, + ) -> (Ty<'tcx>, Sugg<'tcx>) { + let mut applicability = Applicability::MachineApplicable; + let outer_sugg = Sugg::hir_with_context(cx, outer, e.span.ctxt(), "..", &mut applicability); + if let ty::Adt(struct_def, struct_args) = *outer_type.kind() + && struct_def.is_struct() + && let mut fields = struct_def.all_fields() + && let Some(first) = fields.next() + && fields.next().is_none() + && first.vis.is_accessible_from(cx.tcx.parent_module(outer.hir_id), cx.tcx) + { + ( + first.ty(cx.tcx, struct_args), + Sugg::NonParen(format!("{}.{}", outer_sugg.maybe_paren(), first.name).into()), + ) + } else { + (outer_type, outer_sugg) + } + } } impl<'tcx> LateLintPass<'tcx> for Transmute { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { @@ -516,11 +545,14 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { return; } + // A struct having a single pointer can be treated like a pointer. + let (from_field_ty, from_field_expr) = Self::extract_struct_field(cx, e, from_ty, arg); + let linted = wrong_transmute::check(cx, e, from_ty, to_ty) | crosspointer_transmute::check(cx, e, from_ty, to_ty) | transmuting_null::check(cx, e, arg, to_ty) | transmute_null_to_fn::check(cx, e, arg, to_ty) - | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv) + | transmute_ptr_to_ref::check(cx, e, from_field_ty, to_ty, from_field_expr.clone(), path, self.msrv) | missing_transmute_annotations::check(cx, path, arg, from_ty, to_ty, e.hir_id) | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, self.msrv) diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index e67ab6a73d26..ba107eed6b14 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>( e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, - arg: &'tcx Expr<'_>, + arg: sugg::Sugg<'_>, path: &'tcx Path<'_>, msrv: Msrv, ) -> bool { @@ -27,7 +27,6 @@ pub(super) fn check<'tcx>( e.span, format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"), |diag| { - let arg = sugg::Sugg::hir(cx, arg, ".."); let (deref, cast) = match mutbl { Mutability::Mut => ("&mut *", "*mut"), Mutability::Not => ("&*", "*const"), diff --git a/tests/ui/transmute_ptr_to_ref.fixed b/tests/ui/transmute_ptr_to_ref.fixed index c130575df960..8de47031a400 100644 --- a/tests/ui/transmute_ptr_to_ref.fixed +++ b/tests/ui/transmute_ptr_to_ref.fixed @@ -55,6 +55,52 @@ fn issue1231() { //~^ transmute_ptr_to_ref } +#[derive(Clone, Copy)] +struct PtrRefNamed<'a> { + ptr: *const &'a u32, +} +#[derive(Clone, Copy)] +struct PtrRef<'a>(*const &'a u32); +#[derive(Clone, Copy)] +struct PtrSliceRef<'a>(*const [&'a str]); +#[derive(Clone, Copy)] +struct PtrSlice(*const [i32]); +#[derive(Clone, Copy)] +struct Ptr(*const u32); +impl std::ops::Add for Ptr { + type Output = Self; + fn add(self, _: Self) -> Self { + self + } +} +mod ptr_mod { + #[derive(Clone, Copy)] + pub struct Ptr(*const u32); +} +fn issue1966(u: PtrSlice, v: PtrSliceRef, w: Ptr, x: PtrRefNamed, y: PtrRef, z: ptr_mod::Ptr) { + unsafe { + let _: &i32 = &*(w.0 as *const i32); + //~^ transmute_ptr_to_ref + let _: &u32 = &*w.0; + //~^ transmute_ptr_to_ref + let _: &&u32 = &*x.ptr.cast::<&u32>(); + //~^ transmute_ptr_to_ref + // The field is not accessible. The program should not generate code + // that accesses the field. + let _: &u32 = std::mem::transmute(z); + let _ = &*w.0.cast::(); + //~^ transmute_ptr_to_ref + let _: &[&str] = &*(v.0 as *const [&str]); + //~^ transmute_ptr_to_ref + let _ = &*(u.0 as *const [i32]); + //~^ transmute_ptr_to_ref + let _: &&u32 = &*y.0.cast::<&u32>(); + //~^ transmute_ptr_to_ref + let _: &u32 = &*(w + w).0; + //~^ transmute_ptr_to_ref + } +} + fn issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { unsafe { match 0 { @@ -89,7 +135,7 @@ fn meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { } #[clippy::msrv = "1.37"] -fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { +fn under_msrv<'a, 'b, 'c>(x: *const &'a u32, y: PtrRef) -> &'c &'b u32 { unsafe { let a = 0u32; let a = &a as *const u32; @@ -97,10 +143,16 @@ fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { //~^ transmute_ptr_to_ref let _: &u32 = &*(a as *const u32); //~^ transmute_ptr_to_ref + let _ = &*(Ptr(a).0 as *const u32); + //~^ transmute_ptr_to_ref match 0 { 0 => &*(x as *const () as *const &u32), //~^ transmute_ptr_to_ref - _ => &*(x as *const () as *const &'b u32), + 1 => &*(x as *const () as *const &'b u32), + //~^ transmute_ptr_to_ref + 2 => &*(y.0 as *const () as *const &u32), + //~^ transmute_ptr_to_ref + _ => &*(y.0 as *const () as *const &'b u32), //~^ transmute_ptr_to_ref } } diff --git a/tests/ui/transmute_ptr_to_ref.rs b/tests/ui/transmute_ptr_to_ref.rs index f79d54234a2c..52fe669de935 100644 --- a/tests/ui/transmute_ptr_to_ref.rs +++ b/tests/ui/transmute_ptr_to_ref.rs @@ -55,6 +55,52 @@ struct Foo<'a, T> { //~^ transmute_ptr_to_ref } +#[derive(Clone, Copy)] +struct PtrRefNamed<'a> { + ptr: *const &'a u32, +} +#[derive(Clone, Copy)] +struct PtrRef<'a>(*const &'a u32); +#[derive(Clone, Copy)] +struct PtrSliceRef<'a>(*const [&'a str]); +#[derive(Clone, Copy)] +struct PtrSlice(*const [i32]); +#[derive(Clone, Copy)] +struct Ptr(*const u32); +impl std::ops::Add for Ptr { + type Output = Self; + fn add(self, _: Self) -> Self { + self + } +} +mod ptr_mod { + #[derive(Clone, Copy)] + pub struct Ptr(*const u32); +} +fn issue1966(u: PtrSlice, v: PtrSliceRef, w: Ptr, x: PtrRefNamed, y: PtrRef, z: ptr_mod::Ptr) { + unsafe { + let _: &i32 = std::mem::transmute(w); + //~^ transmute_ptr_to_ref + let _: &u32 = std::mem::transmute(w); + //~^ transmute_ptr_to_ref + let _: &&u32 = core::mem::transmute(x); + //~^ transmute_ptr_to_ref + // The field is not accessible. The program should not generate code + // that accesses the field. + let _: &u32 = std::mem::transmute(z); + let _ = std::mem::transmute::<_, &u32>(w); + //~^ transmute_ptr_to_ref + let _: &[&str] = core::mem::transmute(v); + //~^ transmute_ptr_to_ref + let _ = std::mem::transmute::<_, &[i32]>(u); + //~^ transmute_ptr_to_ref + let _: &&u32 = std::mem::transmute(y); + //~^ transmute_ptr_to_ref + let _: &u32 = std::mem::transmute(w + w); + //~^ transmute_ptr_to_ref + } +} + fn issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { unsafe { match 0 { @@ -89,7 +135,7 @@ fn meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { } #[clippy::msrv = "1.37"] -fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { +fn under_msrv<'a, 'b, 'c>(x: *const &'a u32, y: PtrRef) -> &'c &'b u32 { unsafe { let a = 0u32; let a = &a as *const u32; @@ -97,10 +143,16 @@ fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { //~^ transmute_ptr_to_ref let _: &u32 = std::mem::transmute::<_, &u32>(a); //~^ transmute_ptr_to_ref + let _ = std::mem::transmute::<_, &u32>(Ptr(a)); + //~^ transmute_ptr_to_ref match 0 { 0 => std::mem::transmute(x), //~^ transmute_ptr_to_ref - _ => std::mem::transmute::<_, &&'b u32>(x), + 1 => std::mem::transmute::<_, &&'b u32>(x), + //~^ transmute_ptr_to_ref + 2 => std::mem::transmute(y), + //~^ transmute_ptr_to_ref + _ => std::mem::transmute::<_, &&'b u32>(y), //~^ transmute_ptr_to_ref } } diff --git a/tests/ui/transmute_ptr_to_ref.stderr b/tests/ui/transmute_ptr_to_ref.stderr index 3f404d295fef..c0f0ca916761 100644 --- a/tests/ui/transmute_ptr_to_ref.stderr +++ b/tests/ui/transmute_ptr_to_ref.stderr @@ -61,125 +61,191 @@ error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`) LL | unsafe { std::mem::transmute::<_, Bar>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)` +error: transmute from a pointer type (`*const u32`) to a reference type (`&i32`) + --> tests/ui/transmute_ptr_to_ref.rs:82:23 + | +LL | let _: &i32 = std::mem::transmute(w); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(w.0 as *const i32)` + +error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:84:23 + | +LL | let _: &u32 = std::mem::transmute(w); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*w.0` + error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:61:18 + --> tests/ui/transmute_ptr_to_ref.rs:86:24 + | +LL | let _: &&u32 = core::mem::transmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.ptr.cast::<&u32>()` + +error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:91:17 + | +LL | let _ = std::mem::transmute::<_, &u32>(w); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*w.0.cast::()` + +error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`) + --> tests/ui/transmute_ptr_to_ref.rs:93:26 + | +LL | let _: &[&str] = core::mem::transmute(v); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(v.0 as *const [&str])` + +error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`) + --> tests/ui/transmute_ptr_to_ref.rs:95:17 + | +LL | let _ = std::mem::transmute::<_, &[i32]>(u); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(u.0 as *const [i32])` + +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:97:24 + | +LL | let _: &&u32 = std::mem::transmute(y); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.0.cast::<&u32>()` + +error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:99:23 + | +LL | let _: &u32 = std::mem::transmute(w + w); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(w + w).0` + +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:107:18 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:63:18 + --> tests/ui/transmute_ptr_to_ref.rs:109:18 | LL | 1 => std::mem::transmute(y), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:65:18 + --> tests/ui/transmute_ptr_to_ref.rs:111:18 | LL | 2 => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:67:18 + --> tests/ui/transmute_ptr_to_ref.rs:113:18 | LL | _ => std::mem::transmute::<_, &&'b u32>(y), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:78:23 + --> tests/ui/transmute_ptr_to_ref.rs:124:23 | LL | let _: &u32 = std::mem::transmute(a); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:80:23 + --> tests/ui/transmute_ptr_to_ref.rs:126:23 | LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:83:18 + --> tests/ui/transmute_ptr_to_ref.rs:129:18 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:85:18 + --> tests/ui/transmute_ptr_to_ref.rs:131:18 | LL | _ => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:96:23 + --> tests/ui/transmute_ptr_to_ref.rs:142:23 | LL | let _: &u32 = std::mem::transmute(a); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:98:23 + --> tests/ui/transmute_ptr_to_ref.rs:144:23 | LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)` +error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:146:17 + | +LL | let _ = std::mem::transmute::<_, &u32>(Ptr(a)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(Ptr(a).0 as *const u32)` + error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:101:18 + --> tests/ui/transmute_ptr_to_ref.rs:149:18 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:103:18 + --> tests/ui/transmute_ptr_to_ref.rs:151:18 | -LL | _ => std::mem::transmute::<_, &&'b u32>(x), +LL | 1 => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)` +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:153:18 + | +LL | 2 => std::mem::transmute(y), + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(y.0 as *const () as *const &u32)` + +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> tests/ui/transmute_ptr_to_ref.rs:155:18 + | +LL | _ => std::mem::transmute::<_, &&'b u32>(y), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(y.0 as *const () as *const &'b u32)` + error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[u32]`) - --> tests/ui/transmute_ptr_to_ref.rs:113:17 + --> tests/ui/transmute_ptr_to_ref.rs:165:17 | LL | let _ = core::mem::transmute::<_, &[u32]>(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [u32])` error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[u32]`) - --> tests/ui/transmute_ptr_to_ref.rs:115:25 + --> tests/ui/transmute_ptr_to_ref.rs:167:25 | LL | let _: &[u32] = core::mem::transmute(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [u32])` error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&[u8]]`) - --> tests/ui/transmute_ptr_to_ref.rs:119:17 + --> tests/ui/transmute_ptr_to_ref.rs:171:17 | LL | let _ = core::mem::transmute::<_, &[&[u8]]>(a_s_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&[u8]])` error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&[u8]]`) - --> tests/ui/transmute_ptr_to_ref.rs:121:27 + --> tests/ui/transmute_ptr_to_ref.rs:173:27 | LL | let _: &[&[u8]] = core::mem::transmute(a_s_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&[u8]])` error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`) - --> tests/ui/transmute_ptr_to_ref.rs:125:17 + --> tests/ui/transmute_ptr_to_ref.rs:177:17 | LL | let _ = core::mem::transmute::<_, &[i32]>(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [i32])` error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`) - --> tests/ui/transmute_ptr_to_ref.rs:127:25 + --> tests/ui/transmute_ptr_to_ref.rs:179:25 | LL | let _: &[i32] = core::mem::transmute(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*ptr` error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`) - --> tests/ui/transmute_ptr_to_ref.rs:131:17 + --> tests/ui/transmute_ptr_to_ref.rs:183:17 | LL | let _ = core::mem::transmute::<_, &[&str]>(a_s_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&str])` error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`) - --> tests/ui/transmute_ptr_to_ref.rs:133:26 + --> tests/ui/transmute_ptr_to_ref.rs:185:26 | LL | let _: &[&str] = core::mem::transmute(a_s_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&str])` -error: aborting due to 30 previous errors +error: aborting due to 41 previous errors From e9ceae44b7a659f81144ddb175d6bfa4e9b19504 Mon Sep 17 00:00:00 2001 From: ceptontech <> Date: Mon, 1 Dec 2025 09:00:29 -0800 Subject: [PATCH 176/585] feat(transmute_ptr_to_ptr): Handle a pointer wrapped in a struct Now the program checks for transmutting from a struct containing a single raw pointer to a raw pointer. changelog: [`transmute_ptr_to_ptr`]: now checks for a pointer wrapped in a struct --- clippy_lints/src/transmute/mod.rs | 2 +- .../src/transmute/transmute_ptr_to_ptr.rs | 10 +-- tests/ui/transmute_ptr_to_ptr.fixed | 23 ++++++ tests/ui/transmute_ptr_to_ptr.rs | 23 ++++++ tests/ui/transmute_ptr_to_ptr.stderr | 82 +++++++++++++++---- 5 files changed, 116 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 839491b082f2..435cd7bcba4e 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -555,7 +555,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { | transmute_ptr_to_ref::check(cx, e, from_field_ty, to_ty, from_field_expr.clone(), path, self.msrv) | missing_transmute_annotations::check(cx, path, arg, from_ty, to_ty, e.hir_id) | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) - | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, self.msrv) + | transmute_ptr_to_ptr::check(cx, e, from_field_ty, to_ty, from_field_expr, self.msrv) | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg) | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg) | (unsound_collection_transmute::check(cx, e, from_ty, to_ty) diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index 91fce5d5bd68..036b16e3dc3d 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -14,11 +14,9 @@ pub(super) fn check<'tcx>( e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, - arg: &'tcx Expr<'_>, + arg: sugg::Sugg<'_>, msrv: Msrv, ) -> bool { - let mut applicability = Applicability::MachineApplicable; - let arg_sugg = sugg::Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut applicability); match (from_ty.kind(), to_ty.kind()) { (ty::RawPtr(from_pointee_ty, from_mutbl), ty::RawPtr(to_pointee_ty, to_mutbl)) => { span_lint_and_then( @@ -34,7 +32,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion_verbose( e.span, "use `pointer::cast` instead", - format!("{}.cast::<{to_pointee_ty}>()", arg_sugg.maybe_paren()), + format!("{}.cast::<{to_pointee_ty}>()", arg.maybe_paren()), Applicability::MaybeIncorrect, ); } else if from_pointee_ty == to_pointee_ty @@ -49,14 +47,14 @@ pub(super) fn check<'tcx>( diag.span_suggestion_verbose( e.span, format!("use `pointer::{method}` instead"), - format!("{}.{method}()", arg_sugg.maybe_paren()), + format!("{}.{method}()", arg.maybe_paren()), Applicability::MaybeIncorrect, ); } else { diag.span_suggestion_verbose( e.span, "use an `as` cast instead", - arg_sugg.as_ty(to_ty), + arg.as_ty(to_ty), Applicability::MaybeIncorrect, ); } diff --git a/tests/ui/transmute_ptr_to_ptr.fixed b/tests/ui/transmute_ptr_to_ptr.fixed index 476e7e35a1f6..caba277db754 100644 --- a/tests/ui/transmute_ptr_to_ptr.fixed +++ b/tests/ui/transmute_ptr_to_ptr.fixed @@ -24,6 +24,13 @@ struct GenericParam { t: T, } +#[derive(Clone, Copy)] +struct PtrNamed { + ptr: *const u32, +} +#[derive(Clone, Copy)] +struct Ptr(*const u32); + fn transmute_ptr_to_ptr() { let ptr = &1u32 as *const u32; let mut_ptr = &mut 1u32 as *mut u32; @@ -68,6 +75,18 @@ fn transmute_ptr_to_ptr() { let _: &GenericParam<&LifetimeParam<'static>> = unsafe { transmute(&GenericParam { t: &lp }) }; } +fn issue1966() { + let ptr = &1u32 as *const u32; + unsafe { + let _: *const f32 = Ptr(ptr).0.cast::(); + //~^ transmute_ptr_to_ptr + let _: *const f32 = PtrNamed { ptr }.ptr.cast::(); + //~^ transmute_ptr_to_ptr + let _: *mut u32 = Ptr(ptr).0.cast_mut(); + //~^ transmute_ptr_to_ptr + } +} + fn lifetime_to_static(v: *mut &()) -> *const &'static () { unsafe { v as *const &() } //~^ transmute_ptr_to_ptr @@ -81,11 +100,15 @@ const _: &() = { unsafe { transmute::<&'static Zst, &'static ()>(zst) } }; +#[derive(Clone, Copy)] +struct Ptr8(*const u8); #[clippy::msrv = "1.37"] fn msrv_1_37(ptr: *const u8) { unsafe { let _: *const i8 = ptr as *const i8; //~^ transmute_ptr_to_ptr + let _: *const i8 = Ptr8(ptr).0 as *const i8; + //~^ transmute_ptr_to_ptr } } diff --git a/tests/ui/transmute_ptr_to_ptr.rs b/tests/ui/transmute_ptr_to_ptr.rs index 7356668bcab5..b3c2baf29c36 100644 --- a/tests/ui/transmute_ptr_to_ptr.rs +++ b/tests/ui/transmute_ptr_to_ptr.rs @@ -24,6 +24,13 @@ struct GenericParam { t: T, } +#[derive(Clone, Copy)] +struct PtrNamed { + ptr: *const u32, +} +#[derive(Clone, Copy)] +struct Ptr(*const u32); + fn transmute_ptr_to_ptr() { let ptr = &1u32 as *const u32; let mut_ptr = &mut 1u32 as *mut u32; @@ -68,6 +75,18 @@ fn transmute_ptr_to_ptr() { let _: &GenericParam<&LifetimeParam<'static>> = unsafe { transmute(&GenericParam { t: &lp }) }; } +fn issue1966() { + let ptr = &1u32 as *const u32; + unsafe { + let _: *const f32 = transmute(Ptr(ptr)); + //~^ transmute_ptr_to_ptr + let _: *const f32 = transmute(PtrNamed { ptr }); + //~^ transmute_ptr_to_ptr + let _: *mut u32 = transmute(Ptr(ptr)); + //~^ transmute_ptr_to_ptr + } +} + fn lifetime_to_static(v: *mut &()) -> *const &'static () { unsafe { transmute(v) } //~^ transmute_ptr_to_ptr @@ -81,11 +100,15 @@ fn lifetime_to_static(v: *mut &()) -> *const &'static () { unsafe { transmute::<&'static Zst, &'static ()>(zst) } }; +#[derive(Clone, Copy)] +struct Ptr8(*const u8); #[clippy::msrv = "1.37"] fn msrv_1_37(ptr: *const u8) { unsafe { let _: *const i8 = transmute(ptr); //~^ transmute_ptr_to_ptr + let _: *const i8 = transmute(Ptr8(ptr)); + //~^ transmute_ptr_to_ptr } } diff --git a/tests/ui/transmute_ptr_to_ptr.stderr b/tests/ui/transmute_ptr_to_ptr.stderr index c8db4fe214fd..ba9e6df6c2d7 100644 --- a/tests/ui/transmute_ptr_to_ptr.stderr +++ b/tests/ui/transmute_ptr_to_ptr.stderr @@ -1,5 +1,5 @@ error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:32:29 + --> tests/ui/transmute_ptr_to_ptr.rs:39:29 | LL | let _: *const f32 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + let _: *const f32 = ptr.cast::(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:35:27 + --> tests/ui/transmute_ptr_to_ptr.rs:42:27 | LL | let _: *mut f32 = transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^ @@ -25,37 +25,37 @@ LL + let _: *mut f32 = mut_ptr.cast::(); | error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:39:23 + --> tests/ui/transmute_ptr_to_ptr.rs:46:23 | LL | let _: &f32 = transmute(&1u32); | ^^^^^^^^^^^^^^^^ help: try: `&*(&1u32 as *const u32 as *const f32)` error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:42:23 + --> tests/ui/transmute_ptr_to_ptr.rs:49:23 | LL | let _: &f32 = transmute(&1f64); | ^^^^^^^^^^^^^^^^ help: try: `&*(&1f64 as *const f64 as *const f32)` error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:47:27 + --> tests/ui/transmute_ptr_to_ptr.rs:54:27 | LL | let _: &mut f32 = transmute(&mut 1u32); | ^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)` error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:50:37 + --> tests/ui/transmute_ptr_to_ptr.rs:57:37 | LL | let _: &GenericParam = transmute(&GenericParam { t: 1u32 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam as *const GenericParam)` error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:54:27 + --> tests/ui/transmute_ptr_to_ptr.rs:61:27 | LL | let u8_ref: &u8 = transmute(u64_ref); | ^^^^^^^^^^^^^^^^^^ help: try: `&*(u64_ref as *const u64 as *const u8)` error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:57:29 + --> tests/ui/transmute_ptr_to_ptr.rs:64:29 | LL | let _: *const u32 = transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^ @@ -67,7 +67,7 @@ LL + let _: *const u32 = mut_ptr.cast_const(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:60:27 + --> tests/ui/transmute_ptr_to_ptr.rs:67:27 | LL | let _: *mut u32 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -79,7 +79,43 @@ LL + let _: *mut u32 = ptr.cast_mut(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:72:14 + --> tests/ui/transmute_ptr_to_ptr.rs:81:29 + | +LL | let _: *const f32 = transmute(Ptr(ptr)); + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `pointer::cast` instead + | +LL - let _: *const f32 = transmute(Ptr(ptr)); +LL + let _: *const f32 = Ptr(ptr).0.cast::(); + | + +error: transmute from a pointer to a pointer + --> tests/ui/transmute_ptr_to_ptr.rs:83:29 + | +LL | let _: *const f32 = transmute(PtrNamed { ptr }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `pointer::cast` instead + | +LL - let _: *const f32 = transmute(PtrNamed { ptr }); +LL + let _: *const f32 = PtrNamed { ptr }.ptr.cast::(); + | + +error: transmute from a pointer to a pointer + --> tests/ui/transmute_ptr_to_ptr.rs:85:27 + | +LL | let _: *mut u32 = transmute(Ptr(ptr)); + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `pointer::cast_mut` instead + | +LL - let _: *mut u32 = transmute(Ptr(ptr)); +LL + let _: *mut u32 = Ptr(ptr).0.cast_mut(); + | + +error: transmute from a pointer to a pointer + --> tests/ui/transmute_ptr_to_ptr.rs:91:14 | LL | unsafe { transmute(v) } | ^^^^^^^^^^^^ @@ -91,7 +127,7 @@ LL + unsafe { v as *const &() } | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:87:28 + --> tests/ui/transmute_ptr_to_ptr.rs:108:28 | LL | let _: *const i8 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -103,7 +139,19 @@ LL + let _: *const i8 = ptr as *const i8; | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:95:28 + --> tests/ui/transmute_ptr_to_ptr.rs:110:28 + | +LL | let _: *const i8 = transmute(Ptr8(ptr)); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use an `as` cast instead + | +LL - let _: *const i8 = transmute(Ptr8(ptr)); +LL + let _: *const i8 = Ptr8(ptr).0 as *const i8; + | + +error: transmute from a pointer to a pointer + --> tests/ui/transmute_ptr_to_ptr.rs:118:28 | LL | let _: *const i8 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -115,7 +163,7 @@ LL + let _: *const i8 = ptr.cast::(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:103:26 + --> tests/ui/transmute_ptr_to_ptr.rs:126:26 | LL | let _: *mut u8 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -127,7 +175,7 @@ LL + let _: *mut u8 = ptr as *mut u8; | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:105:28 + --> tests/ui/transmute_ptr_to_ptr.rs:128:28 | LL | let _: *const u8 = transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^ @@ -139,7 +187,7 @@ LL + let _: *const u8 = mut_ptr as *const u8; | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:113:26 + --> tests/ui/transmute_ptr_to_ptr.rs:136:26 | LL | let _: *mut u8 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -151,7 +199,7 @@ LL + let _: *mut u8 = ptr.cast_mut(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:115:28 + --> tests/ui/transmute_ptr_to_ptr.rs:138:28 | LL | let _: *const u8 = transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^ @@ -162,5 +210,5 @@ LL - let _: *const u8 = transmute(mut_ptr); LL + let _: *const u8 = mut_ptr.cast_const(); | -error: aborting due to 16 previous errors +error: aborting due to 20 previous errors From 7de190a64be614acbc7a1a085afc2438faa8db64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Mon, 1 Dec 2025 19:40:50 +0100 Subject: [PATCH 177/585] `io::Error::downcast`: avoid reallocation in case of failure --- library/std/src/io/error.rs | 24 +++++++++++----------- library/std/src/io/error/repr_bitpacked.rs | 9 -------- library/std/src/io/error/repr_unpacked.rs | 3 --- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 21e82d43a800..0167be4d514c 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -950,19 +950,19 @@ pub fn downcast(self) -> result::Result where E: error::Error + Send + Sync + 'static, { - match self.repr.into_data() { - ErrorData::Custom(b) if b.error.is::() => { - let res = (*b).error.downcast::(); - - // downcast is a really trivial and is marked as inline, so - // it's likely be inlined here. - // - // And the compiler should be able to eliminate the branch - // that produces `Err` here since b.error.is::() - // returns true. - Ok(*res.unwrap()) + if let ErrorData::Custom(c) = self.repr.data() + && c.error.is::() + { + if let ErrorData::Custom(b) = self.repr.into_data() + && let Ok(err) = b.error.downcast::() + { + Ok(*err) + } else { + // Safety: We have just checked that the condition is true + unsafe { crate::hint::unreachable_unchecked() } } - repr_data => Err(Self { repr: Repr::new(repr_data) }), + } else { + Err(self) } } diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 716da37168d0..7353816a8171 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -133,15 +133,6 @@ unsafe impl Send for Repr {} unsafe impl Sync for Repr {} impl Repr { - pub(super) fn new(dat: ErrorData>) -> Self { - match dat { - ErrorData::Os(code) => Self::new_os(code), - ErrorData::Simple(kind) => Self::new_simple(kind), - ErrorData::SimpleMessage(simple_message) => Self::new_simple_message(simple_message), - ErrorData::Custom(b) => Self::new_custom(b), - } - } - pub(super) fn new_custom(b: Box) -> Self { let p = Box::into_raw(b).cast::(); // Should only be possible if an allocator handed out a pointer with diff --git a/library/std/src/io/error/repr_unpacked.rs b/library/std/src/io/error/repr_unpacked.rs index dc8a95577c95..b3e7b5f024ea 100644 --- a/library/std/src/io/error/repr_unpacked.rs +++ b/library/std/src/io/error/repr_unpacked.rs @@ -10,9 +10,6 @@ impl Repr { #[inline] - pub(super) fn new(dat: ErrorData>) -> Self { - Self(dat) - } pub(super) fn new_custom(b: Box) -> Self { Self(Inner::Custom(b)) } From 62e0a843c0453233c0ebdbe756939ab7511c1a9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 1 Dec 2025 19:44:21 +0100 Subject: [PATCH 178/585] also introduce Peekable::next_if_map_mut next to next_if_map --- library/core/src/iter/adapters/peekable.rs | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index a55de75d56c6..ee40d2b74c64 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -331,6 +331,8 @@ pub fn next_if_eq(&mut self, expected: &T) -> Option /// If the closure panics, the next value will always be consumed and dropped /// even if the panic is caught, because the closure never returned an `Err` value to put back. /// + /// See also: [`next_if_map_mut`](Self::next_if_map_mut). + /// /// # Examples /// /// Parse the leading decimal number from an iterator of characters. @@ -419,6 +421,44 @@ pub fn next_if_map(&mut self, f: impl FnOnce(I::Item) -> Result) self.peeked = Some(unpeek); None } + + /// Gives a mutable reference to the next value of the iterator and applies a function `f` to it, + /// returning the result and advancing the iterator if `f` returns `Some`. + /// + /// Otherwise, if `f` returns `None`, the next value is kept for the next iteration. + /// + /// If `f` panics, the item that is consumed from the iterator as if `Some` was returned from `f`. + /// The value will be dropped. + /// + /// This is similar to [`next_if_map`](Self::next_if_map), except ownership of the item is not given to `f`. + /// This can be preferable if `f` would copy the item anyway. + /// + /// # Examples + /// + /// Parse the leading decimal number from an iterator of characters. + /// ``` + /// #![feature(peekable_next_if_map)] + /// let mut iter = "125 GOTO 10".chars().peekable(); + /// let mut line_num = 0_u32; + /// while let Some(digit) = iter.next_if_map_mut(|c| c.to_digit(10)) { + /// line_num = line_num * 10 + digit; + /// } + /// assert_eq!(line_num, 125); + /// assert_eq!(iter.collect::(), " GOTO 10"); + /// ``` + #[unstable(feature = "peekable_next_if_map", issue = "143702")] + pub fn next_if_map_mut(&mut self, f: impl FnOnce(&mut I::Item) -> Option) -> Option { + let unpeek = if let Some(mut item) = self.next() { + match f(&mut item) { + Some(result) => return Some(result), + None => Some(item), + } + } else { + None + }; + self.peeked = Some(unpeek); + None + } } #[unstable(feature = "trusted_len", issue = "37572")] From d60f7800ef5fb3996a8c74f57b9932ab913448af Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 23 Nov 2025 11:21:06 -0300 Subject: [PATCH 179/585] This statement is misleading --- library/core/src/mem/mod.rs | 4 +--- tests/ui/thir-print/offset_of.stdout | 18 +++++++++--------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index f4fcc9b1f366..ad5fda0cfe4d 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -898,8 +898,6 @@ pub const fn replace(dest: &mut T, src: T) -> T { /// Disposes of a value. /// -/// This does so by calling the argument's implementation of [`Drop`][drop]. -/// /// This effectively does nothing for types which implement `Copy`, e.g. /// integers. Such values are copied and _then_ moved into the function, so the /// value persists after this function call. @@ -910,7 +908,7 @@ pub const fn replace(dest: &mut T, src: T) -> T { /// pub fn drop(_x: T) {} /// ``` /// -/// Because `_x` is moved into the function, it is automatically dropped before +/// Because `_x` is moved into the function, it is automatically [dropped][drop] before /// the function returns. /// /// [drop]: Drop diff --git a/tests/ui/thir-print/offset_of.stdout b/tests/ui/thir-print/offset_of.stdout index e1b6ea9349b4..846817f47528 100644 --- a/tests/ui/thir-print/offset_of.stdout +++ b/tests/ui/thir-print/offset_of.stdout @@ -68,7 +68,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::concrete).10)) - span: $DIR/offset_of.rs:37:5: 1435:57 (#0) + span: $DIR/offset_of.rs:37:5: 1433:57 (#0) } } Stmt { @@ -117,7 +117,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::concrete).20)) - span: $DIR/offset_of.rs:38:5: 1435:57 (#0) + span: $DIR/offset_of.rs:38:5: 1433:57 (#0) } } Stmt { @@ -166,7 +166,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::concrete).30)) - span: $DIR/offset_of.rs:39:5: 1435:57 (#0) + span: $DIR/offset_of.rs:39:5: 1433:57 (#0) } } Stmt { @@ -215,7 +215,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::concrete).40)) - span: $DIR/offset_of.rs:40:5: 1435:57 (#0) + span: $DIR/offset_of.rs:40:5: 1433:57 (#0) } } Stmt { @@ -264,7 +264,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::concrete).50)) - span: $DIR/offset_of.rs:41:5: 1435:57 (#0) + span: $DIR/offset_of.rs:41:5: 1433:57 (#0) } } ] @@ -864,7 +864,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::generic).12)) - span: $DIR/offset_of.rs:45:5: 1435:57 (#0) + span: $DIR/offset_of.rs:45:5: 1433:57 (#0) } } Stmt { @@ -913,7 +913,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::generic).24)) - span: $DIR/offset_of.rs:46:5: 1435:57 (#0) + span: $DIR/offset_of.rs:46:5: 1433:57 (#0) } } Stmt { @@ -962,7 +962,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::generic).36)) - span: $DIR/offset_of.rs:47:5: 1435:57 (#0) + span: $DIR/offset_of.rs:47:5: 1433:57 (#0) } } Stmt { @@ -1011,7 +1011,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::generic).48)) - span: $DIR/offset_of.rs:48:5: 1435:57 (#0) + span: $DIR/offset_of.rs:48:5: 1433:57 (#0) } } ] From 18af84b1380cd5af07d5fa09c0cad19d5ef55243 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Dec 2025 22:32:36 +0100 Subject: [PATCH 180/585] debuginfo/macro-stepping test: extend comments --- tests/debuginfo/macro-stepping.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/debuginfo/macro-stepping.rs b/tests/debuginfo/macro-stepping.rs index bdeadf8a5c05..0dff383be825 100644 --- a/tests/debuginfo/macro-stepping.rs +++ b/tests/debuginfo/macro-stepping.rs @@ -1,3 +1,8 @@ +//! This tests that `next` skips over macro invocations correctly. +//! The `#locN` markers have no meaning for compiletest, we include them just +//! so that the debugger prints them when printing the current source location, +//! and we can match on them for testing purposes. + //@ ignore-android //@ min-lldb-version: 1800 //@ min-gdb-version: 13.0 @@ -68,6 +73,7 @@ //@ lldb-command:next //@ lldb-command:frame select //@ lldb-check:[...] #loc5 [...] +// FIXME: what about loc6? //@ lldb-command:continue //@ lldb-command:step From 5c282908be9642b53137af05734f14ed03c0afae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Mon, 1 Dec 2025 22:46:13 +0100 Subject: [PATCH 181/585] Add myself (mati865) to the review rotation I've been procrastinating long enough. --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 325a62235c71..dec156cc9918 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1430,6 +1430,7 @@ compiler = [ "@JonathanBrouwer", "@lcnr", "@madsmtm", + "@mati865", "@Nadrieril", "@nnethercote", "@oli-obk", From e4b8c5a6a5d52532e8bb23196f1b0e3d1b9f90e4 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Mon, 1 Dec 2025 22:27:51 +0000 Subject: [PATCH 182/585] fix: `useless_conversion` wrongly unmangled macros --- clippy_lints/src/useless_conversion.rs | 5 ++++- tests/ui/useless_conversion.fixed | 11 +++++++++++ tests/ui/useless_conversion.rs | 11 +++++++++++ tests/ui/useless_conversion.stderr | 8 +++++++- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 0cf5b9431a34..c06313d1a4c4 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -354,7 +354,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { return; } - let sugg = snippet(cx, recv.span, "").into_owned(); + let mut applicability = Applicability::MachineApplicable; + let sugg = snippet_with_context(cx, recv.span, e.span.ctxt(), "", &mut applicability) + .0 + .into_owned(); span_lint_and_sugg( cx, USELESS_CONVERSION, diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index 9de7d2c67149..adf5e58d9a1a 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -442,3 +442,14 @@ fn issue14739() { let _ = R.map(|_x| 0); //~^ useless_conversion } + +fn issue16165() { + macro_rules! mac { + (iter $e:expr) => { + $e.iter() + }; + } + + for _ in mac!(iter [1, 2]) {} + //~^ useless_conversion +} diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index 38cd1175aa48..d95fe49e2e2b 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -442,3 +442,14 @@ fn issue14739() { let _ = R.into_iter().map(|_x| 0); //~^ useless_conversion } + +fn issue16165() { + macro_rules! mac { + (iter $e:expr) => { + $e.iter() + }; + } + + for _ in mac!(iter [1, 2]).into_iter() {} + //~^ useless_conversion +} diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 3bfaf1411c2c..052c664f6f2e 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -389,5 +389,11 @@ error: useless conversion to the same type: `std::ops::Range` LL | let _ = R.into_iter().map(|_x| 0); | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` -error: aborting due to 43 previous errors +error: useless conversion to the same type: `std::slice::Iter<'_, i32>` + --> tests/ui/useless_conversion.rs:453:14 + | +LL | for _ in mac!(iter [1, 2]).into_iter() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `mac!(iter [1, 2])` + +error: aborting due to 44 previous errors From b2b059c20b92aef06a94449d3a67d22837d3d430 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Mon, 1 Dec 2025 07:21:47 -0700 Subject: [PATCH 183/585] chore: Update annotate-snippets to 0.12.10 --- Cargo.lock | 6 ++-- compiler/rustc_errors/Cargo.toml | 2 +- .../clippy/tests/ui/manual_async_fn.stderr | 36 +++++++++++++++++++ .../clippy/tests/ui/map_unwrap_or.stderr | 4 +++ .../clippy/tests/ui/match_same_arms.stderr | 1 - .../ui/non_canonical_partial_ord_impl.stderr | 2 ++ .../clippy/tests/ui/print_literal.stderr | 1 + .../argument-suggestions/issue-112507.stderr | 3 ++ .../invalid-nan-comparison-suggestion.stderr | 3 ++ .../unused/closure-body-issue-136741.stderr | 1 + tests/ui/privacy/suggest-box-new.stderr | 3 ++ tests/ui/suggestions/issue-109396.stderr | 5 +++ tests/ui/suggestions/issue-109854.stderr | 4 +++ .../suggestions/multi-suggestion.ascii.stderr | 3 ++ .../multi-suggestion.unicode.stderr | 3 ++ .../suggestions/suggest-remove-refs-3.stderr | 1 + 16 files changed, 73 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d8d5111583e..2cc2e094e9f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,9 +74,9 @@ dependencies = [ [[package]] name = "annotate-snippets" -version = "0.12.9" +version = "0.12.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44baf24dd94e781f74dfe67ffee75a09a57971ddf0f615a178b4f6d404b48ff" +checksum = "15580ece6ea97cbf832d60ba19c021113469480852c6a2a6beb0db28f097bf1f" dependencies = [ "anstyle", "memchr", @@ -3838,7 +3838,7 @@ dependencies = [ name = "rustc_errors" version = "0.0.0" dependencies = [ - "annotate-snippets 0.12.9", + "annotate-snippets 0.12.10", "anstream", "anstyle", "derive_setters", diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index a513a0345c3b..6c5a1740a9a6 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -annotate-snippets = { version = "0.12.9", features = ["simd"] } +annotate-snippets = { version = "0.12.10", features = ["simd"] } anstream = "0.6.20" anstyle = "1.0.13" derive_setters = "0.1.6" diff --git a/src/tools/clippy/tests/ui/manual_async_fn.stderr b/src/tools/clippy/tests/ui/manual_async_fn.stderr index 54a9b1d40a11..fe6a20589b96 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.stderr +++ b/src/tools/clippy/tests/ui/manual_async_fn.stderr @@ -9,6 +9,9 @@ LL | fn fut() -> impl Future { help: make the function `async` and return the output of the future directly | LL - fn fut() -> impl Future { +LL - +LL - async { 42 } +LL - } LL + async fn fut() -> i32 { 42 } | @@ -21,6 +24,9 @@ LL | fn fut2() ->impl Future { help: make the function `async` and return the output of the future directly | LL - fn fut2() ->impl Future { +LL - +LL - async { 42 } +LL - } LL + async fn fut2() -> i32 { 42 } | @@ -33,6 +39,9 @@ LL | fn fut3()-> impl Future { help: make the function `async` and return the output of the future directly | LL - fn fut3()-> impl Future { +LL - +LL - async { 42 } +LL - } LL + async fn fut3() -> i32 { 42 } | @@ -45,6 +54,9 @@ LL | fn empty_fut() -> impl Future { help: make the function `async` and return the output of the future directly | LL - fn empty_fut() -> impl Future { +LL - +LL - async {} +LL - } LL + async fn empty_fut() {} | @@ -57,6 +69,9 @@ LL | fn empty_fut2() ->impl Future { help: make the function `async` and return the output of the future directly | LL - fn empty_fut2() ->impl Future { +LL - +LL - async {} +LL - } LL + async fn empty_fut2() {} | @@ -69,6 +84,9 @@ LL | fn empty_fut3()-> impl Future { help: make the function `async` and return the output of the future directly | LL - fn empty_fut3()-> impl Future { +LL - +LL - async {} +LL - } LL + async fn empty_fut3() {} | @@ -81,6 +99,9 @@ LL | fn core_fut() -> impl core::future::Future { help: make the function `async` and return the output of the future directly | LL - fn core_fut() -> impl core::future::Future { +LL - +LL - async move { 42 } +LL - } LL + async fn core_fut() -> i32 { 42 } | @@ -116,6 +137,9 @@ LL | fn elided(_: &i32) -> impl Future + '_ { help: make the function `async` and return the output of the future directly | LL - fn elided(_: &i32) -> impl Future + '_ { +LL - +LL - async { 42 } +LL - } LL + async fn elided(_: &i32) -> i32 { 42 } | @@ -128,6 +152,9 @@ LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + help: make the function `async` and return the output of the future directly | LL - fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { +LL - +LL - async { 42 } +LL - } LL + async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { 42 } | @@ -140,6 +167,9 @@ LL | pub fn issue_10450() -> impl Future { help: make the function `async` and return the output of the future directly | LL - pub fn issue_10450() -> impl Future { +LL - +LL - async { 42 } +LL - } LL + pub async fn issue_10450() -> i32 { 42 } | @@ -152,6 +182,9 @@ LL | pub(crate) fn issue_10450_2() -> impl Future { help: make the function `async` and return the output of the future directly | LL - pub(crate) fn issue_10450_2() -> impl Future { +LL - +LL - async { 42 } +LL - } LL + pub(crate) async fn issue_10450_2() -> i32 { 42 } | @@ -164,6 +197,9 @@ LL | pub(self) fn issue_10450_3() -> impl Future { help: make the function `async` and return the output of the future directly | LL - pub(self) fn issue_10450_3() -> impl Future { +LL - +LL - async { 42 } +LL - } LL + pub(self) async fn issue_10450_3() -> i32 { 42 } | diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.stderr b/src/tools/clippy/tests/ui/map_unwrap_or.stderr index 0b6c9b7fcf19..b0b02f3f8d6b 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or.stderr +++ b/src/tools/clippy/tests/ui/map_unwrap_or.stderr @@ -12,6 +12,9 @@ LL | | .unwrap_or(0); help: use `map_or(, )` instead | LL - let _ = opt.map(|x| x + 1) +LL - +LL - // Should lint even though this call is on a separate line. +LL - .unwrap_or(0); LL + let _ = opt.map_or(0, |x| x + 1); | @@ -98,6 +101,7 @@ LL | | .unwrap_or(None); help: use `and_then()` instead | LL - .map(|x| Some(x + 1)) +LL - .unwrap_or(None); LL + .and_then(|x| Some(x + 1)); | diff --git a/src/tools/clippy/tests/ui/match_same_arms.stderr b/src/tools/clippy/tests/ui/match_same_arms.stderr index 8aa60f835766..bd0b7b2871ec 100644 --- a/src/tools/clippy/tests/ui/match_same_arms.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms.stderr @@ -30,7 +30,6 @@ help: otherwise remove the non-wildcard arms | LL - 2 => 'b', LL - 3 => 'b', -LL + _ => 'b', | error: these match arms have identical bodies diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr index 8e55603dd9da..a134df17691e 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr @@ -28,6 +28,8 @@ LL | | } help: change this to | LL - fn partial_cmp(&self, _: &Self) -> Option { +LL - todo!(); +LL - } LL + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } | diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr index c136f52800f6..229f3bf269d3 100644 --- a/src/tools/clippy/tests/ui/print_literal.stderr +++ b/src/tools/clippy/tests/ui/print_literal.stderr @@ -310,6 +310,7 @@ LL | "name", 5, "x", 0.01 help: try | LL - "Hello {}: {2} is {3:.*} (which {3} with {1} places)", +LL - "name", 5, "x", 0.01 LL + "Hello name: x is {1:.*} (which {1} with {0} places)", 5, 0.01 | diff --git a/tests/ui/argument-suggestions/issue-112507.stderr b/tests/ui/argument-suggestions/issue-112507.stderr index e2ea9af7dc2c..7c692b67a2d8 100644 --- a/tests/ui/argument-suggestions/issue-112507.stderr +++ b/tests/ui/argument-suggestions/issue-112507.stderr @@ -20,6 +20,9 @@ help: remove the extra arguments | LL - 0, LL - None, +LL - None, +LL - 0, +LL - ); LL + None); | diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr b/tests/ui/lint/invalid-nan-comparison-suggestion.stderr index 9d07d3f92402..f9b1428de464 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr +++ b/tests/ui/lint/invalid-nan-comparison-suggestion.stderr @@ -131,6 +131,9 @@ LL | | }; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - b != { +LL - +LL - &f32::NAN +LL - }; LL + !b.is_nan(); | diff --git a/tests/ui/lint/unused/closure-body-issue-136741.stderr b/tests/ui/lint/unused/closure-body-issue-136741.stderr index 2ea872c08c7a..14b4dc975698 100644 --- a/tests/ui/lint/unused/closure-body-issue-136741.stderr +++ b/tests/ui/lint/unused/closure-body-issue-136741.stderr @@ -43,6 +43,7 @@ help: remove these parentheses | LL - let _ = (0..).find(|n| ( LL - n % 2 == 0 +LL - )); LL + let _ = (0..).find(|n| n % 2 == 0); | diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr index 566f31fc305e..e3a7e5f62017 100644 --- a/tests/ui/privacy/suggest-box-new.stderr +++ b/tests/ui/privacy/suggest-box-new.stderr @@ -67,6 +67,9 @@ LL + wtf: Some(Box::new_in(_, _)), help: consider using the `Default` trait | LL - wtf: Some(Box(U { +LL - wtf: None, +LL - x: (), +LL - })), LL + wtf: Some(::default()), | diff --git a/tests/ui/suggestions/issue-109396.stderr b/tests/ui/suggestions/issue-109396.stderr index 5419e8240c59..5fac07a9a096 100644 --- a/tests/ui/suggestions/issue-109396.stderr +++ b/tests/ui/suggestions/issue-109396.stderr @@ -25,6 +25,11 @@ note: function defined here help: remove the extra arguments | LL - file.as_raw_fd(), +LL - +LL - 0, +LL - 0, +LL - 0, +LL - ); LL + ); | diff --git a/tests/ui/suggestions/issue-109854.stderr b/tests/ui/suggestions/issue-109854.stderr index d9cbbe37d461..89d5b4c0178c 100644 --- a/tests/ui/suggestions/issue-109854.stderr +++ b/tests/ui/suggestions/issue-109854.stderr @@ -23,6 +23,10 @@ note: associated function defined here help: remove the extra arguments | LL - generate_setter, +LL - r#" +LL - pub(crate) struct Person {} +LL - "#, +LL - r#""#, LL + /* usize */, | diff --git a/tests/ui/suggestions/multi-suggestion.ascii.stderr b/tests/ui/suggestions/multi-suggestion.ascii.stderr index bb14eb2fb572..c2ae19b1ae9a 100644 --- a/tests/ui/suggestions/multi-suggestion.ascii.stderr +++ b/tests/ui/suggestions/multi-suggestion.ascii.stderr @@ -67,6 +67,9 @@ LL + wtf: Some(Box::new_in(_, _)), help: consider using the `Default` trait | LL - wtf: Some(Box(U { +LL - wtf: None, +LL - x: (), +LL - })), LL + wtf: Some(::default()), | diff --git a/tests/ui/suggestions/multi-suggestion.unicode.stderr b/tests/ui/suggestions/multi-suggestion.unicode.stderr index e7f9e7153d19..fc187cac91d1 100644 --- a/tests/ui/suggestions/multi-suggestion.unicode.stderr +++ b/tests/ui/suggestions/multi-suggestion.unicode.stderr @@ -67,6 +67,9 @@ LL + wtf: Some(Box::new_in(_, _)), help: consider using the `Default` trait ╭╴ LL - wtf: Some(Box(U { +LL - wtf: None, +LL - x: (), +LL - })), LL + wtf: Some(::default()), ╰╴ diff --git a/tests/ui/suggestions/suggest-remove-refs-3.stderr b/tests/ui/suggestions/suggest-remove-refs-3.stderr index a3e142563ff8..cb01468798ff 100644 --- a/tests/ui/suggestions/suggest-remove-refs-3.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-3.stderr @@ -13,6 +13,7 @@ LL | | .enumerate() { help: consider removing 5 leading `&`-references | LL - for (i, _) in & & & +LL - & &v LL + for (i, _) in v | From b07013c4fdfc0bb68044e4f39ab66d4f53e40dd9 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Mon, 1 Dec 2025 07:21:47 -0700 Subject: [PATCH 184/585] chore: Update annotate-snippets to 0.12.10 --- tests/ui/manual_async_fn.stderr | 36 +++++++++++++++++++ tests/ui/map_unwrap_or.stderr | 4 +++ tests/ui/match_same_arms.stderr | 1 - .../ui/non_canonical_partial_ord_impl.stderr | 2 ++ tests/ui/print_literal.stderr | 1 + 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/tests/ui/manual_async_fn.stderr b/tests/ui/manual_async_fn.stderr index 54a9b1d40a11..fe6a20589b96 100644 --- a/tests/ui/manual_async_fn.stderr +++ b/tests/ui/manual_async_fn.stderr @@ -9,6 +9,9 @@ LL | fn fut() -> impl Future { help: make the function `async` and return the output of the future directly | LL - fn fut() -> impl Future { +LL - +LL - async { 42 } +LL - } LL + async fn fut() -> i32 { 42 } | @@ -21,6 +24,9 @@ LL | fn fut2() ->impl Future { help: make the function `async` and return the output of the future directly | LL - fn fut2() ->impl Future { +LL - +LL - async { 42 } +LL - } LL + async fn fut2() -> i32 { 42 } | @@ -33,6 +39,9 @@ LL | fn fut3()-> impl Future { help: make the function `async` and return the output of the future directly | LL - fn fut3()-> impl Future { +LL - +LL - async { 42 } +LL - } LL + async fn fut3() -> i32 { 42 } | @@ -45,6 +54,9 @@ LL | fn empty_fut() -> impl Future { help: make the function `async` and return the output of the future directly | LL - fn empty_fut() -> impl Future { +LL - +LL - async {} +LL - } LL + async fn empty_fut() {} | @@ -57,6 +69,9 @@ LL | fn empty_fut2() ->impl Future { help: make the function `async` and return the output of the future directly | LL - fn empty_fut2() ->impl Future { +LL - +LL - async {} +LL - } LL + async fn empty_fut2() {} | @@ -69,6 +84,9 @@ LL | fn empty_fut3()-> impl Future { help: make the function `async` and return the output of the future directly | LL - fn empty_fut3()-> impl Future { +LL - +LL - async {} +LL - } LL + async fn empty_fut3() {} | @@ -81,6 +99,9 @@ LL | fn core_fut() -> impl core::future::Future { help: make the function `async` and return the output of the future directly | LL - fn core_fut() -> impl core::future::Future { +LL - +LL - async move { 42 } +LL - } LL + async fn core_fut() -> i32 { 42 } | @@ -116,6 +137,9 @@ LL | fn elided(_: &i32) -> impl Future + '_ { help: make the function `async` and return the output of the future directly | LL - fn elided(_: &i32) -> impl Future + '_ { +LL - +LL - async { 42 } +LL - } LL + async fn elided(_: &i32) -> i32 { 42 } | @@ -128,6 +152,9 @@ LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + help: make the function `async` and return the output of the future directly | LL - fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { +LL - +LL - async { 42 } +LL - } LL + async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { 42 } | @@ -140,6 +167,9 @@ LL | pub fn issue_10450() -> impl Future { help: make the function `async` and return the output of the future directly | LL - pub fn issue_10450() -> impl Future { +LL - +LL - async { 42 } +LL - } LL + pub async fn issue_10450() -> i32 { 42 } | @@ -152,6 +182,9 @@ LL | pub(crate) fn issue_10450_2() -> impl Future { help: make the function `async` and return the output of the future directly | LL - pub(crate) fn issue_10450_2() -> impl Future { +LL - +LL - async { 42 } +LL - } LL + pub(crate) async fn issue_10450_2() -> i32 { 42 } | @@ -164,6 +197,9 @@ LL | pub(self) fn issue_10450_3() -> impl Future { help: make the function `async` and return the output of the future directly | LL - pub(self) fn issue_10450_3() -> impl Future { +LL - +LL - async { 42 } +LL - } LL + pub(self) async fn issue_10450_3() -> i32 { 42 } | diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index 0b6c9b7fcf19..b0b02f3f8d6b 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -12,6 +12,9 @@ LL | | .unwrap_or(0); help: use `map_or(, )` instead | LL - let _ = opt.map(|x| x + 1) +LL - +LL - // Should lint even though this call is on a separate line. +LL - .unwrap_or(0); LL + let _ = opt.map_or(0, |x| x + 1); | @@ -98,6 +101,7 @@ LL | | .unwrap_or(None); help: use `and_then()` instead | LL - .map(|x| Some(x + 1)) +LL - .unwrap_or(None); LL + .and_then(|x| Some(x + 1)); | diff --git a/tests/ui/match_same_arms.stderr b/tests/ui/match_same_arms.stderr index 8aa60f835766..bd0b7b2871ec 100644 --- a/tests/ui/match_same_arms.stderr +++ b/tests/ui/match_same_arms.stderr @@ -30,7 +30,6 @@ help: otherwise remove the non-wildcard arms | LL - 2 => 'b', LL - 3 => 'b', -LL + _ => 'b', | error: these match arms have identical bodies diff --git a/tests/ui/non_canonical_partial_ord_impl.stderr b/tests/ui/non_canonical_partial_ord_impl.stderr index 8e55603dd9da..a134df17691e 100644 --- a/tests/ui/non_canonical_partial_ord_impl.stderr +++ b/tests/ui/non_canonical_partial_ord_impl.stderr @@ -28,6 +28,8 @@ LL | | } help: change this to | LL - fn partial_cmp(&self, _: &Self) -> Option { +LL - todo!(); +LL - } LL + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } | diff --git a/tests/ui/print_literal.stderr b/tests/ui/print_literal.stderr index c136f52800f6..229f3bf269d3 100644 --- a/tests/ui/print_literal.stderr +++ b/tests/ui/print_literal.stderr @@ -310,6 +310,7 @@ LL | "name", 5, "x", 0.01 help: try | LL - "Hello {}: {2} is {3:.*} (which {3} with {1} places)", +LL - "name", 5, "x", 0.01 LL + "Hello name: x is {1:.*} (which {1} with {0} places)", 5, 0.01 | From ab9d0e0ab6d063ddcc0495a076f712bca5a725f8 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 2 Dec 2025 11:13:37 +0900 Subject: [PATCH 185/585] moved tests updated `tests/ui/README.md`and `src/tools/tidy/src/issues.txt` --- src/tools/tidy/src/issues.txt | 1 - tests/ui/README.md | 10 ---------- tests/ui/{warnings => entry-point}/hello-world.rs | 0 tests/ui/{for => for-loop-while}/for-c-in-str.rs | 0 tests/ui/{for => for-loop-while}/for-c-in-str.stderr | 0 tests/ui/{for => for-loop-while}/for-else-err.rs | 0 tests/ui/{for => for-loop-while}/for-else-err.stderr | 0 .../{for => for-loop-while}/for-else-let-else-err.rs | 0 .../for-else-let-else-err.stderr | 0 tests/ui/{for => for-loop-while}/for-loop-bogosity.rs | 0 .../{for => for-loop-while}/for-loop-bogosity.stderr | 0 .../for-loop-diagnostic-span.rs} | 0 .../for-loop-diagnostic-span.stderr} | 0 .../for-loop-refutable-pattern-error-message.rs | 0 .../for-loop-refutable-pattern-error-message.stderr | 0 .../ui/{for => for-loop-while}/for-loop-type-error.rs | 0 .../{for => for-loop-while}/for-loop-type-error.stderr | 0 .../for-loop-unconstrained-element-type.rs | 0 .../for-loop-unconstrained-element-type.stderr | 0 .../iter-from-mac-call.rs} | 0 .../iter-from-mac-call.stderr} | 0 .../no-explicit-path.rs} | 0 .../dyn-iterator-deref-in-for-loop.current.stderr} | 0 .../dyn-iterator-deref-in-for-loop.next.stderr} | 0 .../dyn-iterator-deref-in-for-loop.rs} | 0 .../object/trait-object-lifetime-conversion.rs} | 0 26 files changed, 11 deletions(-) rename tests/ui/{warnings => entry-point}/hello-world.rs (100%) rename tests/ui/{for => for-loop-while}/for-c-in-str.rs (100%) rename tests/ui/{for => for-loop-while}/for-c-in-str.stderr (100%) rename tests/ui/{for => for-loop-while}/for-else-err.rs (100%) rename tests/ui/{for => for-loop-while}/for-else-err.stderr (100%) rename tests/ui/{for => for-loop-while}/for-else-let-else-err.rs (100%) rename tests/ui/{for => for-loop-while}/for-else-let-else-err.stderr (100%) rename tests/ui/{for => for-loop-while}/for-loop-bogosity.rs (100%) rename tests/ui/{for => for-loop-while}/for-loop-bogosity.stderr (100%) rename tests/ui/{for/for-expn.rs => for-loop-while/for-loop-diagnostic-span.rs} (100%) rename tests/ui/{for/for-expn.stderr => for-loop-while/for-loop-diagnostic-span.stderr} (100%) rename tests/ui/{for => for-loop-while}/for-loop-refutable-pattern-error-message.rs (100%) rename tests/ui/{for => for-loop-while}/for-loop-refutable-pattern-error-message.stderr (100%) rename tests/ui/{for => for-loop-while}/for-loop-type-error.rs (100%) rename tests/ui/{for => for-loop-while}/for-loop-type-error.stderr (100%) rename tests/ui/{for => for-loop-while}/for-loop-unconstrained-element-type.rs (100%) rename tests/ui/{for => for-loop-while}/for-loop-unconstrained-element-type.stderr (100%) rename tests/ui/{for/iter_from_mac_call.rs => for-loop-while/iter-from-mac-call.rs} (100%) rename tests/ui/{for/iter_from_mac_call.stderr => for-loop-while/iter-from-mac-call.stderr} (100%) rename tests/ui/{warnings/no-explicit-path-issue-122509.rs => resolve/no-explicit-path.rs} (100%) rename tests/ui/{for/issue-20605.current.stderr => traits/dyn-iterator-deref-in-for-loop.current.stderr} (100%) rename tests/ui/{for/issue-20605.next.stderr => traits/dyn-iterator-deref-in-for-loop.next.stderr} (100%) rename tests/ui/{for/issue-20605.rs => traits/dyn-iterator-deref-in-for-loop.rs} (100%) rename tests/ui/{trait-objects/trait-object-lifetime-conversion-47638.rs => traits/object/trait-object-lifetime-conversion.rs} (100%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index a37700f2e853..0f3f2f37ebf2 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1014,7 +1014,6 @@ ui/for-loop-while/issue-1257.rs ui/for-loop-while/issue-2216.rs ui/for-loop-while/issue-51345.rs ui/for-loop-while/issue-69841.rs -ui/for/issue-20605.rs ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs ui/foreign/issue-91370-foreign-fn-block-impl.rs ui/foreign/issue-99276-same-type-lifetimes.rs diff --git a/tests/ui/README.md b/tests/ui/README.md index 11003bbef992..c175b2e293b1 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -585,12 +585,6 @@ Exercises the `format!` macro. A broad category of tests on functions. -## `tests/ui/for/`: `for` keyword - -Tests on the `for` keyword and some of its associated errors, such as attempting to write the faulty pattern `for _ in 0..1 {} else {}`. - -**FIXME**: Should be merged with `ui/for-loop-while`. - ## `tests/ui/force-inlining/`: `#[rustc_force_inline]` Tests for `#[rustc_force_inline]`, which will force a function to always be labelled as inline by the compiler (it will be inserted at the point of its call instead of being used as a normal function call.) If the compiler is unable to inline the function, an error will be reported. See . @@ -1545,10 +1539,6 @@ Tests on `enum` variants. **FIXME**: Contains a single test described as "Check that rustc accepts various version info flags.", should be rehomed. -## `tests/ui/warnings/` - -**FIXME**: Contains a single test on non-explicit paths (`::one()`). Should be rehomed probably to `tests/ui/resolve/`. - ## `tests/ui/wasm/` These tests target the `wasm32` architecture specifically. They are usually regression tests for WASM-specific bugs which were observed in the past. diff --git a/tests/ui/warnings/hello-world.rs b/tests/ui/entry-point/hello-world.rs similarity index 100% rename from tests/ui/warnings/hello-world.rs rename to tests/ui/entry-point/hello-world.rs diff --git a/tests/ui/for/for-c-in-str.rs b/tests/ui/for-loop-while/for-c-in-str.rs similarity index 100% rename from tests/ui/for/for-c-in-str.rs rename to tests/ui/for-loop-while/for-c-in-str.rs diff --git a/tests/ui/for/for-c-in-str.stderr b/tests/ui/for-loop-while/for-c-in-str.stderr similarity index 100% rename from tests/ui/for/for-c-in-str.stderr rename to tests/ui/for-loop-while/for-c-in-str.stderr diff --git a/tests/ui/for/for-else-err.rs b/tests/ui/for-loop-while/for-else-err.rs similarity index 100% rename from tests/ui/for/for-else-err.rs rename to tests/ui/for-loop-while/for-else-err.rs diff --git a/tests/ui/for/for-else-err.stderr b/tests/ui/for-loop-while/for-else-err.stderr similarity index 100% rename from tests/ui/for/for-else-err.stderr rename to tests/ui/for-loop-while/for-else-err.stderr diff --git a/tests/ui/for/for-else-let-else-err.rs b/tests/ui/for-loop-while/for-else-let-else-err.rs similarity index 100% rename from tests/ui/for/for-else-let-else-err.rs rename to tests/ui/for-loop-while/for-else-let-else-err.rs diff --git a/tests/ui/for/for-else-let-else-err.stderr b/tests/ui/for-loop-while/for-else-let-else-err.stderr similarity index 100% rename from tests/ui/for/for-else-let-else-err.stderr rename to tests/ui/for-loop-while/for-else-let-else-err.stderr diff --git a/tests/ui/for/for-loop-bogosity.rs b/tests/ui/for-loop-while/for-loop-bogosity.rs similarity index 100% rename from tests/ui/for/for-loop-bogosity.rs rename to tests/ui/for-loop-while/for-loop-bogosity.rs diff --git a/tests/ui/for/for-loop-bogosity.stderr b/tests/ui/for-loop-while/for-loop-bogosity.stderr similarity index 100% rename from tests/ui/for/for-loop-bogosity.stderr rename to tests/ui/for-loop-while/for-loop-bogosity.stderr diff --git a/tests/ui/for/for-expn.rs b/tests/ui/for-loop-while/for-loop-diagnostic-span.rs similarity index 100% rename from tests/ui/for/for-expn.rs rename to tests/ui/for-loop-while/for-loop-diagnostic-span.rs diff --git a/tests/ui/for/for-expn.stderr b/tests/ui/for-loop-while/for-loop-diagnostic-span.stderr similarity index 100% rename from tests/ui/for/for-expn.stderr rename to tests/ui/for-loop-while/for-loop-diagnostic-span.stderr diff --git a/tests/ui/for/for-loop-refutable-pattern-error-message.rs b/tests/ui/for-loop-while/for-loop-refutable-pattern-error-message.rs similarity index 100% rename from tests/ui/for/for-loop-refutable-pattern-error-message.rs rename to tests/ui/for-loop-while/for-loop-refutable-pattern-error-message.rs diff --git a/tests/ui/for/for-loop-refutable-pattern-error-message.stderr b/tests/ui/for-loop-while/for-loop-refutable-pattern-error-message.stderr similarity index 100% rename from tests/ui/for/for-loop-refutable-pattern-error-message.stderr rename to tests/ui/for-loop-while/for-loop-refutable-pattern-error-message.stderr diff --git a/tests/ui/for/for-loop-type-error.rs b/tests/ui/for-loop-while/for-loop-type-error.rs similarity index 100% rename from tests/ui/for/for-loop-type-error.rs rename to tests/ui/for-loop-while/for-loop-type-error.rs diff --git a/tests/ui/for/for-loop-type-error.stderr b/tests/ui/for-loop-while/for-loop-type-error.stderr similarity index 100% rename from tests/ui/for/for-loop-type-error.stderr rename to tests/ui/for-loop-while/for-loop-type-error.stderr diff --git a/tests/ui/for/for-loop-unconstrained-element-type.rs b/tests/ui/for-loop-while/for-loop-unconstrained-element-type.rs similarity index 100% rename from tests/ui/for/for-loop-unconstrained-element-type.rs rename to tests/ui/for-loop-while/for-loop-unconstrained-element-type.rs diff --git a/tests/ui/for/for-loop-unconstrained-element-type.stderr b/tests/ui/for-loop-while/for-loop-unconstrained-element-type.stderr similarity index 100% rename from tests/ui/for/for-loop-unconstrained-element-type.stderr rename to tests/ui/for-loop-while/for-loop-unconstrained-element-type.stderr diff --git a/tests/ui/for/iter_from_mac_call.rs b/tests/ui/for-loop-while/iter-from-mac-call.rs similarity index 100% rename from tests/ui/for/iter_from_mac_call.rs rename to tests/ui/for-loop-while/iter-from-mac-call.rs diff --git a/tests/ui/for/iter_from_mac_call.stderr b/tests/ui/for-loop-while/iter-from-mac-call.stderr similarity index 100% rename from tests/ui/for/iter_from_mac_call.stderr rename to tests/ui/for-loop-while/iter-from-mac-call.stderr diff --git a/tests/ui/warnings/no-explicit-path-issue-122509.rs b/tests/ui/resolve/no-explicit-path.rs similarity index 100% rename from tests/ui/warnings/no-explicit-path-issue-122509.rs rename to tests/ui/resolve/no-explicit-path.rs diff --git a/tests/ui/for/issue-20605.current.stderr b/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr similarity index 100% rename from tests/ui/for/issue-20605.current.stderr rename to tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr similarity index 100% rename from tests/ui/for/issue-20605.next.stderr rename to tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr diff --git a/tests/ui/for/issue-20605.rs b/tests/ui/traits/dyn-iterator-deref-in-for-loop.rs similarity index 100% rename from tests/ui/for/issue-20605.rs rename to tests/ui/traits/dyn-iterator-deref-in-for-loop.rs diff --git a/tests/ui/trait-objects/trait-object-lifetime-conversion-47638.rs b/tests/ui/traits/object/trait-object-lifetime-conversion.rs similarity index 100% rename from tests/ui/trait-objects/trait-object-lifetime-conversion-47638.rs rename to tests/ui/traits/object/trait-object-lifetime-conversion.rs From 416ae00e31c04b62cd11959c2fe20e25bdf743a9 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 2 Dec 2025 11:24:03 +0900 Subject: [PATCH 186/585] cleaned up some tests --- tests/ui/for-loop-while/for-c-in-str.rs | 3 ++- tests/ui/for-loop-while/for-c-in-str.stderr | 2 +- tests/ui/for-loop-while/for-loop-bogosity.rs | 10 +++++----- tests/ui/for-loop-while/for-loop-bogosity.stderr | 2 +- .../ui/for-loop-while/for-loop-diagnostic-span.stderr | 2 +- tests/ui/for-loop-while/for-loop-type-error.rs | 2 ++ tests/ui/for-loop-while/for-loop-type-error.stderr | 2 +- .../for-loop-unconstrained-element-type.rs | 3 ++- .../for-loop-unconstrained-element-type.stderr | 6 +++--- tests/ui/resolve/no-explicit-path.rs | 1 + 10 files changed, 19 insertions(+), 14 deletions(-) diff --git a/tests/ui/for-loop-while/for-c-in-str.rs b/tests/ui/for-loop-while/for-c-in-str.rs index b086128d28cb..b3190101da09 100644 --- a/tests/ui/for-loop-while/for-c-in-str.rs +++ b/tests/ui/for-loop-while/for-c-in-str.rs @@ -1,4 +1,5 @@ -// E0277 should point exclusively at line 6, not the entire for loop span +//! Tests that the E0277 error span, generated by the `for` loop desugaring, +//! points exclusively to the loop header expression and not the full loop block. fn main() { for c in "asdf" { diff --git a/tests/ui/for-loop-while/for-c-in-str.stderr b/tests/ui/for-loop-while/for-c-in-str.stderr index 475cf8c88749..30749274f919 100644 --- a/tests/ui/for-loop-while/for-c-in-str.stderr +++ b/tests/ui/for-loop-while/for-c-in-str.stderr @@ -1,5 +1,5 @@ error[E0277]: `&str` is not an iterator - --> $DIR/for-c-in-str.rs:4:14 + --> $DIR/for-c-in-str.rs:5:14 | LL | for c in "asdf" { | ^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()` diff --git a/tests/ui/for-loop-while/for-loop-bogosity.rs b/tests/ui/for-loop-while/for-loop-bogosity.rs index 9341dea0974b..19117620c5e6 100644 --- a/tests/ui/for-loop-while/for-loop-bogosity.rs +++ b/tests/ui/for-loop-while/for-loop-bogosity.rs @@ -1,3 +1,6 @@ +//! Tests that a struct with a `next` method but without the `Iterator` trait +//! implementation yields an error in a `for` loop. + struct MyStruct { x: isize, y: isize, @@ -10,12 +13,9 @@ fn next(&mut self) -> Option { } pub fn main() { - let mut bogus = MyStruct { - x: 1, - y: 2, - }; + let mut bogus = MyStruct { x: 1, y: 2 }; for x in bogus { - //~^ ERROR `MyStruct` is not an iterator + //~^ ERROR `MyStruct` is not an iterator drop(x); } } diff --git a/tests/ui/for-loop-while/for-loop-bogosity.stderr b/tests/ui/for-loop-while/for-loop-bogosity.stderr index f4d99671f8e0..53bd32e337fd 100644 --- a/tests/ui/for-loop-while/for-loop-bogosity.stderr +++ b/tests/ui/for-loop-while/for-loop-bogosity.stderr @@ -5,7 +5,7 @@ LL | for x in bogus { | ^^^^^ `MyStruct` is not an iterator | help: the trait `Iterator` is not implemented for `MyStruct` - --> $DIR/for-loop-bogosity.rs:1:1 + --> $DIR/for-loop-bogosity.rs:4:1 | LL | struct MyStruct { | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/for-loop-while/for-loop-diagnostic-span.stderr b/tests/ui/for-loop-while/for-loop-diagnostic-span.stderr index 00822324039f..d2fc05f054a0 100644 --- a/tests/ui/for-loop-while/for-loop-diagnostic-span.stderr +++ b/tests/ui/for-loop-while/for-loop-diagnostic-span.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `foo` in this scope - --> $DIR/for-expn.rs:6:7 + --> $DIR/for-loop-diagnostic-span.rs:6:7 | LL | foo | ^^^ not found in this scope diff --git a/tests/ui/for-loop-while/for-loop-type-error.rs b/tests/ui/for-loop-while/for-loop-type-error.rs index 8d9fc20f0d0d..895f1985a619 100644 --- a/tests/ui/for-loop-while/for-loop-type-error.rs +++ b/tests/ui/for-loop-while/for-loop-type-error.rs @@ -1,3 +1,5 @@ +//! regression test for issue + pub fn main() { let x = () + (); //~ ERROR cannot add `()` to `()` diff --git a/tests/ui/for-loop-while/for-loop-type-error.stderr b/tests/ui/for-loop-while/for-loop-type-error.stderr index 393becd1b345..88f383444cb3 100644 --- a/tests/ui/for-loop-while/for-loop-type-error.stderr +++ b/tests/ui/for-loop-while/for-loop-type-error.stderr @@ -1,5 +1,5 @@ error[E0369]: cannot add `()` to `()` - --> $DIR/for-loop-type-error.rs:2:16 + --> $DIR/for-loop-type-error.rs:4:16 | LL | let x = () + (); | -- ^ -- () diff --git a/tests/ui/for-loop-while/for-loop-unconstrained-element-type.rs b/tests/ui/for-loop-while/for-loop-unconstrained-element-type.rs index 0c7a3516a14c..4fff6df5f4d3 100644 --- a/tests/ui/for-loop-while/for-loop-unconstrained-element-type.rs +++ b/tests/ui/for-loop-while/for-loop-unconstrained-element-type.rs @@ -3,7 +3,8 @@ // Subtle changes in the desugaring can cause the // type of elements in the vector to (incorrectly) // fallback to `!` or `()`. +// regression test for issue fn main() { - for i in Vec::new() { } //~ ERROR type annotations needed + for i in Vec::new() {} //~ ERROR type annotations needed } diff --git a/tests/ui/for-loop-while/for-loop-unconstrained-element-type.stderr b/tests/ui/for-loop-while/for-loop-unconstrained-element-type.stderr index 3add3ae2eeb2..3b3fa6e7b5c6 100644 --- a/tests/ui/for-loop-while/for-loop-unconstrained-element-type.stderr +++ b/tests/ui/for-loop-while/for-loop-unconstrained-element-type.stderr @@ -1,12 +1,12 @@ error[E0282]: type annotations needed - --> $DIR/for-loop-unconstrained-element-type.rs:8:14 + --> $DIR/for-loop-unconstrained-element-type.rs:9:14 | -LL | for i in Vec::new() { } +LL | for i in Vec::new() {} | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec` | help: consider specifying the generic argument | -LL | for i in Vec::::new() { } +LL | for i in Vec::::new() {} | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/resolve/no-explicit-path.rs b/tests/ui/resolve/no-explicit-path.rs index 5be4b174076d..11a5b78ab910 100644 --- a/tests/ui/resolve/no-explicit-path.rs +++ b/tests/ui/resolve/no-explicit-path.rs @@ -1,3 +1,4 @@ +//! regression test for issue //@ build-pass //@ compile-flags: -C codegen-units=2 --emit asm From 073f5e29f11092aa0635ba79e66ec8a3eac33e65 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 2 Dec 2025 11:25:36 +0900 Subject: [PATCH 187/585] Updated `tests/ui/for-loop-while/iter-from-mac-call.rs` --- tests/ui/for-loop-while/iter-from-mac-call.rs | 25 +++++++++++-------- .../for-loop-while/iter-from-mac-call.stderr | 21 +++------------- ...-iterator-deref-in-for-loop.current.stderr | 6 ++--- ...dyn-iterator-deref-in-for-loop.next.stderr | 6 ++--- .../traits/dyn-iterator-deref-in-for-loop.rs | 11 +++++--- 5 files changed, 32 insertions(+), 37 deletions(-) diff --git a/tests/ui/for-loop-while/iter-from-mac-call.rs b/tests/ui/for-loop-while/iter-from-mac-call.rs index 8df21456222c..58177444c3f9 100644 --- a/tests/ui/for-loop-while/iter-from-mac-call.rs +++ b/tests/ui/for-loop-while/iter-from-mac-call.rs @@ -1,13 +1,12 @@ +//! Tests for trait/type errors when dereferencing via macro in a for loop. + macro_rules! deref { - ($e:expr) => { *$e }; + ($e:expr) => { + *$e + }; } -fn f1<'a>(mut iter: Box>) { - for item in deref!(iter) { *item = 0 } - //~^ ERROR `dyn Iterator` is not an iterator -} - -fn f2(x: &mut i32) { +fn f1(x: &mut i32) { for _item in deref!(x) {} //~^ ERROR `i32` is not an iterator } @@ -15,12 +14,16 @@ fn f2(x: &mut i32) { struct Wrapped(i32); macro_rules! borrow_deref { - ($e:expr) => { &mut *$e }; + ($e:expr) => { + &mut *$e + }; } -fn f3<'a>(mut iter: Box>) { - for Wrapped(item) in borrow_deref!(iter) { *item = 0 } - //~^ ERROR mismatched types +fn f2<'a>(mut iter: Box>) { + for Wrapped(item) in borrow_deref!(iter) { + //~^ ERROR mismatched types + *item = 0 + } } fn main() {} diff --git a/tests/ui/for-loop-while/iter-from-mac-call.stderr b/tests/ui/for-loop-while/iter-from-mac-call.stderr index e62efb250e29..4cde6a8a86d3 100644 --- a/tests/ui/for-loop-while/iter-from-mac-call.stderr +++ b/tests/ui/for-loop-while/iter-from-mac-call.stderr @@ -1,18 +1,5 @@ -error[E0277]: `dyn Iterator` is not an iterator - --> $DIR/iter_from_mac_call.rs:6:17 - | -LL | for item in deref!(iter) { *item = 0 } - | ^^^^^^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator` - | - = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied - = note: required for `dyn Iterator` to implement `IntoIterator` -help: consider mutably borrowing here - | -LL | for item in &mut deref!(iter) { *item = 0 } - | ++++ - error[E0277]: `i32` is not an iterator - --> $DIR/iter_from_mac_call.rs:11:18 + --> $DIR/iter-from-mac-call.rs:10:18 | LL | for _item in deref!(x) {} | ^^^^^^^^^ `i32` is not an iterator @@ -22,14 +9,14 @@ LL | for _item in deref!(x) {} = note: required for `i32` to implement `IntoIterator` error[E0308]: mismatched types - --> $DIR/iter_from_mac_call.rs:22:9 + --> $DIR/iter-from-mac-call.rs:23:9 | -LL | for Wrapped(item) in borrow_deref!(iter) { *item = 0 } +LL | for Wrapped(item) in borrow_deref!(iter) { | ^^^^^^^^^^^^^ ------------------- this is an iterator with items of type `&mut i32` | | | expected `i32`, found `Wrapped` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr b/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr index 1a66cb414649..b5a9b82a93a3 100644 --- a/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr +++ b/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr @@ -1,14 +1,14 @@ error[E0277]: `dyn Iterator` is not an iterator - --> $DIR/issue-20605.rs:6:17 + --> $DIR/dyn-iterator-deref-in-for-loop.rs:9:17 | -LL | for item in *things { *item = 0 } +LL | for item in *things { | ^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator` | = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied = note: required for `dyn Iterator` to implement `IntoIterator` help: consider mutably borrowing here | -LL | for item in &mut *things { *item = 0 } +LL | for item in &mut *things { | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr b/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr index 1a66cb414649..b5a9b82a93a3 100644 --- a/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr +++ b/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr @@ -1,14 +1,14 @@ error[E0277]: `dyn Iterator` is not an iterator - --> $DIR/issue-20605.rs:6:17 + --> $DIR/dyn-iterator-deref-in-for-loop.rs:9:17 | -LL | for item in *things { *item = 0 } +LL | for item in *things { | ^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator` | = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied = note: required for `dyn Iterator` to implement `IntoIterator` help: consider mutably borrowing here | -LL | for item in &mut *things { *item = 0 } +LL | for item in &mut *things { | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/dyn-iterator-deref-in-for-loop.rs b/tests/ui/traits/dyn-iterator-deref-in-for-loop.rs index 5c56e64a0172..04587df1555d 100644 --- a/tests/ui/traits/dyn-iterator-deref-in-for-loop.rs +++ b/tests/ui/traits/dyn-iterator-deref-in-for-loop.rs @@ -1,10 +1,15 @@ +//! Tests that dereferencing a Box in a for loop correctly yields an error, +//! as the unsized trait object does not implement IntoIterator. +//! regression test for //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -fn changer<'a>(mut things: Box>) { - for item in *things { *item = 0 } - //~^ ERROR `dyn Iterator` is not an iterator +fn changer<'a>(mut things: Box>) { + for item in *things { + //~^ ERROR `dyn Iterator` is not an iterator + *item = 0 + } } fn main() {} From 6bd9d7625d65b14a9c09a9dafa0cf7b9b6263e4f Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 30 Nov 2025 23:32:07 -0800 Subject: [PATCH 188/585] =?UTF-8?q?Assume=20the=20returned=20value=20in=20?= =?UTF-8?q?`.filter(=E2=80=A6).count()`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to how this helps in `slice::Iter::position`, LLVM sometimes loses track of how high this can get, so for `TrustedLen` iterators tell it what the upper bound is. --- library/core/src/iter/adapters/filter.rs | 41 ++++++++++++++++++- .../iter-filter-count-assume.rs | 34 +++++++++++++++ .../iter-filter-count-debug-check.rs | 34 +++++++++++++++ 3 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 tests/codegen-llvm/lib-optimizations/iter-filter-count-assume.rs create mode 100644 tests/ui/iterators/iter-filter-count-debug-check.rs diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs index dd08cd6f61c4..b22419ccf080 100644 --- a/library/core/src/iter/adapters/filter.rs +++ b/library/core/src/iter/adapters/filter.rs @@ -4,7 +4,7 @@ use crate::fmt; use crate::iter::adapters::SourceIter; -use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused}; +use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedLen}; use crate::num::NonZero; use crate::ops::Try; @@ -138,7 +138,13 @@ fn to_usize(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> usize move |x| predicate(&x) as usize } - self.iter.map(to_usize(self.predicate)).sum() + let before = self.iter.size_hint().1.unwrap_or(usize::MAX); + let total = self.iter.map(to_usize(self.predicate)).sum(); + // SAFETY: `total` and `before` came from the same iterator of type `I` + unsafe { + ::assume_count_le_upper_bound(total, before); + } + total } #[inline] @@ -214,3 +220,34 @@ unsafe impl InPlaceIterable for Filter { const EXPAND_BY: Option> = I::EXPAND_BY; const MERGE_BY: Option> = I::MERGE_BY; } + +trait SpecAssumeCount { + /// # Safety + /// + /// `count` must be an number of items actually read from the iterator. + /// + /// `upper` must either: + /// - have come from `size_hint().1` on the iterator, or + /// - be `usize::MAX` which will vacuously do nothing. + unsafe fn assume_count_le_upper_bound(count: usize, upper: usize); +} + +impl SpecAssumeCount for I { + #[inline] + #[rustc_inherit_overflow_checks] + default unsafe fn assume_count_le_upper_bound(count: usize, upper: usize) { + // In the default we can't trust the `upper` for soundness + // because it came from an untrusted `size_hint`. + + // In debug mode we might as well check that the size_hint wasn't too small + let _ = upper - count; + } +} + +impl SpecAssumeCount for I { + #[inline] + unsafe fn assume_count_le_upper_bound(count: usize, upper: usize) { + // SAFETY: The `upper` is trusted because it came from a `TrustedLen` iterator. + unsafe { crate::hint::assert_unchecked(count <= upper) } + } +} diff --git a/tests/codegen-llvm/lib-optimizations/iter-filter-count-assume.rs b/tests/codegen-llvm/lib-optimizations/iter-filter-count-assume.rs new file mode 100644 index 000000000000..7588b23efc3a --- /dev/null +++ b/tests/codegen-llvm/lib-optimizations/iter-filter-count-assume.rs @@ -0,0 +1,34 @@ +//@ compile-flags: -Copt-level=3 +//@ edition: 2024 + +#![crate_type = "lib"] + +// Similar to how we `assume` that `slice::Iter::position` is within the length, +// check that `count` also does that for `TrustedLen` iterators. +// See https://rust-lang.zulipchat.com/#narrow/channel/122651-general/topic/Overflow-chk.20removed.20for.20array.20of.2059.2C.20but.20not.2060.2C.20elems/with/561070780 + +// CHECK-LABEL: @filter_count_untrusted +#[unsafe(no_mangle)] +pub fn filter_count_untrusted(bar: &[u8; 1234]) -> u16 { + // CHECK-NOT: llvm.assume + // CHECK: call void @{{.+}}unwrap_failed + // CHECK-NOT: llvm.assume + let mut iter = bar.iter(); + let iter = std::iter::from_fn(|| iter.next()); // Make it not TrustedLen + u16::try_from(iter.filter(|v| **v == 0).count()).unwrap() +} + +// CHECK-LABEL: @filter_count_trusted +#[unsafe(no_mangle)] +pub fn filter_count_trusted(bar: &[u8; 1234]) -> u16 { + // CHECK-NOT: unwrap_failed + // CHECK: %[[ASSUME:.+]] = icmp ult {{i64|i32|i16}} %{{.+}}, 1235 + // CHECK-NEXT: tail call void @llvm.assume(i1 %[[ASSUME]]) + // CHECK-NOT: unwrap_failed + let iter = bar.iter(); + u16::try_from(iter.filter(|v| **v == 0).count()).unwrap() +} + +// CHECK: ; core::result::unwrap_failed +// CHECK-NEXT: Function Attrs +// CHECK-NEXT: declare{{.+}}void @{{.+}}unwrap_failed diff --git a/tests/ui/iterators/iter-filter-count-debug-check.rs b/tests/ui/iterators/iter-filter-count-debug-check.rs new file mode 100644 index 000000000000..6e3a3f73920e --- /dev/null +++ b/tests/ui/iterators/iter-filter-count-debug-check.rs @@ -0,0 +1,34 @@ +//@ run-pass +//@ needs-unwind +//@ ignore-backends: gcc +//@ compile-flags: -C overflow-checks + +use std::panic; + +struct Lies(usize); + +impl Iterator for Lies { + type Item = usize; + + fn next(&mut self) -> Option { + if self.0 == 0 { + None + } else { + self.0 -= 1; + Some(self.0) + } + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(2)) + } +} + +fn main() { + let r = panic::catch_unwind(|| { + // This returns more items than its `size_hint` said was possible, + // which `Filter::count` detects via `overflow-checks`. + let _ = Lies(10).filter(|&x| x > 3).count(); + }); + assert!(r.is_err()); +} From 3f1aa0b47eb16ebf049436ca0d5a16ea250f45d7 Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Mon, 1 Dec 2025 20:37:11 +0200 Subject: [PATCH 189/585] Additional test for uN::{gather,scatter}_bits --- library/coretests/tests/num/uint_macros.rs | 64 ++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs index 7f3e27e9c446..6e746a6a2278 100644 --- a/library/coretests/tests/num/uint_macros.rs +++ b/library/coretests/tests/num/uint_macros.rs @@ -387,6 +387,70 @@ fn test_lots_of_isqrt() { } } + #[cfg(not(miri))] // Miri is too slow + #[test] + fn test_lots_of_gather_scatter() { + // Generate a handful of bit patterns to use as inputs + let xs = { + let mut xs = vec![]; + let mut x: $T = !0; + let mut w = $T::BITS; + while w > 0 { + w >>= 1; + xs.push(x); + xs.push(!x); + x ^= x << w; + } + xs + }; + if $T::BITS == 8 { + assert_eq!(&xs, &[0xff, 0x00, 0x0f, 0xf0, 0x33, 0xcc, 0x55, 0xaa]); + } + + // `256 * BITS` masks + let sparse_masks = (i8::MIN..=i8::MAX) + .map(|i| (i as i128 as $T).rotate_right(4)) + .flat_map(|x| (0..$T::BITS).map(move |s| ((1 as $T) << s) ^ x)); + + for sparse in sparse_masks { + // Collect the set bits to sequential low bits + let dense = sparse.gather_bits(sparse); + let count = sparse.count_ones(); + assert_eq!(count, dense.count_ones()); + assert_eq!(count, dense.trailing_ones()); + + let mut t = sparse; + for k in 0..$T::BITS { + let x = ((1 as $T) << k).scatter_bits(sparse); + let y = t.isolate_lowest_one(); + assert_eq!(x, y); + t ^= y; + } + + let mut t = sparse; + for k in 0..count { + let y = t.isolate_lowest_one(); + let x = y.gather_bits(sparse); + assert_eq!(x, (1 as $T) << k); + t ^= y; + } + + for &x in &xs { + // Gather bits from `x & sparse` to `dense` + let dx = x.gather_bits(sparse); + assert_eq!(dx & !dense, 0); + + // Scatter bits from `x & dense` to `sparse` + let sx = x.scatter_bits(sparse); + assert_eq!(sx & !sparse, 0); + + // The other recovers the input (within the mask) + assert_eq!(dx.scatter_bits(sparse), x & sparse); + assert_eq!(sx.gather_bits(sparse), x & dense); + } + } + } + test_runtime_and_compiletime! { fn test_div_floor() { assert_eq_const_safe!($T: (8 as $T).div_floor(3), 2); From 382509988b74f43d2797212cfe56cb24d0423cd4 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 14 Nov 2025 00:32:21 -0800 Subject: [PATCH 190/585] Remove initialized-bytes tracking from `BorrowedBuf` and `BorrowedCursor` As discussed extensively in libs-api, the initialized-bytes tracking primarily benefits calls to `read_buf` that end up initializing the buffer and calling `read`, at the expense of calls to `read_buf` that *don't* need to initialize the buffer. Essentially, this optimizes for the past at the expense of the future. If people observe performance issues using `read_buf` (or something that calls it) with a given `Read` impl, they can fix those performance issues by implementing `read_buf` for that `Read`. Update the documentation to stop talking about initialized-but-unfilled bytes. Remove all functions that just deal with those bytes and their tracking, and remove usage of those methods. Remove `BorrowedCursor::advance` as there's no longer a safe case for advancing within initialized-but-unfilled bytes. Rename `BorrowedCursor::advance_unchecked` to `advance`. Update tests. --- library/core/src/io/borrowed_buf.rs | 162 +++--------------- library/coretests/tests/io/borrowed_buf.rs | 90 ++-------- library/std/src/fs/tests.rs | 2 - library/std/src/io/buffered/bufreader.rs | 9 - .../std/src/io/buffered/bufreader/buffer.rs | 27 +-- library/std/src/io/buffered/tests.rs | 24 --- library/std/src/io/copy.rs | 13 -- library/std/src/io/mod.rs | 53 +----- library/std/src/io/tests.rs | 9 - library/std/src/io/util.rs | 2 +- library/std/src/io/util/tests.rs | 8 - library/std/src/net/tcp/tests.rs | 2 - library/std/src/process/tests.rs | 2 - library/std/src/sys/fd/unix.rs | 4 +- .../std/src/sys/net/connection/socket/unix.rs | 2 +- 15 files changed, 53 insertions(+), 356 deletions(-) diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index 088dea781294..b765b96fd00a 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -2,27 +2,26 @@ use crate::fmt::{self, Debug, Formatter}; use crate::mem::{self, MaybeUninit}; -use crate::{cmp, ptr}; -/// A borrowed byte buffer which is incrementally filled and initialized. +/// A borrowed buffer of initially uninitialized bytes, which is incrementally filled. /// -/// This type is a sort of "double cursor". It tracks three regions in the buffer: a region at the beginning of the -/// buffer that has been logically filled with data, a region that has been initialized at some point but not yet -/// logically filled, and a region at the end that is fully uninitialized. The filled region is guaranteed to be a -/// subset of the initialized region. +/// This type makes it safer to work with `MaybeUninit` buffers, such as to read into a buffer +/// without having to initialize it first. It tracks the region of bytes that have been filled and +/// the region that remains uninitialized. /// -/// In summary, the contents of the buffer can be visualized as: +/// The contents of the buffer can be visualized as: /// ```not_rust -/// [ capacity ] -/// [ filled | unfilled ] -/// [ initialized | uninitialized ] +/// [ capacity ] +/// [ len: filled and initialized | capacity - len: uninitialized ] /// ``` /// -/// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique reference -/// (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_init`), but cannot be -/// directly written. To write into the buffer, use `unfilled` to create a `BorrowedCursor`. The cursor -/// has write-only access to the unfilled portion of the buffer (you can think of it as a -/// write-only iterator). +/// Note that `BorrowedBuf` does not distinguish between uninitialized data and data that was +/// previously initialized but no longer contains valid data. +/// +/// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique +/// reference (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_len`), but +/// cannot be directly written. To write into the buffer, use `unfilled` to create a +/// `BorrowedCursor`. The cursor has write-only access to the unfilled portion of the buffer. /// /// The lifetime `'data` is a bound on the lifetime of the underlying data. pub struct BorrowedBuf<'data> { @@ -30,14 +29,11 @@ pub struct BorrowedBuf<'data> { buf: &'data mut [MaybeUninit], /// The length of `self.buf` which is known to be filled. filled: usize, - /// The length of `self.buf` which is known to be initialized. - init: usize, } impl Debug for BorrowedBuf<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("BorrowedBuf") - .field("init", &self.init) .field("filled", &self.filled) .field("capacity", &self.capacity()) .finish() @@ -48,24 +44,22 @@ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> { #[inline] fn from(slice: &'data mut [u8]) -> BorrowedBuf<'data> { - let len = slice.len(); - BorrowedBuf { - // SAFETY: initialized data never becoming uninitialized is an invariant of BorrowedBuf + // SAFETY: Always in bounds. We treat the buffer as uninitialized, even though it's + // already initialized. buf: unsafe { (slice as *mut [u8]).as_uninit_slice_mut().unwrap() }, filled: 0, - init: len, } } } /// Creates a new `BorrowedBuf` from an uninitialized buffer. /// -/// Use `set_init` if part of the buffer is known to be already initialized. +/// Use `set_filled` if part of the buffer is known to be already filled. impl<'data> From<&'data mut [MaybeUninit]> for BorrowedBuf<'data> { #[inline] fn from(buf: &'data mut [MaybeUninit]) -> BorrowedBuf<'data> { - BorrowedBuf { buf, filled: 0, init: 0 } + BorrowedBuf { buf, filled: 0 } } } @@ -74,14 +68,11 @@ fn from(buf: &'data mut [MaybeUninit]) -> BorrowedBuf<'data> { /// Use `BorrowedCursor::with_unfilled_buf` instead for a safer alternative. impl<'data> From> for BorrowedBuf<'data> { #[inline] - fn from(mut buf: BorrowedCursor<'data>) -> BorrowedBuf<'data> { - let init = buf.init_mut().len(); + fn from(buf: BorrowedCursor<'data>) -> BorrowedBuf<'data> { BorrowedBuf { - // SAFETY: no initialized byte is ever uninitialized as per - // `BorrowedBuf`'s invariant + // SAFETY: Always in bounds. We treat the buffer as uninitialized. buf: unsafe { buf.buf.buf.get_unchecked_mut(buf.buf.filled..) }, filled: 0, - init, } } } @@ -99,12 +90,6 @@ pub fn len(&self) -> usize { self.filled } - /// Returns the length of the initialized part of the buffer. - #[inline] - pub fn init_len(&self) -> usize { - self.init - } - /// Returns a shared reference to the filled portion of the buffer. #[inline] pub fn filled(&self) -> &[u8] { @@ -159,33 +144,16 @@ pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> { /// Clears the buffer, resetting the filled region to empty. /// - /// The number of initialized bytes is not changed, and the contents of the buffer are not modified. + /// The contents of the buffer are not modified. #[inline] pub fn clear(&mut self) -> &mut Self { self.filled = 0; self } - - /// Asserts that the first `n` bytes of the buffer are initialized. - /// - /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer - /// bytes than are already known to be initialized. - /// - /// # Safety - /// - /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized. - #[inline] - pub unsafe fn set_init(&mut self, n: usize) -> &mut Self { - self.init = cmp::max(self.init, n); - self - } } /// A writeable view of the unfilled portion of a [`BorrowedBuf`]. /// -/// The unfilled portion consists of an initialized and an uninitialized part; see [`BorrowedBuf`] -/// for details. -/// /// Data can be written directly to the cursor by using [`append`](BorrowedCursor::append) or /// indirectly by getting a slice of part or all of the cursor and writing into the slice. In the /// indirect case, the caller must call [`advance`](BorrowedCursor::advance) after writing to inform @@ -238,48 +206,17 @@ pub fn written(&self) -> usize { self.buf.filled } - /// Returns a mutable reference to the initialized portion of the cursor. - #[inline] - pub fn init_mut(&mut self) -> &mut [u8] { - // SAFETY: We only slice the initialized part of the buffer, which is always valid - unsafe { - let buf = self.buf.buf.get_unchecked_mut(self.buf.filled..self.buf.init); - buf.assume_init_mut() - } - } - /// Returns a mutable reference to the whole cursor. /// /// # Safety /// - /// The caller must not uninitialize any bytes in the initialized portion of the cursor. + /// The caller must not uninitialize any previously initialized bytes. #[inline] pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit] { // SAFETY: always in bounds unsafe { self.buf.buf.get_unchecked_mut(self.buf.filled..) } } - /// Advances the cursor by asserting that `n` bytes have been filled. - /// - /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be - /// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements - /// and its unfilled portion (and the capacity of this cursor) shrinks by `n` elements. - /// - /// If less than `n` bytes initialized (by the cursor's point of view), `set_init` should be - /// called first. - /// - /// # Panics - /// - /// Panics if there are less than `n` bytes initialized. - #[inline] - pub fn advance(&mut self, n: usize) -> &mut Self { - // The subtraction cannot underflow by invariant of this type. - assert!(n <= self.buf.init - self.buf.filled); - - self.buf.filled += n; - self - } - /// Advances the cursor by asserting that `n` bytes have been filled. /// /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be @@ -288,42 +225,11 @@ pub fn advance(&mut self, n: usize) -> &mut Self { /// /// # Safety /// - /// The caller must ensure that the first `n` bytes of the cursor have been properly - /// initialised. + /// The caller must ensure that the first `n` bytes of the cursor have been initialized. `n` + /// must not exceed the remaining capacity of this cursor. #[inline] - pub unsafe fn advance_unchecked(&mut self, n: usize) -> &mut Self { + pub unsafe fn advance(&mut self, n: usize) -> &mut Self { self.buf.filled += n; - self.buf.init = cmp::max(self.buf.init, self.buf.filled); - self - } - - /// Initializes all bytes in the cursor. - #[inline] - pub fn ensure_init(&mut self) -> &mut Self { - // SAFETY: always in bounds and we never uninitialize these bytes. - let uninit = unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) }; - - // SAFETY: 0 is a valid value for MaybeUninit and the length matches the allocation - // since it is comes from a slice reference. - unsafe { - ptr::write_bytes(uninit.as_mut_ptr(), 0, uninit.len()); - } - self.buf.init = self.buf.capacity(); - - self - } - - /// Asserts that the first `n` unfilled bytes of the cursor are initialized. - /// - /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when - /// called with fewer bytes than are already known to be initialized. - /// - /// # Safety - /// - /// The caller must ensure that the first `n` bytes of the buffer have already been initialized. - #[inline] - pub unsafe fn set_init(&mut self, n: usize) -> &mut Self { - self.buf.init = cmp::max(self.buf.init, self.buf.filled + n); self } @@ -341,10 +247,6 @@ pub fn append(&mut self, buf: &[u8]) { self.as_mut()[..buf.len()].write_copy_of_slice(buf); } - // SAFETY: We just added the entire contents of buf to the filled section. - unsafe { - self.set_init(buf.len()); - } self.buf.filled += buf.len(); } @@ -367,17 +269,9 @@ pub fn with_unfilled_buf(&mut self, f: impl FnOnce(&mut BorrowedBuf<'_>) -> T // there, one could mark some bytes as initialized even though there aren't. assert!(core::ptr::addr_eq(prev_ptr, buf.buf)); - let filled = buf.filled; - let init = buf.init; - - // Update `init` and `filled` fields with what was written to the buffer. - // `self.buf.filled` was the starting length of the `BorrowedBuf`. - // - // SAFETY: These amounts of bytes were initialized/filled in the `BorrowedBuf`, - // and therefore they are initialized/filled in the cursor too, because the - // buffer wasn't replaced. - self.buf.init = self.buf.filled + init; - self.buf.filled += filled; + // SAFETY: These bytes were filled in the `BorrowedBuf`, so they're filled in the cursor + // too, because the buffer wasn't replaced. + self.buf.filled += buf.filled; res } diff --git a/library/coretests/tests/io/borrowed_buf.rs b/library/coretests/tests/io/borrowed_buf.rs index aaa98d26ff8b..730ba04465a1 100644 --- a/library/coretests/tests/io/borrowed_buf.rs +++ b/library/coretests/tests/io/borrowed_buf.rs @@ -8,7 +8,6 @@ fn new() { let mut rbuf: BorrowedBuf<'_> = buf.into(); assert_eq!(rbuf.filled().len(), 0); - assert_eq!(rbuf.init_len(), 16); assert_eq!(rbuf.capacity(), 16); assert_eq!(rbuf.unfilled().capacity(), 16); } @@ -20,27 +19,16 @@ fn uninit() { let mut rbuf: BorrowedBuf<'_> = buf.into(); assert_eq!(rbuf.filled().len(), 0); - assert_eq!(rbuf.init_len(), 0); assert_eq!(rbuf.capacity(), 16); assert_eq!(rbuf.unfilled().capacity(), 16); } -#[test] -fn initialize_unfilled() { - let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - rbuf.unfilled().ensure_init(); - - assert_eq!(rbuf.init_len(), 16); -} - #[test] fn advance_filled() { let buf: &mut [_] = &mut [0; 16]; let mut rbuf: BorrowedBuf<'_> = buf.into(); - rbuf.unfilled().advance(1); + unsafe { rbuf.unfilled().advance(1) }; assert_eq!(rbuf.filled().len(), 1); assert_eq!(rbuf.unfilled().capacity(), 15); @@ -51,7 +39,7 @@ fn clear() { let buf: &mut [_] = &mut [255; 16]; let mut rbuf: BorrowedBuf<'_> = buf.into(); - rbuf.unfilled().advance(16); + unsafe { rbuf.unfilled().advance(16) }; assert_eq!(rbuf.filled().len(), 16); assert_eq!(rbuf.unfilled().capacity(), 0); @@ -61,33 +49,9 @@ fn clear() { assert_eq!(rbuf.filled().len(), 0); assert_eq!(rbuf.unfilled().capacity(), 16); - assert_eq!(rbuf.unfilled().init_mut(), [255; 16]); -} + unsafe { rbuf.unfilled().advance(16) }; -#[test] -fn set_init() { - let buf: &mut [_] = &mut [MaybeUninit::zeroed(); 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - unsafe { - rbuf.set_init(8); - } - - assert_eq!(rbuf.init_len(), 8); - - rbuf.unfilled().advance(4); - - unsafe { - rbuf.set_init(2); - } - - assert_eq!(rbuf.init_len(), 8); - - unsafe { - rbuf.set_init(8); - } - - assert_eq!(rbuf.init_len(), 8); + assert_eq!(rbuf.filled(), [255; 16]); } #[test] @@ -97,7 +61,6 @@ fn append() { rbuf.unfilled().append(&[0; 8]); - assert_eq!(rbuf.init_len(), 8); assert_eq!(rbuf.filled().len(), 8); assert_eq!(rbuf.filled(), [0; 8]); @@ -105,7 +68,6 @@ fn append() { rbuf.unfilled().append(&[1; 16]); - assert_eq!(rbuf.init_len(), 16); assert_eq!(rbuf.filled().len(), 16); assert_eq!(rbuf.filled(), [1; 16]); } @@ -125,43 +87,12 @@ fn reborrow_written() { assert_eq!(cursor.written(), 32); assert_eq!(buf.unfilled().written(), 32); - assert_eq!(buf.init_len(), 32); assert_eq!(buf.filled().len(), 32); let filled = buf.filled(); assert_eq!(&filled[..16], [1; 16]); assert_eq!(&filled[16..], [2; 16]); } -#[test] -fn cursor_set_init() { - let buf: &mut [_] = &mut [MaybeUninit::zeroed(); 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - unsafe { - rbuf.unfilled().set_init(8); - } - - assert_eq!(rbuf.init_len(), 8); - assert_eq!(rbuf.unfilled().init_mut().len(), 8); - assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 16); - - rbuf.unfilled().advance(4); - - unsafe { - rbuf.unfilled().set_init(2); - } - - assert_eq!(rbuf.init_len(), 8); - - unsafe { - rbuf.unfilled().set_init(8); - } - - assert_eq!(rbuf.init_len(), 12); - assert_eq!(rbuf.unfilled().init_mut().len(), 8); - assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 12); -} - #[test] fn cursor_with_unfilled_buf() { let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; @@ -169,31 +100,30 @@ fn cursor_with_unfilled_buf() { let mut cursor = rbuf.unfilled(); cursor.with_unfilled_buf(|buf| { + assert_eq!(buf.capacity(), 16); buf.unfilled().append(&[1, 2, 3]); assert_eq!(buf.filled(), &[1, 2, 3]); }); - assert_eq!(cursor.init_mut().len(), 0); assert_eq!(cursor.written(), 3); cursor.with_unfilled_buf(|buf| { assert_eq!(buf.capacity(), 13); - assert_eq!(buf.init_len(), 0); - buf.unfilled().ensure_init(); - buf.unfilled().advance(4); + unsafe { + buf.unfilled().as_mut().write_filled(0); + buf.unfilled().advance(4) + }; }); - assert_eq!(cursor.init_mut().len(), 9); assert_eq!(cursor.written(), 7); cursor.with_unfilled_buf(|buf| { assert_eq!(buf.capacity(), 9); - assert_eq!(buf.init_len(), 9); }); - assert_eq!(cursor.init_mut().len(), 9); assert_eq!(cursor.written(), 7); + assert_eq!(rbuf.len(), 7); assert_eq!(rbuf.filled(), &[1, 2, 3, 0, 0, 0, 0]); } diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 0517760c3550..a139b0610786 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -699,8 +699,6 @@ fn file_test_read_buf() { let mut file = check!(File::open(filename)); check!(file.read_buf(buf.unfilled())); assert_eq!(buf.filled(), &[1, 2, 3, 4]); - // File::read_buf should omit buffer initialization. - assert_eq!(buf.init_len(), 4); check!(fs::remove_file(filename)); } diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 40441dc057d0..69c260b5410a 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -284,15 +284,6 @@ pub(in crate::io) fn discard_buffer(&mut self) { } } -// This is only used by a test which asserts that the initialization-tracking is correct. -#[cfg(test)] -impl BufReader { - #[allow(missing_docs)] - pub fn initialized(&self) -> usize { - self.buf.initialized() - } -} - impl BufReader { /// Seeks relative to the current position. If the new position lies within the buffer, /// the buffer will not be flushed, allowing for more efficient seeks. diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index 9b600cd55758..2694726b3f44 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -21,25 +21,19 @@ pub struct Buffer { // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are // initialized with bytes from a read. filled: usize, - // This is the max number of bytes returned across all `fill_buf` calls. We track this so that we - // can accurately tell `read_buf` how many bytes of buf are initialized, to bypass as much of its - // defensive initialization as possible. Note that while this often the same as `filled`, it - // doesn't need to be. Calls to `fill_buf` are not required to actually fill the buffer, and - // omitting this is a huge perf regression for `Read` impls that do not. - initialized: usize, } impl Buffer { #[inline] pub fn with_capacity(capacity: usize) -> Self { let buf = Box::new_uninit_slice(capacity); - Self { buf, pos: 0, filled: 0, initialized: 0 } + Self { buf, pos: 0, filled: 0 } } #[inline] pub fn try_with_capacity(capacity: usize) -> io::Result { match Box::try_new_uninit_slice(capacity) { - Ok(buf) => Ok(Self { buf, pos: 0, filled: 0, initialized: 0 }), + Ok(buf) => Ok(Self { buf, pos: 0, filled: 0 }), Err(_) => { Err(io::const_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer")) } @@ -68,12 +62,6 @@ pub fn pos(&self) -> usize { self.pos } - // This is only used by a test which asserts that the initialization-tracking is correct. - #[cfg(test)] - pub fn initialized(&self) -> usize { - self.initialized - } - #[inline] pub fn discard_buffer(&mut self) { self.pos = 0; @@ -110,13 +98,8 @@ pub fn unconsume(&mut self, amt: usize) { /// Read more bytes into the buffer without discarding any of its contents pub fn read_more(&mut self, mut reader: impl Read) -> io::Result { let mut buf = BorrowedBuf::from(&mut self.buf[self.filled..]); - let old_init = self.initialized - self.filled; - unsafe { - buf.set_init(old_init); - } reader.read_buf(buf.unfilled())?; self.filled += buf.len(); - self.initialized += buf.init_len() - old_init; Ok(buf.len()) } @@ -137,16 +120,10 @@ pub fn fill_buf(&mut self, mut reader: impl Read) -> io::Result<&[u8]> { debug_assert!(self.pos == self.filled); let mut buf = BorrowedBuf::from(&mut *self.buf); - // SAFETY: `self.filled` bytes will always have been initialized. - unsafe { - buf.set_init(self.initialized); - } - let result = reader.read_buf(buf.unfilled()); self.pos = 0; self.filled = buf.len(); - self.initialized = buf.init_len(); result?; } diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index 17f6107aa030..068dca819775 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -1052,30 +1052,6 @@ fn single_formatted_write() { assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]); } -#[test] -fn bufreader_full_initialize() { - struct OneByteReader; - impl Read for OneByteReader { - fn read(&mut self, buf: &mut [u8]) -> crate::io::Result { - if buf.len() > 0 { - buf[0] = 0; - Ok(1) - } else { - Ok(0) - } - } - } - let mut reader = BufReader::new(OneByteReader); - // Nothing is initialized yet. - assert_eq!(reader.initialized(), 0); - - let buf = reader.fill_buf().unwrap(); - // We read one byte... - assert_eq!(buf.len(), 1); - // But we initialized the whole buffer! - assert_eq!(reader.initialized(), reader.capacity()); -} - /// This is a regression test for https://github.com/rust-lang/rust/issues/127584. #[test] fn bufwriter_aliasing() { diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index d060ad528973..13269735cb5c 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -215,28 +215,19 @@ fn copy_from(&mut self, reader: &mut R) -> Result { } let mut len = 0; - let mut init = 0; loop { let buf = self.buffer_mut(); let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into(); - unsafe { - // SAFETY: init is either 0 or the init_len from the previous iteration. - read_buf.set_init(init); - } - if read_buf.capacity() >= DEFAULT_BUF_SIZE { let mut cursor = read_buf.unfilled(); match reader.read_buf(cursor.reborrow()) { Ok(()) => { let bytes_read = cursor.written(); - if bytes_read == 0 { return Ok(len); } - - init = read_buf.init_len() - bytes_read; len += bytes_read as u64; // SAFETY: BorrowedBuf guarantees all of its filled bytes are init @@ -249,10 +240,6 @@ fn copy_from(&mut self, reader: &mut R) -> Result { Err(e) => return Err(e), } } else { - // All the bytes that were already in the buffer are initialized, - // treat them as such when the buffer is flushed. - init += buf.len(); - self.flush_buf()?; } } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 25a4661a0bc9..358676b737fd 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -419,8 +419,6 @@ pub(crate) fn default_read_to_end( .and_then(|s| s.checked_add(1024)?.checked_next_multiple_of(DEFAULT_BUF_SIZE)) .unwrap_or(DEFAULT_BUF_SIZE); - let mut initialized = 0; // Extra initialized bytes from previous loop iteration - const PROBE_SIZE: usize = 32; fn small_probe_read(r: &mut R, buf: &mut Vec) -> Result { @@ -449,8 +447,6 @@ fn small_probe_read(r: &mut R, buf: &mut Vec) -> Result(r: &mut R, buf: &mut Vec) -> Result = spare.into(); - // SAFETY: These bytes were initialized but not filled in the previous loop - unsafe { - read_buf.set_init(initialized); - } - let mut cursor = read_buf.unfilled(); let result = loop { match r.read_buf(cursor.reborrow()) { @@ -489,9 +480,7 @@ fn small_probe_read(r: &mut R, buf: &mut Vec) -> Result(r: &mut R, buf: &mut Vec) -> Result 1 { - max_read_size = usize::MAX; - } - // we have passed a larger buffer than previously and the // reader still hasn't returned a short read if buf_len >= max_read_size && bytes_read == buf_len { @@ -587,8 +557,13 @@ pub(crate) fn default_read_buf(read: F, mut cursor: BorrowedCursor<'_>) -> Re where F: FnOnce(&mut [u8]) -> Result, { - let n = read(cursor.ensure_init().init_mut())?; - cursor.advance(n); + // SAFETY: We do not uninitialize any part of the buffer. + let n = read(unsafe { cursor.as_mut().write_filled(0) })?; + assert!(n <= cursor.capacity()); + // SAFETY: We've initialized the entire buffer, and `read` can't make it uninitialized. + unsafe { + cursor.advance(n); + } Ok(()) } @@ -3058,31 +3033,21 @@ fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> { // The condition above guarantees that `self.limit` fits in `usize`. let limit = self.limit as usize; - let extra_init = cmp::min(limit, buf.init_mut().len()); - // SAFETY: no uninit data is written to ibuf let ibuf = unsafe { &mut buf.as_mut()[..limit] }; let mut sliced_buf: BorrowedBuf<'_> = ibuf.into(); - // SAFETY: extra_init bytes of ibuf are known to be initialized - unsafe { - sliced_buf.set_init(extra_init); - } - let mut cursor = sliced_buf.unfilled(); let result = self.inner.read_buf(cursor.reborrow()); - let new_init = cursor.init_mut().len(); let filled = sliced_buf.len(); // cursor / sliced_buf / ibuf must drop here + // SAFETY: filled bytes have been filled and therefore initialized unsafe { - // SAFETY: filled bytes have been filled and therefore initialized - buf.advance_unchecked(filled); - // SAFETY: new_init bytes of buf's unfilled buffer have been initialized - buf.set_init(new_init); + buf.advance(filled); } self.limit -= filled as u64; diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index b22988d4a8a9..e14e6432eafa 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -209,15 +209,6 @@ fn read_buf_exact() { assert_eq!(c.read_buf_exact(buf.unfilled()).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); } -#[test] -#[should_panic] -fn borrowed_cursor_advance_overflow() { - let mut buf = [0; 512]; - let mut buf = BorrowedBuf::from(&mut buf[..]); - buf.unfilled().advance(1); - buf.unfilled().advance(usize::MAX); -} - #[test] fn take_eof() { struct R; diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index 0410df3ef1a3..a09c8bc06930 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -283,7 +283,7 @@ fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { // SAFETY: No uninit bytes are being written. unsafe { buf.as_mut() }.write_filled(self.byte); // SAFETY: the entire unfilled portion of buf has been initialized. - unsafe { buf.advance_unchecked(buf.capacity()) }; + unsafe { buf.advance(buf.capacity()) }; Ok(()) } diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs index d0f106d7af41..92dbc3919bea 100644 --- a/library/std/src/io/util/tests.rs +++ b/library/std/src/io/util/tests.rs @@ -75,43 +75,36 @@ fn empty_reads() { let mut buf: BorrowedBuf<'_> = buf.into(); e.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit()]; let mut buf: BorrowedBuf<'_> = buf.into(); e.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; let mut buf: BorrowedBuf<'_> = buf.into(); e.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; let mut buf: BorrowedBuf<'_> = buf.into(); Read::by_ref(&mut e).read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [MaybeUninit<_>] = &mut []; let mut buf: BorrowedBuf<'_> = buf.into(); e.read_buf_exact(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit()]; let mut buf: BorrowedBuf<'_> = buf.into(); assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; let mut buf: BorrowedBuf<'_> = buf.into(); assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; let mut buf: BorrowedBuf<'_> = buf.into(); @@ -120,7 +113,6 @@ fn empty_reads() { ErrorKind::UnexpectedEof, ); assert_eq!(buf.len(), 0); - assert_eq!(buf.init_len(), 0); let mut buf = Vec::new(); assert_eq!(e.read_to_end(&mut buf).unwrap(), 0); diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 7c7ef7b2f701..4787f8a1040b 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -315,8 +315,6 @@ fn read_buf() { let mut buf = BorrowedBuf::from(buf.as_mut_slice()); t!(s.read_buf(buf.unfilled())); assert_eq!(buf.filled(), &[1, 2, 3, 4]); - // TcpStream::read_buf should omit buffer initialization. - assert_eq!(buf.init_len(), 4); t.join().ok().expect("thread panicked"); }) diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index 12c5130defe5..c8a83edffe42 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -188,10 +188,8 @@ fn child_stdout_read_buf() { // ChildStdout::read_buf should omit buffer initialization. if cfg!(target_os = "windows") { assert_eq!(buf.filled(), b"abc\r\n"); - assert_eq!(buf.init_len(), 5); } else { assert_eq!(buf.filled(), b"abc\n"); - assert_eq!(buf.init_len(), 4); }; } diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index 2b2dfe48e89e..a631e1d91393 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -185,7 +185,7 @@ pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { // SAFETY: `ret` bytes were written to the initialized portion of the buffer unsafe { - cursor.advance_unchecked(ret as usize); + cursor.advance(ret as usize); } Ok(()) } @@ -203,7 +203,7 @@ pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Re // SAFETY: `ret` bytes were written to the initialized portion of the buffer unsafe { - cursor.advance_unchecked(ret as usize); + cursor.advance(ret as usize); } Ok(()) } diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index 559e27604a9d..c892daf0d39c 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -293,7 +293,7 @@ fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Resu ) })?; unsafe { - buf.advance_unchecked(ret as usize); + buf.advance(ret as usize); } Ok(()) } From 93cd4f8a0494700a59fb499289ece76b9ff89e51 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 27 Nov 2025 15:25:24 +0100 Subject: [PATCH 191/585] link funding page in `.github/FUNDING.yml` --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000000..6a3ab0c92074 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: ["rust-lang.org/funding"] From 140832aa592997525a94027d2cfe9c6acd7f6bdf Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 15:39:17 +0100 Subject: [PATCH 192/585] update readme wrt never type tests --- tests/ui/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ui/README.md b/tests/ui/README.md index 344b0b2500df..9864d88ceb07 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -941,6 +941,8 @@ Contains a single test. It imports a massive amount of very similar types from a ## `tests/ui/never_type/` +Tests relating to the never type. Most tests are specifically about the never type fallback behavior. + See [Tracking issue for promoting `!` to a type (RFC 1216) #35121](https://github.com/rust-lang/rust/issues/35121). ## `tests/ui/new-range/` From 3432ff9a1da3a6560bcf33fda3cee5061ab4bebc Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 15:39:17 +0100 Subject: [PATCH 193/585] remove test for `T -> !` coercion We used to allow `T -> !` coercions (yes!! not `! -> T`) in unreachable code. This was later removed during 2018 stabilization attempt, see: - https://github.com/rust-lang/rust/issues/40800 - https://github.com/rust-lang/rust/pull/47630/commits/59688e119e1b9c2506fa9173728ae88eb196bf5e - https://github.com/rust-lang/rust/issues/46325 I've kept `tests/ui/coercion/coerce-to-bang-cast.rs`, as that is a reasonable test for us *not* having `-> !` coercions. --- tests/ui/coercion/coerce-to-bang.rs | 79 -------------- tests/ui/coercion/coerce-to-bang.stderr | 130 ------------------------ 2 files changed, 209 deletions(-) delete mode 100644 tests/ui/coercion/coerce-to-bang.rs delete mode 100644 tests/ui/coercion/coerce-to-bang.stderr diff --git a/tests/ui/coercion/coerce-to-bang.rs b/tests/ui/coercion/coerce-to-bang.rs deleted file mode 100644 index 1e06934d09f9..000000000000 --- a/tests/ui/coercion/coerce-to-bang.rs +++ /dev/null @@ -1,79 +0,0 @@ -#![feature(never_type)] - -fn foo(x: usize, y: !, z: usize) { } - -fn call_foo_a() { - foo(return, 22, 44); - //~^ ERROR mismatched types -} - -fn call_foo_b() { - // Divergence happens in the argument itself, definitely ok. - foo(22, return, 44); -} - -fn call_foo_c() { - // This test fails because the divergence happens **after** the - // coercion to `!`: - foo(22, 44, return); //~ ERROR mismatched types -} - -fn call_foo_d() { - // This test passes because `a` has type `!`: - let a: ! = return; - let b = 22; - let c = 44; - foo(a, b, c); // ... and hence a reference to `a` is expected to diverge. - //~^ ERROR mismatched types -} - -fn call_foo_e() { - // This test probably could pass but we don't *know* that `a` - // has type `!` so we don't let it work. - let a = return; - let b = 22; - let c = 44; - foo(a, b, c); //~ ERROR mismatched types -} - -fn call_foo_f() { - // This fn fails because `a` has type `usize`, and hence a - // reference to is it **not** considered to diverge. - let a: usize = return; - let b = 22; - let c = 44; - foo(a, b, c); //~ ERROR mismatched types -} - -fn array_a() { - // Return is coerced to `!` just fine, but `22` cannot be. - let x: [!; 2] = [return, 22]; //~ ERROR mismatched types -} - -fn array_b() { - // Error: divergence has not yet occurred. - let x: [!; 2] = [22, return]; //~ ERROR mismatched types -} - -fn tuple_a() { - // No divergence at all. - let x: (usize, !, usize) = (22, 44, 66); //~ ERROR mismatched types -} - -fn tuple_b() { - // Divergence happens before coercion: OK - let x: (usize, !, usize) = (return, 44, 66); - //~^ ERROR mismatched types -} - -fn tuple_c() { - // Divergence happens before coercion: OK - let x: (usize, !, usize) = (22, return, 66); -} - -fn tuple_d() { - // Error: divergence happens too late - let x: (usize, !, usize) = (22, 44, return); //~ ERROR mismatched types -} - -fn main() { } diff --git a/tests/ui/coercion/coerce-to-bang.stderr b/tests/ui/coercion/coerce-to-bang.stderr deleted file mode 100644 index 3c737358adc7..000000000000 --- a/tests/ui/coercion/coerce-to-bang.stderr +++ /dev/null @@ -1,130 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:6:17 - | -LL | foo(return, 22, 44); - | --- ^^ expected `!`, found integer - | | - | arguments to this function are incorrect - | - = note: expected type `!` - found type `{integer}` -note: function defined here - --> $DIR/coerce-to-bang.rs:3:4 - | -LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ ---- - -error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:18:13 - | -LL | foo(22, 44, return); - | --- ^^ expected `!`, found integer - | | - | arguments to this function are incorrect - | - = note: expected type `!` - found type `{integer}` -note: function defined here - --> $DIR/coerce-to-bang.rs:3:4 - | -LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ ---- - -error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:26:12 - | -LL | foo(a, b, c); // ... and hence a reference to `a` is expected to diverge. - | --- ^ expected `!`, found integer - | | - | arguments to this function are incorrect - | - = note: expected type `!` - found type `{integer}` -note: function defined here - --> $DIR/coerce-to-bang.rs:3:4 - | -LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ ---- - -error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:36:12 - | -LL | foo(a, b, c); - | --- ^ expected `!`, found integer - | | - | arguments to this function are incorrect - | - = note: expected type `!` - found type `{integer}` -note: function defined here - --> $DIR/coerce-to-bang.rs:3:4 - | -LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ ---- - -error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:45:12 - | -LL | foo(a, b, c); - | --- ^ expected `!`, found integer - | | - | arguments to this function are incorrect - | - = note: expected type `!` - found type `{integer}` -note: function defined here - --> $DIR/coerce-to-bang.rs:3:4 - | -LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ ---- - -error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:50:21 - | -LL | let x: [!; 2] = [return, 22]; - | ------ ^^^^^^^^^^^^ expected `[!; 2]`, found `[{integer}; 2]` - | | - | expected due to this - | - = note: expected array `[!; 2]` - found array `[{integer}; 2]` - -error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:55:22 - | -LL | let x: [!; 2] = [22, return]; - | ^^ expected `!`, found integer - | - = note: expected type `!` - found type `{integer}` - -error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:60:37 - | -LL | let x: (usize, !, usize) = (22, 44, 66); - | ^^ expected `!`, found integer - | - = note: expected type `!` - found type `{integer}` - -error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:65:41 - | -LL | let x: (usize, !, usize) = (return, 44, 66); - | ^^ expected `!`, found integer - | - = note: expected type `!` - found type `{integer}` - -error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:76:37 - | -LL | let x: (usize, !, usize) = (22, 44, return); - | ^^ expected `!`, found integer - | - = note: expected type `!` - found type `{integer}` - -error: aborting due to 10 previous errors - -For more information about this error, try `rustc --explain E0308`. From e6d2b2add76bbe223d20134583ccc003a80fc025 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 16:56:42 +0100 Subject: [PATCH 194/585] refactor `Box dyn Error>` regression test --- .../coerce-issue-49593-box-never.e2021.stderr | 19 ++++++ .../coercion/coerce-issue-49593-box-never.rs | 62 +++++++------------ 2 files changed, 40 insertions(+), 41 deletions(-) create mode 100644 tests/ui/coercion/coerce-issue-49593-box-never.e2021.stderr diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.e2021.stderr b/tests/ui/coercion/coerce-issue-49593-box-never.e2021.stderr new file mode 100644 index 000000000000..214c37febc06 --- /dev/null +++ b/tests/ui/coercion/coerce-issue-49593-box-never.e2021.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `(): std::error::Error` is not satisfied + --> $DIR/coerce-issue-49593-box-never.rs:28:5 + | +LL | Box::new(x) + | ^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` + | + = note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>` + +error[E0277]: the trait bound `(): std::error::Error` is not satisfied + --> $DIR/coerce-issue-49593-box-never.rs:33:5 + | +LL | raw_ptr(x) + | ^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` + | + = note: required for the cast from `*mut ()` to `*mut (dyn std::error::Error + 'static)` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.rs b/tests/ui/coercion/coerce-issue-49593-box-never.rs index 6706d07e1f76..751450a7fb43 100644 --- a/tests/ui/coercion/coerce-issue-49593-box-never.rs +++ b/tests/ui/coercion/coerce-issue-49593-box-never.rs @@ -1,57 +1,37 @@ -//@ revisions: nofallback fallback -//@[fallback] edition: 2024 -//@[fallback] check-pass +// Regression test for . +// +// This checks that we can construct `Box` by calling `Box::new` +// with a value of the never type. And similarly for raw pointers. +// +// This used to fail because we tried to coerce `! -> dyn Error`, which then +// failed because we were trying to pass an unsized value by value, etc. +// +// On edition <= 2021 this currently fails because of never type fallback to +// unit. +// +//@ revisions: e2021 e2024 +//@[e2021] edition: 2021 +//@[e2024] edition: 2024 +// +//@[e2024] check-pass #![feature(never_type)] use std::error::Error; use std::mem; -fn raw_ptr_box(t: T) -> *mut T { +fn raw_ptr(t: T) -> *mut T { panic!() } fn foo(x: !) -> Box { - // Method resolution will generate new inference vars and relate them. - // Thus fallback will not fall back to `!`, but `()` instead. - Box::<_ /* ! */>::new(x) - //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied + Box::new(x) + //[e2021]~^ ERROR trait bound `(): std::error::Error` is not satisfied } fn foo_raw_ptr(x: !) -> *mut dyn Error { - /* *mut $0 is coerced to *mut Error here */ - raw_ptr_box::<_ /* ! */>(x) - //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied -} - -fn no_coercion(d: *mut dyn Error) -> *mut dyn Error { - /* an unsize coercion won't compile here, and it is indeed not used - because there is nothing requiring the _ to be Sized */ - d as *mut _ -} - -trait Xyz {} -struct S; -struct T; -impl Xyz for S {} -impl Xyz for T {} - -fn foo_no_never() { - let mut x /* : Option */ = None; - let mut first_iter = false; - loop { - if !first_iter { - let y: Box - = /* Box<$0> is coerced to Box here */ Box::new(x.unwrap()); - } - - x = Some(S); - first_iter = true; - } - - let mut y: Option = None; - // assert types are equal - mem::swap(&mut x, &mut y); + raw_ptr(x) + //[e2021]~^ ERROR trait bound `(): std::error::Error` is not satisfied } fn main() {} From 0cbb9e68917a54fde791174dd7424e010309f088 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 17:35:27 +0100 Subject: [PATCH 195/585] expand never type gate test --- .../feature-gates/feature-gate-never_type.rs | 79 ++++++++++++++---- .../feature-gate-never_type.stderr | 80 ++++++++++++------- 2 files changed, 112 insertions(+), 47 deletions(-) diff --git a/tests/ui/feature-gates/feature-gate-never_type.rs b/tests/ui/feature-gates/feature-gate-never_type.rs index f5d28a4877fd..c678d55acd0f 100644 --- a/tests/ui/feature-gates/feature-gate-never_type.rs +++ b/tests/ui/feature-gates/feature-gate-never_type.rs @@ -1,26 +1,71 @@ // Test that ! errors when used in illegal positions with feature(never_type) disabled -trait Foo { - type Wub; +mod ungated { + //! Functions returning `!` directly (as in `-> !`) and function pointers doing the same are + //! allowed with no gates. + + fn panic() -> ! { + panic!(); + } + + fn takes_fn_ptr(x: fn() -> !) -> ! { + x() + } } -type Ma = (u32, !, i32); //~ ERROR type is experimental -type Meeshka = Vec; //~ ERROR type is experimental -type Mow = &'static fn(!) -> !; //~ ERROR type is experimental -type Skwoz = &'static mut !; //~ ERROR type is experimental +mod gated { + //! All other mentions of the type are gated. -impl Foo for Meeshka { - type Wub = !; //~ ERROR type is experimental + trait Foo { + type Wub; + } + + type Ma = (u32, !, i32); //~ ERROR type is experimental + type Meeshka = Vec; //~ ERROR type is experimental + type Mow = &'static fn(!) -> !; //~ ERROR type is experimental + type Skwoz = &'static mut !; //~ ERROR type is experimental + type Meow = fn() -> Result<(), !>; //~ ERROR type is experimental + + impl Foo for Meeshka { + type Wub = !; //~ ERROR type is experimental + } + + fn look_ma_no_feature_gate !>() {} //~ ERROR type is experimental + + fn tadam(f: &dyn Fn() -> !) {} //~ ERROR type is experimental + + fn toudoum() -> impl Fn() -> ! { //~ ERROR type is experimental + || panic!() + } + + fn infallible() -> Result<(), !> { //~ ERROR type is experimental + Ok(()) + } } -fn look_ma_no_feature_gate !>() {} //~ ERROR type is experimental -fn tadam(f: &dyn Fn() -> !) {} //~ ERROR type is experimental -fn panic() -> ! { - panic!(); -} -fn toudoum() -> impl Fn() -> ! { //~ ERROR type is experimental - panic +mod hack { + //! There is a hack which, by exploiting the fact that `fn() -> !` can be named stably and that + //! type system does not interact with stability, allows one to mention the never type while + //! avoiding any and all feature gates. It is generally considered a "hack"/compiler bug, and + //! thus users of this hack resign stability guarantees. However, fixing this is more trouble + //! than good. + + trait F { + type Ret; + } + + impl F for fn() -> T { + type Ret = T; + } + + type Never = ! as F>::Ret; + + fn damn( + never: Never, + _: &dyn Fn() -> Never, + ) -> (impl Fn() -> Never, &'static mut Never, Never, u8) { + (|| never, never, never, never) + } } -fn main() { -} +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-never_type.stderr b/tests/ui/feature-gates/feature-gate-never_type.stderr index 33e4e019b18d..475aac433b84 100644 --- a/tests/ui/feature-gates/feature-gate-never_type.stderr +++ b/tests/ui/feature-gates/feature-gate-never_type.stderr @@ -1,27 +1,17 @@ error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:7:17 + --> $DIR/feature-gate-never_type.rs:23:21 | -LL | type Ma = (u32, !, i32); - | ^ +LL | type Ma = (u32, !, i32); + | ^ | = note: see issue #35121 for more information = help: add `#![feature(never_type)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:8:20 + --> $DIR/feature-gate-never_type.rs:24:24 | -LL | type Meeshka = Vec; - | ^ - | - = note: see issue #35121 for more information - = help: add `#![feature(never_type)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:9:24 - | -LL | type Mow = &'static fn(!) -> !; +LL | type Meeshka = Vec; | ^ | = note: see issue #35121 for more information @@ -29,55 +19,85 @@ LL | type Mow = &'static fn(!) -> !; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:10:27 + --> $DIR/feature-gate-never_type.rs:25:28 | -LL | type Skwoz = &'static mut !; - | ^ +LL | type Mow = &'static fn(!) -> !; + | ^ | = note: see issue #35121 for more information = help: add `#![feature(never_type)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:13:16 + --> $DIR/feature-gate-never_type.rs:26:31 | -LL | type Wub = !; - | ^ +LL | type Skwoz = &'static mut !; + | ^ | = note: see issue #35121 for more information = help: add `#![feature(never_type)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:16:43 + --> $DIR/feature-gate-never_type.rs:27:36 | -LL | fn look_ma_no_feature_gate !>() {} - | ^ +LL | type Meow = fn() -> Result<(), !>; + | ^ | = note: see issue #35121 for more information = help: add `#![feature(never_type)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:17:26 + --> $DIR/feature-gate-never_type.rs:30:20 | -LL | fn tadam(f: &dyn Fn() -> !) {} - | ^ +LL | type Wub = !; + | ^ | = note: see issue #35121 for more information = help: add `#![feature(never_type)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:21:30 + --> $DIR/feature-gate-never_type.rs:33:47 | -LL | fn toudoum() -> impl Fn() -> ! { +LL | fn look_ma_no_feature_gate !>() {} + | ^ + | + = note: see issue #35121 for more information + = help: add `#![feature(never_type)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `!` type is experimental + --> $DIR/feature-gate-never_type.rs:35:30 + | +LL | fn tadam(f: &dyn Fn() -> !) {} | ^ | = note: see issue #35121 for more information = help: add `#![feature(never_type)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 8 previous errors +error[E0658]: the `!` type is experimental + --> $DIR/feature-gate-never_type.rs:37:34 + | +LL | fn toudoum() -> impl Fn() -> ! { + | ^ + | + = note: see issue #35121 for more information + = help: add `#![feature(never_type)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `!` type is experimental + --> $DIR/feature-gate-never_type.rs:41:35 + | +LL | fn infallible() -> Result<(), !> { + | ^ + | + = note: see issue #35121 for more information + = help: add `#![feature(never_type)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0658`. From 98430c4d9d547a7e8dc8171247b6eed09427b922 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 19:00:43 +0100 Subject: [PATCH 196/585] remove unused features from some tests --- tests/ui/lint/unused/issue-103320-must-use-ops.rs | 1 - tests/ui/lint/unused/issue-103320-must-use-ops.stderr | 10 +++++----- tests/ui/never_type/auto-traits.rs | 1 - tests/ui/process/process-panic-after-fork.rs | 1 - 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/ui/lint/unused/issue-103320-must-use-ops.rs b/tests/ui/lint/unused/issue-103320-must-use-ops.rs index 5749fef46908..bb399fc1aa29 100644 --- a/tests/ui/lint/unused/issue-103320-must-use-ops.rs +++ b/tests/ui/lint/unused/issue-103320-must-use-ops.rs @@ -1,7 +1,6 @@ //@ check-pass #![warn(unused_must_use)] -#![feature(never_type)] use std::ops::Add; use std::ops::Sub; diff --git a/tests/ui/lint/unused/issue-103320-must-use-ops.stderr b/tests/ui/lint/unused/issue-103320-must-use-ops.stderr index 57439ec6a8fd..0f32757ed20f 100644 --- a/tests/ui/lint/unused/issue-103320-must-use-ops.stderr +++ b/tests/ui/lint/unused/issue-103320-must-use-ops.stderr @@ -1,5 +1,5 @@ warning: unused return value of `add` that must be used - --> $DIR/issue-103320-must-use-ops.rs:16:5 + --> $DIR/issue-103320-must-use-ops.rs:15:5 | LL | x.add(4); | ^^^^^^^^ @@ -16,7 +16,7 @@ LL | let _ = x.add(4); | +++++++ warning: unused return value of `sub` that must be used - --> $DIR/issue-103320-must-use-ops.rs:18:5 + --> $DIR/issue-103320-must-use-ops.rs:17:5 | LL | x.sub(4); | ^^^^^^^^ @@ -28,7 +28,7 @@ LL | let _ = x.sub(4); | +++++++ warning: unused return value of `mul` that must be used - --> $DIR/issue-103320-must-use-ops.rs:20:5 + --> $DIR/issue-103320-must-use-ops.rs:19:5 | LL | x.mul(4); | ^^^^^^^^ @@ -40,7 +40,7 @@ LL | let _ = x.mul(4); | +++++++ warning: unused return value of `div` that must be used - --> $DIR/issue-103320-must-use-ops.rs:22:5 + --> $DIR/issue-103320-must-use-ops.rs:21:5 | LL | x.div(4); | ^^^^^^^^ @@ -52,7 +52,7 @@ LL | let _ = x.div(4); | +++++++ warning: unused return value of `rem` that must be used - --> $DIR/issue-103320-must-use-ops.rs:24:5 + --> $DIR/issue-103320-must-use-ops.rs:23:5 | LL | x.rem(4); | ^^^^^^^^ diff --git a/tests/ui/never_type/auto-traits.rs b/tests/ui/never_type/auto-traits.rs index 8a2b9a145866..19554f13b0ba 100644 --- a/tests/ui/never_type/auto-traits.rs +++ b/tests/ui/never_type/auto-traits.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(auto_traits)] -#![feature(negative_impls)] #![feature(never_type)] fn main() { diff --git a/tests/ui/process/process-panic-after-fork.rs b/tests/ui/process/process-panic-after-fork.rs index 154ff51878d6..4632d3b61f7b 100644 --- a/tests/ui/process/process-panic-after-fork.rs +++ b/tests/ui/process/process-panic-after-fork.rs @@ -8,7 +8,6 @@ //@ ignore-backends: gcc #![feature(rustc_private)] -#![feature(never_type)] #![feature(panic_always_abort)] #![allow(invalid_from_utf8)] From 93b5361202665c41970646569df4236751297094 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 2 Dec 2025 05:22:00 -0500 Subject: [PATCH 197/585] ci: Increase the benchmark rustc version to 2025-12-01 Zerocopy (an indirect test dependency) has started requiring recently-stabilized features, so upgrade our benchmark toolchain to match. --- library/compiler-builtins/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 16f958c881d3..c8faecfcb2cc 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -13,7 +13,7 @@ env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings RUST_BACKTRACE: full - BENCHMARK_RUSTC: nightly-2025-05-28 # Pin the toolchain for reproducable results + BENCHMARK_RUSTC: nightly-2025-12-01 # Pin the toolchain for reproducable results jobs: # Determine which tests should be run based on changed files. From 5e0b1533469354abe4f2e447598cd08aea1c002c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 2 Dec 2025 11:47:22 +0100 Subject: [PATCH 198/585] Fix example which wrongly implied that the upper bound of edition ranges was inclusive And explicitly state the fact that the upper bound is exclusive since only giving an example is too implicit. --- src/doc/rustc-dev-guide/src/tests/directives.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 4226c1750ef2..7cf5869b719c 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -273,7 +273,9 @@ This affects which edition is used by `./x test` to run the test. For example: - A test with the `//@ edition: 2018` directive will only run under the 2018 edition. -- A test with the `//@ edition: 2015..2021` directive can be run under the 2015, 2018, and 2021 editions. +- A test with the `//@ edition: 2015..2021` directive can be run under the 2015 and the 2018 edition, + so the upper bound is exclusive just like in Rust + (note that there's no equivalent to Rust's `..=` where the upper bound is inclusive). However, CI will only run the test with the lowest edition in the range (which is 2015 in this example). - A test with the `//@ edition: 2018..` directive will run under 2018 edition or greater. However, CI will only run the test with the lowest edition in the range (which is 2018 in this example). From 94a62dc6045f9bb027128119d55d54c593c5d795 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Tue, 2 Dec 2025 10:59:26 +0000 Subject: [PATCH 199/585] Prepare for merging from rust-lang/rust This updates the rust-version file to 47cd7120d9b4e1b64eb27c87522a07888197fae8. --- library/compiler-builtins/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version index 8854fb95997b..71fbbbaa984f 100644 --- a/library/compiler-builtins/rust-version +++ b/library/compiler-builtins/rust-version @@ -1 +1 @@ -caccb4d0368bd918ef6668af8e13834d07040417 +47cd7120d9b4e1b64eb27c87522a07888197fae8 From 5dec6b3a56b8852f491e7758ff4c1bed6090a3a3 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 19:56:13 +0100 Subject: [PATCH 200/585] refactor test for note on `!: Tr` error --- .../defaulted-never-note.e2021.stderr | 18 +++++ .../defaulted-never-note.e2024.stderr | 62 +++++++++++++++ .../defaulted-never-note.fallback.stderr | 24 ------ .../defaulted-never-note.nofallback.stderr | 18 ----- tests/ui/never_type/defaulted-never-note.rs | 77 ++++++++++++------- 5 files changed, 129 insertions(+), 70 deletions(-) create mode 100644 tests/ui/never_type/defaulted-never-note.e2021.stderr create mode 100644 tests/ui/never_type/defaulted-never-note.e2024.stderr delete mode 100644 tests/ui/never_type/defaulted-never-note.fallback.stderr delete mode 100644 tests/ui/never_type/defaulted-never-note.nofallback.stderr diff --git a/tests/ui/never_type/defaulted-never-note.e2021.stderr b/tests/ui/never_type/defaulted-never-note.e2021.stderr new file mode 100644 index 000000000000..96013df5fb0d --- /dev/null +++ b/tests/ui/never_type/defaulted-never-note.e2021.stderr @@ -0,0 +1,18 @@ +Future incompatibility report: Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/defaulted-never-note.rs:38:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = help: specify the types explicitly +note: in edition 2024, the requirement `!: OnlyUnit` will fail + --> $DIR/defaulted-never-note.rs:40:19 + | +LL | requires_unit(x); + | ^ +help: use `()` annotations to avoid fallback changes + | +LL | let x: () = return; + | ++++ + diff --git a/tests/ui/never_type/defaulted-never-note.e2024.stderr b/tests/ui/never_type/defaulted-never-note.e2024.stderr new file mode 100644 index 000000000000..d8c6059a67d3 --- /dev/null +++ b/tests/ui/never_type/defaulted-never-note.e2024.stderr @@ -0,0 +1,62 @@ +error[E0277]: the trait bound `!: OnlyUnit` is not satisfied + --> $DIR/defaulted-never-note.rs:40:19 + | +LL | requires_unit(x); + | ------------- ^ the trait `OnlyUnit` is not implemented for `!` + | | + | required by a bound introduced by this call + | +help: the trait `OnlyUnit` is implemented for `()` + --> $DIR/defaulted-never-note.rs:13:1 + | +LL | impl OnlyUnit for () {} + | ^^^^^^^^^^^^^^^^^^^^ + = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 for more information) + = help: you might have intended to use the type `()` here instead +note: required by a bound in `requires_unit` + --> $DIR/defaulted-never-note.rs:16:26 + | +LL | fn requires_unit(_: impl OnlyUnit) {} + | ^^^^^^^^ required by this bound in `requires_unit` + +error[E0277]: the trait bound `!: OnlyU32` is not satisfied + --> $DIR/defaulted-never-note.rs:48:18 + | +LL | requires_u32(x); + | ------------ ^ the trait `OnlyU32` is not implemented for `!` + | | + | required by a bound introduced by this call + | +help: the trait `OnlyU32` is implemented for `u32` + --> $DIR/defaulted-never-note.rs:23:1 + | +LL | impl OnlyU32 for u32 {} + | ^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `requires_u32` + --> $DIR/defaulted-never-note.rs:26:25 + | +LL | fn requires_u32(_: impl OnlyU32) {} + | ^^^^^^^ required by this bound in `requires_u32` + +error[E0277]: the trait bound `!: Nothing` is not satisfied + --> $DIR/defaulted-never-note.rs:54:22 + | +LL | requires_nothing(x); + | ---------------- ^ the trait `Nothing` is not implemented for `!` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/defaulted-never-note.rs:31:1 + | +LL | trait Nothing {} + | ^^^^^^^^^^^^^ +note: required by a bound in `requires_nothing` + --> $DIR/defaulted-never-note.rs:34:29 + | +LL | fn requires_nothing(_: impl Nothing) {} + | ^^^^^^^ required by this bound in `requires_nothing` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/never_type/defaulted-never-note.fallback.stderr b/tests/ui/never_type/defaulted-never-note.fallback.stderr deleted file mode 100644 index 81b01052ba39..000000000000 --- a/tests/ui/never_type/defaulted-never-note.fallback.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0277]: the trait bound `!: ImplementedForUnitButNotNever` is not satisfied - --> $DIR/defaulted-never-note.rs:27:9 - | -LL | foo(_x); - | --- ^^ the trait `ImplementedForUnitButNotNever` is not implemented for `!` - | | - | required by a bound introduced by this call - | -help: the trait `ImplementedForUnitButNotNever` is implemented for `()` - --> $DIR/defaulted-never-note.rs:20:1 - | -LL | impl ImplementedForUnitButNotNever for () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 for more information) - = help: you might have intended to use the type `()` here instead -note: required by a bound in `foo` - --> $DIR/defaulted-never-note.rs:22:11 - | -LL | fn foo(_t: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/never_type/defaulted-never-note.nofallback.stderr b/tests/ui/never_type/defaulted-never-note.nofallback.stderr deleted file mode 100644 index f084985153c6..000000000000 --- a/tests/ui/never_type/defaulted-never-note.nofallback.stderr +++ /dev/null @@ -1,18 +0,0 @@ -Future incompatibility report: Future breakage diagnostic: -warning: this function depends on never type fallback being `()` - --> $DIR/defaulted-never-note.rs:25:1 - | -LL | fn smeg() { - | ^^^^^^^^^ - | - = help: specify the types explicitly -note: in edition 2024, the requirement `!: ImplementedForUnitButNotNever` will fail - --> $DIR/defaulted-never-note.rs:27:9 - | -LL | foo(_x); - | ^^ -help: use `()` annotations to avoid fallback changes - | -LL | let _x: () = return; - | ++++ - diff --git a/tests/ui/never_type/defaulted-never-note.rs b/tests/ui/never_type/defaulted-never-note.rs index 71b3e0bcf80a..79510bbfa0dc 100644 --- a/tests/ui/never_type/defaulted-never-note.rs +++ b/tests/ui/never_type/defaulted-never-note.rs @@ -1,37 +1,58 @@ -//@ revisions: nofallback fallback -//@[fallback] edition: 2024 -//@[nofallback] run-pass -//@[fallback] check-fail - +// Test diagnostic for the case where a trait is not implemented for `!`. If it is implemented +// for `()`, we want to add a note saying that this might be caused by a breaking change in the +// compiler. +// +//@ revisions: e2021 e2024 +//@[e2021] edition: 2021 +//@[e2024] edition: 2024 +//@[e2021] run-pass #![expect(dependency_on_unit_never_type_fallback, unused)] -trait Deserialize: Sized { - fn deserialize() -> Result; -} +trait OnlyUnit {} -impl Deserialize for () { - fn deserialize() -> Result<(), String> { - Ok(()) - } -} +impl OnlyUnit for () {} +//[e2024]~^ help: trait `OnlyUnit` is implemented for `()` -trait ImplementedForUnitButNotNever {} +fn requires_unit(_: impl OnlyUnit) {} +//[e2024]~^ note: required by this bound in `requires_unit` +//[e2024]~| note: required by a bound in `requires_unit` -impl ImplementedForUnitButNotNever for () {} //[fallback]~ HELP trait `ImplementedForUnitButNotNever` is implemented for `()` -fn foo(_t: T) {} -//[fallback]~^ note: required by this bound in `foo` -//[fallback]~| note: required by a bound in `foo` -fn smeg() { - let _x = return; - foo(_x); - //[fallback]~^ ERROR the trait bound - //[fallback]~| NOTE the trait `ImplementedForUnitButNotNever` is not implemented - //[fallback]~| NOTE this error might have been caused - //[fallback]~| NOTE required by a bound introduced by this call - //[fallback]~| HELP you might have intended to use the type `()` -} +trait OnlyU32 {} + +impl OnlyU32 for u32 {} +//[e2024]~^ help: the trait `OnlyU32` is implemented for `u32` + +fn requires_u32(_: impl OnlyU32) {} +//[e2024]~^ note: required by this bound in `requires_u32` +//[e2024]~| note: required by a bound in `requires_u32` + + +trait Nothing {} +//[e2024]~^ help: this trait has no implementations, consider adding one + +fn requires_nothing(_: impl Nothing) {} +//[e2024]~^ note: required by this bound in `requires_nothing` +//[e2024]~| note: required by a bound in `requires_nothing` fn main() { - smeg(); + let x = return; + requires_unit(x); + //[e2024]~^ error: the trait bound `!: OnlyUnit` is not satisfied + //[e2024]~| note: the trait `OnlyUnit` is not implemented for `!` + //[e2024]~| note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 for more information) + //[e2024]~| note: required by a bound introduced by this call + //[e2024]~| help: you might have intended to use the type `()` + + #[cfg(e2024)] + requires_u32(x); + //[e2024]~^ error: the trait bound `!: OnlyU32` is not satisfied + //[e2024]~| note: the trait `OnlyU32` is not implemented for `!` + //[e2024]~| note: required by a bound introduced by this call + + #[cfg(e2024)] + requires_nothing(x); + //[e2024]~^ error: the trait bound `!: Nothing` is not satisfied + //[e2024]~| note: the trait `Nothing` is not implemented for `!` + //[e2024]~| note: required by a bound introduced by this call } From 8c8d93071417427a69d0a3b83acc8b163bc5e5b5 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 17:43:01 +0100 Subject: [PATCH 201/585] delete a duplicate test Duplicate of `from_infer_breaking_with_unit_fallback.rs` and `question_mark_from_never.rs` --- ...lue-fallback-issue-66757.nofallback.stderr | 17 ----------- .../never-value-fallback-issue-66757.rs | 30 ------------------- 2 files changed, 47 deletions(-) delete mode 100644 tests/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr delete mode 100644 tests/ui/never_type/never-value-fallback-issue-66757.rs diff --git a/tests/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr b/tests/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr deleted file mode 100644 index d00118cd61da..000000000000 --- a/tests/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0277]: the trait bound `E: From<()>` is not satisfied - --> $DIR/never-value-fallback-issue-66757.rs:27:6 - | -LL | >::from(never); - | ^ unsatisfied trait bound - | -help: the trait `From<()>` is not implemented for `E` - but trait `From` is implemented for it - --> $DIR/never-value-fallback-issue-66757.rs:16:1 - | -LL | impl From for E { - | ^^^^^^^^^^^^^^^^^^ - = help: for that trait implementation, expected `!`, found `()` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/never_type/never-value-fallback-issue-66757.rs b/tests/ui/never_type/never-value-fallback-issue-66757.rs deleted file mode 100644 index a113d1b13a4a..000000000000 --- a/tests/ui/never_type/never-value-fallback-issue-66757.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Regression test for #66757 -// -// Test than when you have a `!` value (e.g., the local variable -// never) and an uninferred variable (here the argument to `From`) it -// doesn't fallback to `()` but rather `!`. -// -//@ revisions: nofallback fallback -//@[fallback] edition: 2024 -//@[fallback] run-pass -//@[nofallback] check-fail - -#![feature(never_type)] - -struct E; - -impl From for E { - fn from(_: !) -> E { - E - } -} - -#[allow(unreachable_code)] -#[allow(dead_code)] -#[allow(unused_must_use)] -fn foo(never: !) { - >::from(never); // Ok - >::from(never); //[nofallback]~ ERROR trait bound `E: From<()>` is not satisfied -} - -fn main() { } From 109b6de8fc0c41b3814563f1344d1bb39fdbef50 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 23:05:54 +0100 Subject: [PATCH 202/585] remove outdated tests I don't think they are testing anything anymore --- tests/ui/never_type/impl_trait_fallback.rs | 11 ------- .../ui/never_type/impl_trait_fallback.stderr | 14 -------- tests/ui/never_type/impl_trait_fallback2.rs | 25 -------------- .../ui/never_type/impl_trait_fallback2.stderr | 33 ------------------- tests/ui/never_type/impl_trait_fallback3.rs | 17 ---------- .../ui/never_type/impl_trait_fallback3.stderr | 18 ---------- tests/ui/never_type/impl_trait_fallback4.rs | 26 --------------- .../ui/never_type/impl_trait_fallback4.stderr | 18 ---------- 8 files changed, 162 deletions(-) delete mode 100644 tests/ui/never_type/impl_trait_fallback.rs delete mode 100644 tests/ui/never_type/impl_trait_fallback.stderr delete mode 100644 tests/ui/never_type/impl_trait_fallback2.rs delete mode 100644 tests/ui/never_type/impl_trait_fallback2.stderr delete mode 100644 tests/ui/never_type/impl_trait_fallback3.rs delete mode 100644 tests/ui/never_type/impl_trait_fallback3.stderr delete mode 100644 tests/ui/never_type/impl_trait_fallback4.rs delete mode 100644 tests/ui/never_type/impl_trait_fallback4.stderr diff --git a/tests/ui/never_type/impl_trait_fallback.rs b/tests/ui/never_type/impl_trait_fallback.rs deleted file mode 100644 index dafbd5af9a1e..000000000000 --- a/tests/ui/never_type/impl_trait_fallback.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ check-pass -#![expect(dependency_on_unit_never_type_fallback)] - -fn main() {} - -trait T {} -impl T for () {} - -fn should_ret_unit() -> impl T { - panic!() -} diff --git a/tests/ui/never_type/impl_trait_fallback.stderr b/tests/ui/never_type/impl_trait_fallback.stderr deleted file mode 100644 index bdf6df987832..000000000000 --- a/tests/ui/never_type/impl_trait_fallback.stderr +++ /dev/null @@ -1,14 +0,0 @@ -Future incompatibility report: Future breakage diagnostic: -warning: this function depends on never type fallback being `()` - --> $DIR/impl_trait_fallback.rs:9:1 - | -LL | fn should_ret_unit() -> impl T { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: specify the types explicitly -note: in edition 2024, the requirement `!: T` will fail - --> $DIR/impl_trait_fallback.rs:9:25 - | -LL | fn should_ret_unit() -> impl T { - | ^^^^^^ - diff --git a/tests/ui/never_type/impl_trait_fallback2.rs b/tests/ui/never_type/impl_trait_fallback2.rs deleted file mode 100644 index c7c624bdce6e..000000000000 --- a/tests/ui/never_type/impl_trait_fallback2.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ edition:2015..2021 -#![feature(type_alias_impl_trait)] - -fn main() {} - -trait T {} -impl T for i32 {} - -fn should_ret_unit() -> impl T { - //~^ ERROR `(): T` is not satisfied - panic!() -} - -type Foo = impl T; - -#[define_opaque(Foo)] -fn a() -> Foo { - //~^ ERROR `(): T` is not satisfied - panic!() -} - -#[define_opaque(Foo)] -fn b() -> Foo { - 42 -} diff --git a/tests/ui/never_type/impl_trait_fallback2.stderr b/tests/ui/never_type/impl_trait_fallback2.stderr deleted file mode 100644 index c23b39590a3f..000000000000 --- a/tests/ui/never_type/impl_trait_fallback2.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0277]: the trait bound `(): T` is not satisfied - --> $DIR/impl_trait_fallback2.rs:9:25 - | -LL | fn should_ret_unit() -> impl T { - | ^^^^^^ the trait `T` is not implemented for `()` -LL | -LL | panic!() - | -------- return type was inferred to be `_` here - | -help: the trait `T` is implemented for `i32` - --> $DIR/impl_trait_fallback2.rs:7:1 - | -LL | impl T for i32 {} - | ^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `(): T` is not satisfied - --> $DIR/impl_trait_fallback2.rs:17:11 - | -LL | fn a() -> Foo { - | ^^^ the trait `T` is not implemented for `()` -LL | -LL | panic!() - | -------- return type was inferred to be `_` here - | -help: the trait `T` is implemented for `i32` - --> $DIR/impl_trait_fallback2.rs:7:1 - | -LL | impl T for i32 {} - | ^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/never_type/impl_trait_fallback3.rs b/tests/ui/never_type/impl_trait_fallback3.rs deleted file mode 100644 index 03cd6fc25c2b..000000000000 --- a/tests/ui/never_type/impl_trait_fallback3.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ edition:2015..2021 -#![feature(type_alias_impl_trait)] - -fn main() {} - -trait T { - type Assoc; -} - -type Foo = impl T; - -#[define_opaque(Foo)] -fn a() -> Foo { - //~^ ERROR the trait bound `(): T` is not satisfied - // This is not a defining use, it doesn't actually constrain the opaque type. - panic!() -} diff --git a/tests/ui/never_type/impl_trait_fallback3.stderr b/tests/ui/never_type/impl_trait_fallback3.stderr deleted file mode 100644 index 259aea18d688..000000000000 --- a/tests/ui/never_type/impl_trait_fallback3.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `(): T` is not satisfied - --> $DIR/impl_trait_fallback3.rs:13:11 - | -LL | fn a() -> Foo { - | ^^^ the trait `T` is not implemented for `()` -... -LL | panic!() - | -------- return type was inferred to be `_` here - | -help: this trait has no implementations, consider adding one - --> $DIR/impl_trait_fallback3.rs:6:1 - | -LL | trait T { - | ^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/never_type/impl_trait_fallback4.rs b/tests/ui/never_type/impl_trait_fallback4.rs deleted file mode 100644 index 52ddd74f9161..000000000000 --- a/tests/ui/never_type/impl_trait_fallback4.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ edition:2015..2021 -#![feature(type_alias_impl_trait)] - -trait T { - type Assoc: Cake; -} - -trait Cake: std::fmt::Display { - fn cake() -> Self; -} - -type Foo = impl T; - -fn foo() -> impl T { - //~^ ERROR `(): T` is not satisfied - panic!() -} - -#[define_opaque(Foo)] -fn a() -> Foo { - foo() -} - -fn main() { - println!("{}", ::Assoc::cake()); -} diff --git a/tests/ui/never_type/impl_trait_fallback4.stderr b/tests/ui/never_type/impl_trait_fallback4.stderr deleted file mode 100644 index f9de4b6a4944..000000000000 --- a/tests/ui/never_type/impl_trait_fallback4.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `(): T` is not satisfied - --> $DIR/impl_trait_fallback4.rs:14:13 - | -LL | fn foo() -> impl T { - | ^^^^^^ the trait `T` is not implemented for `()` -LL | -LL | panic!() - | -------- return type was inferred to be `_` here - | -help: this trait has no implementations, consider adding one - --> $DIR/impl_trait_fallback4.rs:4:1 - | -LL | trait T { - | ^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. From 0104d69e4bf6bd1c9d1d66e1e69d72fb0a49cb0b Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 20:14:10 +0100 Subject: [PATCH 203/585] move `tests/ui/{never => never_type}/*` there are only 1 test in that directory, probably created by mistake. --- tests/ui/{never => never_type}/never-type-method-call-15207.rs | 0 .../ui/{never => never_type}/never-type-method-call-15207.stderr | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{never => never_type}/never-type-method-call-15207.rs (100%) rename tests/ui/{never => never_type}/never-type-method-call-15207.stderr (100%) diff --git a/tests/ui/never/never-type-method-call-15207.rs b/tests/ui/never_type/never-type-method-call-15207.rs similarity index 100% rename from tests/ui/never/never-type-method-call-15207.rs rename to tests/ui/never_type/never-type-method-call-15207.rs diff --git a/tests/ui/never/never-type-method-call-15207.stderr b/tests/ui/never_type/never-type-method-call-15207.stderr similarity index 100% rename from tests/ui/never/never-type-method-call-15207.stderr rename to tests/ui/never_type/never-type-method-call-15207.stderr From b1efa8e57973c381419aeff33a858d441e9c4a13 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 23:24:32 +0100 Subject: [PATCH 204/585] stylistic test changes --- tests/ui/never_type/call-fn-never-arg.rs | 2 +- tests/ui/never_type/cast-never.rs | 2 +- .../diverging-fallback-no-leak.e2021.stderr | 18 +++++++++++++ .../diverging-fallback-no-leak.e2024.stderr | 26 +++++++++++++++++++ .../never_type/diverging-fallback-no-leak.rs | 12 +++++---- tests/ui/never_type/eq-never-types.rs | 9 +++---- .../fallback-closure-ret.e2021.stderr | 18 +++++++++++++ .../fallback-closure-ret.e2024.stderr | 24 +++++++++++++++++ tests/ui/never_type/fallback-closure-ret.rs | 16 +++++++----- tests/ui/never_type/impl-for-never.rs | 3 ++- tests/ui/never_type/issue-44402.rs | 11 ++++---- tests/ui/never_type/issue-51506.rs | 2 ++ tests/ui/never_type/issue-51506.stderr | 4 +-- tests/ui/never_type/never-assign-dead-code.rs | 2 +- tests/ui/never_type/never-associated-type.rs | 2 +- tests/ui/never_type/never-in-range-pat.rs | 2 +- tests/ui/never_type/never-type-arg.rs | 2 +- tests/ui/never_type/never_transmute_never.rs | 4 +-- .../ui/never_type/question_mark_from_never.rs | 2 +- tests/ui/never_type/span-bug-issue-121445.rs | 2 ++ .../never_type/span-bug-issue-121445.stderr | 4 +-- 21 files changed, 132 insertions(+), 35 deletions(-) create mode 100644 tests/ui/never_type/diverging-fallback-no-leak.e2021.stderr create mode 100644 tests/ui/never_type/diverging-fallback-no-leak.e2024.stderr create mode 100644 tests/ui/never_type/fallback-closure-ret.e2021.stderr create mode 100644 tests/ui/never_type/fallback-closure-ret.e2024.stderr diff --git a/tests/ui/never_type/call-fn-never-arg.rs b/tests/ui/never_type/call-fn-never-arg.rs index d37f0888b2f0..d64370f2ece6 100644 --- a/tests/ui/never_type/call-fn-never-arg.rs +++ b/tests/ui/never_type/call-fn-never-arg.rs @@ -1,5 +1,5 @@ // Test that we can use a ! for an argument of type ! - +// //@ check-pass #![feature(never_type)] diff --git a/tests/ui/never_type/cast-never.rs b/tests/ui/never_type/cast-never.rs index 34314fcebab0..eaca21018287 100644 --- a/tests/ui/never_type/cast-never.rs +++ b/tests/ui/never_type/cast-never.rs @@ -1,5 +1,5 @@ // Test that we can explicitly cast ! to another type - +// //@ check-pass #![feature(never_type)] diff --git a/tests/ui/never_type/diverging-fallback-no-leak.e2021.stderr b/tests/ui/never_type/diverging-fallback-no-leak.e2021.stderr new file mode 100644 index 000000000000..e67db8c71985 --- /dev/null +++ b/tests/ui/never_type/diverging-fallback-no-leak.e2021.stderr @@ -0,0 +1,18 @@ +Future incompatibility report: Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-no-leak.rs:17:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Test` will fail + --> $DIR/diverging-fallback-no-leak.rs:20:23 + | +LL | unconstrained_arg(return); + | ^^^^^^ +help: use `()` annotations to avoid fallback changes + | +LL | unconstrained_arg::<()>(return); + | ++++++ + diff --git a/tests/ui/never_type/diverging-fallback-no-leak.e2024.stderr b/tests/ui/never_type/diverging-fallback-no-leak.e2024.stderr new file mode 100644 index 000000000000..36b4a1b40e26 --- /dev/null +++ b/tests/ui/never_type/diverging-fallback-no-leak.e2024.stderr @@ -0,0 +1,26 @@ +error[E0277]: the trait bound `!: Test` is not satisfied + --> $DIR/diverging-fallback-no-leak.rs:20:23 + | +LL | unconstrained_arg(return); + | ----------------- ^^^^^^ the trait `Test` is not implemented for `!` + | | + | required by a bound introduced by this call + | +help: the following other types implement trait `Test` + --> $DIR/diverging-fallback-no-leak.rs:11:1 + | +LL | impl Test for i32 {} + | ^^^^^^^^^^^^^^^^^ `i32` +LL | impl Test for () {} + | ^^^^^^^^^^^^^^^^ `()` + = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 for more information) + = help: you might have intended to use the type `()` here instead +note: required by a bound in `unconstrained_arg` + --> $DIR/diverging-fallback-no-leak.rs:14:25 + | +LL | fn unconstrained_arg(_: T) {} + | ^^^^ required by this bound in `unconstrained_arg` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/never_type/diverging-fallback-no-leak.rs b/tests/ui/never_type/diverging-fallback-no-leak.rs index d2bc064e4fd5..fd276ea63880 100644 --- a/tests/ui/never_type/diverging-fallback-no-leak.rs +++ b/tests/ui/never_type/diverging-fallback-no-leak.rs @@ -1,8 +1,9 @@ -//@ revisions: nofallback fallback -//@[fallback] edition: 2024 -//@[nofallback] check-pass +//@ revisions: e2021 e2024 +//@[e2021] edition: 2021 +//@[e2024] edition: 2024 +// +//@[e2021] check-pass -#![cfg_attr(nofallback, expect(dependency_on_unit_never_type_fallback))] fn make_unit() {} @@ -12,9 +13,10 @@ impl Test for () {} fn unconstrained_arg(_: T) {} +#[cfg_attr(e2021, expect(dependency_on_unit_never_type_fallback))] fn main() { // Here the type variable falls back to `!`, // and hence we get a type error. unconstrained_arg(return); - //[fallback]~^ error: trait bound `!: Test` is not satisfied + //[e2024]~^ error: trait bound `!: Test` is not satisfied } diff --git a/tests/ui/never_type/eq-never-types.rs b/tests/ui/never_type/eq-never-types.rs index 19717fcf4433..c130b9a35214 100644 --- a/tests/ui/never_type/eq-never-types.rs +++ b/tests/ui/never_type/eq-never-types.rs @@ -1,10 +1,9 @@ -//@ check-pass +// Regression test for // -// issue: rust-lang/rust#120600 +//@ edition: 2024 +//@ check-pass -#![allow(internal_features)] -#![feature(never_type, rustc_attrs)] -#![rustc_never_type_options(fallback = "never")] +#![feature(never_type)] fn ice(a: !) { a == a; diff --git a/tests/ui/never_type/fallback-closure-ret.e2021.stderr b/tests/ui/never_type/fallback-closure-ret.e2021.stderr new file mode 100644 index 000000000000..44ec166eaa30 --- /dev/null +++ b/tests/ui/never_type/fallback-closure-ret.e2021.stderr @@ -0,0 +1,18 @@ +Future incompatibility report: Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/fallback-closure-ret.rs:21:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Bar` will fail + --> $DIR/fallback-closure-ret.rs:22:5 + | +LL | foo(|| panic!()); + | ^^^^^^^^^^^^^^^^ +help: use `()` annotations to avoid fallback changes + | +LL | foo::<()>(|| panic!()); + | ++++++ + diff --git a/tests/ui/never_type/fallback-closure-ret.e2024.stderr b/tests/ui/never_type/fallback-closure-ret.e2024.stderr new file mode 100644 index 000000000000..9687ddf6459d --- /dev/null +++ b/tests/ui/never_type/fallback-closure-ret.e2024.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `!: Bar` is not satisfied + --> $DIR/fallback-closure-ret.rs:22:5 + | +LL | foo(|| panic!()); + | ^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `!` + | +help: the following other types implement trait `Bar` + --> $DIR/fallback-closure-ret.rs:15:1 + | +LL | impl Bar for () {} + | ^^^^^^^^^^^^^^^ `()` +LL | impl Bar for u32 {} + | ^^^^^^^^^^^^^^^^ `u32` + = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 for more information) + = help: you might have intended to use the type `()` here instead +note: required by a bound in `foo` + --> $DIR/fallback-closure-ret.rs:18:11 + | +LL | fn foo(_: impl Fn() -> R) {} + | ^^^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/never_type/fallback-closure-ret.rs b/tests/ui/never_type/fallback-closure-ret.rs index 4f2bc16e7d56..11d7c685706b 100644 --- a/tests/ui/never_type/fallback-closure-ret.rs +++ b/tests/ui/never_type/fallback-closure-ret.rs @@ -1,12 +1,15 @@ +// Tests the pattern of returning `!` from a closure and then checking if the +// return type iumplements a trait (not implemented for `!`). +// // This test used to test that this pattern is not broken by context dependant // never type fallback. However, it got removed, so now this is an example of // expected breakage from the never type fallback change. // -//@ revisions: nofallback fallback -//@[nofallback] check-pass -//@[fallback] edition: 2024 - -#![cfg_attr(nofallback, expect(dependency_on_unit_never_type_fallback))] +//@ revisions: e2021 e2024 +//@[e2021] edition: 2021 +//@[e2024] edition: 2024 +// +//@[e2021] check-pass trait Bar {} impl Bar for () {} @@ -14,6 +17,7 @@ impl Bar for u32 {} fn foo(_: impl Fn() -> R) {} +#[cfg_attr(e2021, expect(dependency_on_unit_never_type_fallback))] fn main() { - foo(|| panic!()); //[fallback]~ error: the trait bound `!: Bar` is not satisfied + foo(|| panic!()); //[e2024]~ error: the trait bound `!: Bar` is not satisfied } diff --git a/tests/ui/never_type/impl-for-never.rs b/tests/ui/never_type/impl-for-never.rs index 0da79a712d2b..dad3002c9a0c 100644 --- a/tests/ui/never_type/impl-for-never.rs +++ b/tests/ui/never_type/impl-for-never.rs @@ -1,8 +1,9 @@ +// Test that we can call static methods on ! both directly and when it appears in a generic +// //@ run-pass #![feature(never_type)] -// Test that we can call static methods on ! both directly and when it appears in a generic trait StringifyType { fn stringify_type() -> &'static str; diff --git a/tests/ui/never_type/issue-44402.rs b/tests/ui/never_type/issue-44402.rs index 820d1af37bf6..ae8c59a5cf06 100644 --- a/tests/ui/never_type/issue-44402.rs +++ b/tests/ui/never_type/issue-44402.rs @@ -1,13 +1,14 @@ +// Regression test for +// +// Previously inhabitedness check was handling cycles incorrectly causing this +// to not compile. +// //@ check-pass #![allow(dead_code)] #![feature(never_type)] #![feature(exhaustive_patterns)] -// Regression test for inhabitedness check. The old -// cache used to cause us to incorrectly decide -// that `test_b` was invalid. - struct Foo { field1: !, field2: Option<&'static Bar>, @@ -30,4 +31,4 @@ fn test_b() { } } -fn main() { } +fn main() {} diff --git a/tests/ui/never_type/issue-51506.rs b/tests/ui/never_type/issue-51506.rs index d0fe6a0f59a8..c366b6c16b29 100644 --- a/tests/ui/never_type/issue-51506.rs +++ b/tests/ui/never_type/issue-51506.rs @@ -1,3 +1,5 @@ +// Regression test for + #![feature(never_type, specialization)] #![allow(incomplete_features)] diff --git a/tests/ui/never_type/issue-51506.stderr b/tests/ui/never_type/issue-51506.stderr index 09379257c4cc..0e666e017f9c 100644 --- a/tests/ui/never_type/issue-51506.stderr +++ b/tests/ui/never_type/issue-51506.stderr @@ -1,12 +1,12 @@ error[E0277]: `!` is not an iterator - --> $DIR/issue-51506.rs:13:24 + --> $DIR/issue-51506.rs:15:24 | LL | default type Out = !; | ^ `!` is not an iterator | = help: the trait `Iterator` is not implemented for `!` note: required by a bound in `Trait::Out` - --> $DIR/issue-51506.rs:7:15 + --> $DIR/issue-51506.rs:9:15 | LL | type Out: Iterator; | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::Out` diff --git a/tests/ui/never_type/never-assign-dead-code.rs b/tests/ui/never_type/never-assign-dead-code.rs index 2c99d3086fba..0aae868c29b5 100644 --- a/tests/ui/never_type/never-assign-dead-code.rs +++ b/tests/ui/never_type/never-assign-dead-code.rs @@ -1,5 +1,5 @@ // Test that an assignment of type ! makes the rest of the block dead code. - +// //@ check-pass #![feature(never_type)] diff --git a/tests/ui/never_type/never-associated-type.rs b/tests/ui/never_type/never-associated-type.rs index f7b88f604f26..a62ec7e59910 100644 --- a/tests/ui/never_type/never-associated-type.rs +++ b/tests/ui/never_type/never-associated-type.rs @@ -1,5 +1,5 @@ // Test that we can use ! as an associated type. - +// //@ check-pass #![feature(never_type)] diff --git a/tests/ui/never_type/never-in-range-pat.rs b/tests/ui/never_type/never-in-range-pat.rs index ae2d76c172ea..2e0409bfa645 100644 --- a/tests/ui/never_type/never-in-range-pat.rs +++ b/tests/ui/never_type/never-in-range-pat.rs @@ -1,5 +1,5 @@ // Regression test for . - +// // Make sure we don't ICE when there's `!` in a range pattern. // // This shouldn't be allowed anyways, but we only deny it during MIR diff --git a/tests/ui/never_type/never-type-arg.rs b/tests/ui/never_type/never-type-arg.rs index 10023cf41999..45ce6836e2a4 100644 --- a/tests/ui/never_type/never-type-arg.rs +++ b/tests/ui/never_type/never-type-arg.rs @@ -1,5 +1,5 @@ // Test that we can use ! as an argument to a trait impl. - +// //@ check-pass #![feature(never_type)] diff --git a/tests/ui/never_type/never_transmute_never.rs b/tests/ui/never_type/never_transmute_never.rs index b1fcffcb3b7e..096aadd8f04a 100644 --- a/tests/ui/never_type/never_transmute_never.rs +++ b/tests/ui/never_type/never_transmute_never.rs @@ -1,7 +1,5 @@ //@ check-pass -#![crate_type="lib"] - #![feature(never_type)] #![allow(dead_code)] #![allow(unreachable_code)] @@ -21,3 +19,5 @@ pub fn ub() { }; f(x) } + +fn main() {} diff --git a/tests/ui/never_type/question_mark_from_never.rs b/tests/ui/never_type/question_mark_from_never.rs index 06d2a1926ea9..8d73313667ab 100644 --- a/tests/ui/never_type/question_mark_from_never.rs +++ b/tests/ui/never_type/question_mark_from_never.rs @@ -1,4 +1,4 @@ -// issue: rust-lang/rust#66757 +// Regression test for . // // See also: `tests/ui/never_type/from_infer_breaking_with_unit_fallback.rs`. // diff --git a/tests/ui/never_type/span-bug-issue-121445.rs b/tests/ui/never_type/span-bug-issue-121445.rs index 2fe22529c4e9..64bf6bd6aa11 100644 --- a/tests/ui/never_type/span-bug-issue-121445.rs +++ b/tests/ui/never_type/span-bug-issue-121445.rs @@ -1,3 +1,5 @@ +// Regression test for + #![feature(never_type)] fn test2() { diff --git a/tests/ui/never_type/span-bug-issue-121445.stderr b/tests/ui/never_type/span-bug-issue-121445.stderr index b211afa236fe..8c8bc133433a 100644 --- a/tests/ui/never_type/span-bug-issue-121445.stderr +++ b/tests/ui/never_type/span-bug-issue-121445.stderr @@ -1,5 +1,5 @@ error[E0369]: no implementation for `SingleVariant | ()` - --> $DIR/span-bug-issue-121445.rs:6:9 + --> $DIR/span-bug-issue-121445.rs:8:9 | LL | let c2 = SingleVariant::Points(0) | ------------------------ SingleVariant @@ -10,7 +10,7 @@ LL | | }; | |_________- () | note: an implementation of `BitOr<()>` might be missing for `SingleVariant` - --> $DIR/span-bug-issue-121445.rs:11:1 + --> $DIR/span-bug-issue-121445.rs:13:1 | LL | enum SingleVariant { | ^^^^^^^^^^^^^^^^^^ must implement `BitOr<()>` From e9873435a39b73232e38e441e19e63c934c9ae25 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 23:34:34 +0100 Subject: [PATCH 205/585] merge `diverging-fallback-no-leak` into an existing test --- .../editions/never-type-fallback-breaking.rs | 7 +++++ .../diverging-fallback-no-leak.e2021.stderr | 18 ------------- .../diverging-fallback-no-leak.e2024.stderr | 26 ------------------- ...diverging-fallback-no-leak.fallback.stderr | 26 ------------------- ...verging-fallback-no-leak.nofallback.stderr | 18 ------------- .../never_type/diverging-fallback-no-leak.rs | 22 ---------------- 6 files changed, 7 insertions(+), 110 deletions(-) delete mode 100644 tests/ui/never_type/diverging-fallback-no-leak.e2021.stderr delete mode 100644 tests/ui/never_type/diverging-fallback-no-leak.e2024.stderr delete mode 100644 tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr delete mode 100644 tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr delete mode 100644 tests/ui/never_type/diverging-fallback-no-leak.rs diff --git a/tests/ui/editions/never-type-fallback-breaking.rs b/tests/ui/editions/never-type-fallback-breaking.rs index 96e469445397..5554df41f3bc 100644 --- a/tests/ui/editions/never-type-fallback-breaking.rs +++ b/tests/ui/editions/never-type-fallback-breaking.rs @@ -75,3 +75,10 @@ fn fully_apit() -> Result<(), ()> { //[e2024]~^ error: the trait bound `!: Default` is not satisfied Ok(()) } + +fn return_as_argument() { + //[e2021]~^ error: this function depends on never type fallback being `()` + //[e2021]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + takes_apit2(return); + //[e2024]~^ error: trait bound `!: Test` is not satisfied +} diff --git a/tests/ui/never_type/diverging-fallback-no-leak.e2021.stderr b/tests/ui/never_type/diverging-fallback-no-leak.e2021.stderr deleted file mode 100644 index e67db8c71985..000000000000 --- a/tests/ui/never_type/diverging-fallback-no-leak.e2021.stderr +++ /dev/null @@ -1,18 +0,0 @@ -Future incompatibility report: Future breakage diagnostic: -warning: this function depends on never type fallback being `()` - --> $DIR/diverging-fallback-no-leak.rs:17:1 - | -LL | fn main() { - | ^^^^^^^^^ - | - = help: specify the types explicitly -note: in edition 2024, the requirement `!: Test` will fail - --> $DIR/diverging-fallback-no-leak.rs:20:23 - | -LL | unconstrained_arg(return); - | ^^^^^^ -help: use `()` annotations to avoid fallback changes - | -LL | unconstrained_arg::<()>(return); - | ++++++ - diff --git a/tests/ui/never_type/diverging-fallback-no-leak.e2024.stderr b/tests/ui/never_type/diverging-fallback-no-leak.e2024.stderr deleted file mode 100644 index 36b4a1b40e26..000000000000 --- a/tests/ui/never_type/diverging-fallback-no-leak.e2024.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0277]: the trait bound `!: Test` is not satisfied - --> $DIR/diverging-fallback-no-leak.rs:20:23 - | -LL | unconstrained_arg(return); - | ----------------- ^^^^^^ the trait `Test` is not implemented for `!` - | | - | required by a bound introduced by this call - | -help: the following other types implement trait `Test` - --> $DIR/diverging-fallback-no-leak.rs:11:1 - | -LL | impl Test for i32 {} - | ^^^^^^^^^^^^^^^^^ `i32` -LL | impl Test for () {} - | ^^^^^^^^^^^^^^^^ `()` - = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 for more information) - = help: you might have intended to use the type `()` here instead -note: required by a bound in `unconstrained_arg` - --> $DIR/diverging-fallback-no-leak.rs:14:25 - | -LL | fn unconstrained_arg(_: T) {} - | ^^^^ required by this bound in `unconstrained_arg` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr deleted file mode 100644 index 1baccd7b637b..000000000000 --- a/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0277]: the trait bound `!: Test` is not satisfied - --> $DIR/diverging-fallback-no-leak.rs:18:23 - | -LL | unconstrained_arg(return); - | ----------------- ^^^^^^ the trait `Test` is not implemented for `!` - | | - | required by a bound introduced by this call - | -help: the following other types implement trait `Test` - --> $DIR/diverging-fallback-no-leak.rs:10:1 - | -LL | impl Test for i32 {} - | ^^^^^^^^^^^^^^^^^ `i32` -LL | impl Test for () {} - | ^^^^^^^^^^^^^^^^ `()` - = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 for more information) - = help: you might have intended to use the type `()` here instead -note: required by a bound in `unconstrained_arg` - --> $DIR/diverging-fallback-no-leak.rs:13:25 - | -LL | fn unconstrained_arg(_: T) {} - | ^^^^ required by this bound in `unconstrained_arg` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr deleted file mode 100644 index 8423261ed610..000000000000 --- a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr +++ /dev/null @@ -1,18 +0,0 @@ -Future incompatibility report: Future breakage diagnostic: -warning: this function depends on never type fallback being `()` - --> $DIR/diverging-fallback-no-leak.rs:15:1 - | -LL | fn main() { - | ^^^^^^^^^ - | - = help: specify the types explicitly -note: in edition 2024, the requirement `!: Test` will fail - --> $DIR/diverging-fallback-no-leak.rs:18:23 - | -LL | unconstrained_arg(return); - | ^^^^^^ -help: use `()` annotations to avoid fallback changes - | -LL | unconstrained_arg::<()>(return); - | ++++++ - diff --git a/tests/ui/never_type/diverging-fallback-no-leak.rs b/tests/ui/never_type/diverging-fallback-no-leak.rs deleted file mode 100644 index fd276ea63880..000000000000 --- a/tests/ui/never_type/diverging-fallback-no-leak.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ revisions: e2021 e2024 -//@[e2021] edition: 2021 -//@[e2024] edition: 2024 -// -//@[e2021] check-pass - - -fn make_unit() {} - -trait Test {} -impl Test for i32 {} -impl Test for () {} - -fn unconstrained_arg(_: T) {} - -#[cfg_attr(e2021, expect(dependency_on_unit_never_type_fallback))] -fn main() { - // Here the type variable falls back to `!`, - // and hence we get a type error. - unconstrained_arg(return); - //[e2024]~^ error: trait bound `!: Test` is not satisfied -} From 8d01e7289c09a93ca52b74d4f77a3d0fcec115a0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 4 Nov 2025 09:29:47 +0000 Subject: [PATCH 206/585] Call rustc_driver::main() for MIRI_BE_RUSTC=host This way we don't need a special case in MiriBeRustCompilerCalls. Co-Authored-By: Ralf Jung --- src/tools/miri/src/bin/miri.rs | 63 ++++++++++++++-------------------- 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 4bf51f83c4f7..efe707156c40 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -272,18 +272,13 @@ fn after_analysis<'tcx>( } } -struct MiriBeRustCompilerCalls { - target_crate: bool, -} +/// This compiler produces rlibs that are meant for later consumption by Miri. +struct MiriDepCompilerCalls; -impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { +impl rustc_driver::Callbacks for MiriDepCompilerCalls { #[allow(rustc::potential_query_instability)] // rustc_codegen_ssa (where this code is copied from) also allows this lint fn config(&mut self, config: &mut Config) { - if !self.target_crate { - // For a host crate, we fully behave like rustc. - return; - } - // For a target crate, we emit an rlib that Miri can later consume. + // We don't need actual codegen, we just emit an rlib that Miri can later consume. config.make_codegen_backend = Some(Box::new(make_miri_codegen_backend)); // Avoid warnings about unsupported crate types. However, only do that we we are *not* being @@ -367,16 +362,12 @@ fn after_analysis<'tcx>( _: &rustc_interface::interface::Compiler, tcx: TyCtxt<'tcx>, ) -> Compilation { - if self.target_crate { - // cargo-miri has patched the compiler flags to make these into check-only builds, - // but we are still emulating regular rustc builds, which would perform post-mono - // const-eval during collection. So let's also do that here, even if we might be - // running with `--emit=metadata`. In particular this is needed to make - // `compile_fail` doc tests trigger post-mono errors. - // In general `collect_and_partition_mono_items` is not safe to call in check-only - // builds, but we are setting `-Zalways-encode-mir` which avoids those issues. - let _ = tcx.collect_and_partition_mono_items(()); - } + // While the dummy codegen backend doesn't do any codegen, we are still emulating + // regular rustc builds, which would perform post-mono const-eval during collection. + // So let's also do that here. In particular this is needed to make `compile_fail` + // doc tests trigger post-mono errors. + let _ = tcx.collect_and_partition_mono_items(()); + Compilation::Continue } } @@ -457,32 +448,28 @@ fn main() { // If the environment asks us to actually be rustc, then do that. if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") { + if crate_kind == "host" { + // For host crates like proc macros and build scripts, we are an entirely normal rustc. + // These eventually produce actual binaries and never run in Miri. + match rustc_driver::main() { + // Empty match proves this function will never return. + } + } else if crate_kind != "target" { + panic!("invalid `MIRI_BE_RUSTC` value: {crate_kind:?}") + }; + // Earliest rustc setup. rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ()); rustc_driver::init_rustc_env_logger(&early_dcx); - let target_crate = if crate_kind == "target" { - true - } else if crate_kind == "host" { - false - } else { - panic!("invalid `MIRI_BE_RUSTC` value: {crate_kind:?}") - }; - let mut args = args; - // Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building - // a "host" crate. That may cause procedural macros (and probably build scripts) to - // depend on Miri-only symbols, such as `miri_resolve_frame`: - // https://github.com/rust-lang/miri/issues/1760 - if target_crate { - // Splice in the default arguments after the program name. - // Some options have different defaults in Miri than in plain rustc; apply those by making - // them the first arguments after the binary name (but later arguments can overwrite them). - args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); - } + // Splice in the default arguments after the program name. + // Some options have different defaults in Miri than in plain rustc; apply those by making + // them the first arguments after the binary name (but later arguments can overwrite them). + args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); // We cannot use `rustc_driver::main` as we want it to use `args` as the CLI arguments. - run_compiler_and_exit(&args, &mut MiriBeRustCompilerCalls { target_crate }) + run_compiler_and_exit(&args, &mut MiriDepCompilerCalls) } // Add an ICE bug report hook. From 79224797fb36d5823b04cc266c08db5089246d2d Mon Sep 17 00:00:00 2001 From: James Barford-Evans Date: Tue, 2 Dec 2025 15:36:21 +0000 Subject: [PATCH 207/585] Regression tests for system register `ttbr0_el2` --- tests/ui/asm/aarch64/ttbr0_el2.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/ui/asm/aarch64/ttbr0_el2.rs diff --git a/tests/ui/asm/aarch64/ttbr0_el2.rs b/tests/ui/asm/aarch64/ttbr0_el2.rs new file mode 100644 index 000000000000..a283d75c8fff --- /dev/null +++ b/tests/ui/asm/aarch64/ttbr0_el2.rs @@ -0,0 +1,11 @@ +//! Regression test for #97724, recognising ttbr0_el2 as a valid armv8 system register +//@ only-aarch64 +//@ build-pass +use std::arch::asm; + +static PT: [u64; 512] = [0; 512]; +fn main() { + unsafe { + asm!("msr ttbr0_el2, {pt}", pt = in(reg) &PT as *const _ ); + } +} From 1ef636d61a97475b0b0603d8727d336a67a538eb Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 2 Dec 2025 08:03:10 -0800 Subject: [PATCH 208/585] Update other targets for `BorrowedCursor` unstable API changes --- library/std/src/sys/fd/hermit.rs | 2 +- library/std/src/sys/fd/wasi.rs | 2 +- library/std/src/sys/fs/solid.rs | 2 +- library/std/src/sys/net/connection/socket/hermit.rs | 2 +- library/std/src/sys/net/connection/socket/solid.rs | 2 +- library/std/src/sys/net/connection/socket/wasip2.rs | 2 +- library/std/src/sys/net/connection/socket/windows.rs | 2 +- library/std/src/sys/pal/sgx/abi/usercalls/mod.rs | 2 +- library/std/src/sys/pal/windows/handle.rs | 4 ++-- library/std/src/sys/pal/windows/pipe.rs | 2 +- library/std/src/sys/stdio/zkvm.rs | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/std/src/sys/fd/hermit.rs b/library/std/src/sys/fd/hermit.rs index 7e8ba065f1b9..afcd8c635541 100644 --- a/library/std/src/sys/fd/hermit.rs +++ b/library/std/src/sys/fd/hermit.rs @@ -34,7 +34,7 @@ pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { ) })?; // SAFETY: Exactly `result` bytes have been filled. - unsafe { buf.advance_unchecked(result as usize) }; + unsafe { buf.advance(result as usize) }; Ok(()) } diff --git a/library/std/src/sys/fd/wasi.rs b/library/std/src/sys/fd/wasi.rs index 80a5143ff0b0..a468b31168af 100644 --- a/library/std/src/sys/fd/wasi.rs +++ b/library/std/src/sys/fd/wasi.rs @@ -59,7 +59,7 @@ pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { }]; match wasi::fd_read(self.as_raw_fd() as wasi::Fd, &bufs) { Ok(n) => { - buf.advance_unchecked(n); + buf.advance(n); Ok(()) } Err(e) => Err(err2io(e)), diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs index f6d5d3b784d3..ec1db262855a 100644 --- a/library/std/src/sys/fs/solid.rs +++ b/library/std/src/sys/fs/solid.rs @@ -401,7 +401,7 @@ pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { // Safety: `num_bytes_read` bytes were written to the unfilled // portion of the buffer - cursor.advance_unchecked(num_bytes_read); + cursor.advance(num_bytes_read); Ok(()) } diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index 2f5c6fa31d40..f044bf8dfae0 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -143,7 +143,7 @@ fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: i32) -> io::Result ) })?; unsafe { - buf.advance_unchecked(ret as usize); + buf.advance(ret as usize); } Ok(()) } diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index 14cf75adcc06..731157ec319c 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -191,7 +191,7 @@ fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Resu netc::recv(self.as_raw_fd(), buf.as_mut().as_mut_ptr().cast(), buf.capacity(), flags) })?; unsafe { - buf.advance_unchecked(ret as usize); + buf.advance(ret as usize); } Ok(()) } diff --git a/library/std/src/sys/net/connection/socket/wasip2.rs b/library/std/src/sys/net/connection/socket/wasip2.rs index a1b08609eb02..f86034266c26 100644 --- a/library/std/src/sys/net/connection/socket/wasip2.rs +++ b/library/std/src/sys/net/connection/socket/wasip2.rs @@ -167,7 +167,7 @@ fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Resu ) })?; unsafe { - buf.advance_unchecked(ret as usize); + buf.advance(ret as usize); } Ok(()) } diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 6dbebc5e276e..08196d61aa30 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -244,7 +244,7 @@ fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Resu } } _ => { - unsafe { buf.advance_unchecked(result as usize) }; + unsafe { buf.advance(result as usize) }; Ok(()) } } diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs index 5041770faf66..f1e4a5a42577 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs @@ -46,7 +46,7 @@ pub fn read_buf(fd: Fd, mut buf: BorrowedCursor<'_>) -> IoResult<()> { let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.capacity()); let len = raw::read(fd, userbuf.as_mut_ptr().cast(), userbuf.len()).from_sgx_result()?; userbuf[..len].copy_to_enclave(&mut buf.as_mut()[..len]); - buf.advance_unchecked(len); + buf.advance(len); Ok(()) } } diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index 76c8aa939d3b..712f41ba8030 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -121,7 +121,7 @@ pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { Ok(read) => { // Safety: `read` bytes were written to the initialized portion of the buffer unsafe { - cursor.advance_unchecked(read); + cursor.advance(read); } Ok(()) } @@ -144,7 +144,7 @@ pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Re // SAFETY: `read` bytes were written to the initialized portion of the buffer unsafe { - cursor.advance_unchecked(read); + cursor.advance(read); } Ok(()) } diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index b5ccf037a4f2..d8e306068d73 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -259,7 +259,7 @@ pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { Err(e) => Err(e), Ok(n) => { unsafe { - buf.advance_unchecked(n); + buf.advance(n); } Ok(()) } diff --git a/library/std/src/sys/stdio/zkvm.rs b/library/std/src/sys/stdio/zkvm.rs index f31c6c26e87c..84496ac93736 100644 --- a/library/std/src/sys/stdio/zkvm.rs +++ b/library/std/src/sys/stdio/zkvm.rs @@ -19,7 +19,7 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { unsafe { let n = abi::sys_read(fileno::STDIN, buf.as_mut().as_mut_ptr().cast(), buf.capacity()); - buf.advance_unchecked(n); + buf.advance(n); } Ok(()) } From ed64abc14dd3cefcd4a64e087b4e2ab88e124428 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 2 Dec 2025 11:39:15 -0500 Subject: [PATCH 209/585] Update gccjit_sys --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 00bdacaca676..dea1207b05da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,9 +65,9 @@ dependencies = [ [[package]] name = "gccjit_sys" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "263da4f60b7bb5d6a5b21efda961741051ebdbf0e380a09118b03cce66a8c77e" +checksum = "4f81d901767ddba371a619fa9bba657066a4d3c5607ee69bbb557c1c5ba9bf85" dependencies = [ "libc", ] From 7d33e7e0912172d9f6bd4277ee1f5b4a37541a9a Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 17:43:01 +0100 Subject: [PATCH 210/585] clarify purposes of tests --- .../never-type-fallback-breaking.e2021.fixed | 4 ++ .../never-type-fallback-breaking.e2021.stderr | 40 +++++++++---------- .../never-type-fallback-breaking.e2024.stderr | 16 ++++---- .../editions/never-type-fallback-breaking.rs | 11 ++--- tests/ui/never_type/exhaustive_patterns.rs | 3 ++ .../ui/never_type/exhaustive_patterns.stderr | 4 +- tests/ui/never_type/never-result.rs | 3 ++ tests/ui/never_type/never-type-rvalues.rs | 2 + 8 files changed, 46 insertions(+), 37 deletions(-) diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.fixed b/tests/ui/editions/never-type-fallback-breaking.e2021.fixed index c8f3e87027a3..7e6c47ed43e0 100644 --- a/tests/ui/editions/never-type-fallback-breaking.e2021.fixed +++ b/tests/ui/editions/never-type-fallback-breaking.e2021.fixed @@ -1,3 +1,7 @@ +// This is a test for various ways in which the change to the never type +// fallback can break things and for the `dependency_on_unit_never_type_fallback` +// lint. +// //@ revisions: e2021 e2024 // //@[e2021] edition: 2021 diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr index ded694f5a3d4..a910b19d9bf7 100644 --- a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr +++ b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr @@ -1,5 +1,5 @@ error: this function depends on never type fallback being `()` - --> $DIR/never-type-fallback-breaking.rs:16:1 + --> $DIR/never-type-fallback-breaking.rs:20:1 | LL | fn m() { | ^^^^^^ @@ -8,7 +8,7 @@ LL | fn m() { = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail - --> $DIR/never-type-fallback-breaking.rs:20:17 + --> $DIR/never-type-fallback-breaking.rs:24:17 | LL | true => Default::default(), | ^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | let x: () = match true { | ++++ error: this function depends on never type fallback being `()` - --> $DIR/never-type-fallback-breaking.rs:28:1 + --> $DIR/never-type-fallback-breaking.rs:32:1 | LL | fn q() -> Option<()> { | ^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | fn q() -> Option<()> { = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail - --> $DIR/never-type-fallback-breaking.rs:35:5 + --> $DIR/never-type-fallback-breaking.rs:39:5 | LL | deserialize()?; | ^^^^^^^^^^^^^ @@ -38,7 +38,7 @@ LL | deserialize::<()>()?; | ++++++ error: this function depends on never type fallback being `()` - --> $DIR/never-type-fallback-breaking.rs:45:1 + --> $DIR/never-type-fallback-breaking.rs:49:1 | LL | fn meow() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | fn meow() -> Result<(), ()> { = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `(): From` will fail - --> $DIR/never-type-fallback-breaking.rs:48:5 + --> $DIR/never-type-fallback-breaking.rs:52:5 | LL | help(1)?; | ^^^^^^^ @@ -57,7 +57,7 @@ LL | help::<(), _>(1)?; | +++++++++ error: this function depends on never type fallback being `()` - --> $DIR/never-type-fallback-breaking.rs:57:1 + --> $DIR/never-type-fallback-breaking.rs:61:1 | LL | pub fn fallback_return() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | pub fn fallback_return() -> Result<(), ()> { = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail - --> $DIR/never-type-fallback-breaking.rs:60:19 + --> $DIR/never-type-fallback-breaking.rs:64:19 | LL | takes_apit(|| Default::default())?; | ^^^^^^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | takes_apit::<()>(|| Default::default())?; | ++++++ error: this function depends on never type fallback being `()` - --> $DIR/never-type-fallback-breaking.rs:71:1 + --> $DIR/never-type-fallback-breaking.rs:75:1 | LL | fn fully_apit() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | fn fully_apit() -> Result<(), ()> { = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail - --> $DIR/never-type-fallback-breaking.rs:74:17 + --> $DIR/never-type-fallback-breaking.rs:78:17 | LL | takes_apit2(mk()?); | ^^^^^ @@ -98,7 +98,7 @@ error: aborting due to 5 previous errors Future incompatibility report: Future breakage diagnostic: error: this function depends on never type fallback being `()` - --> $DIR/never-type-fallback-breaking.rs:16:1 + --> $DIR/never-type-fallback-breaking.rs:20:1 | LL | fn m() { | ^^^^^^ @@ -107,7 +107,7 @@ LL | fn m() { = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail - --> $DIR/never-type-fallback-breaking.rs:20:17 + --> $DIR/never-type-fallback-breaking.rs:24:17 | LL | true => Default::default(), | ^^^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL | let x: () = match true { Future breakage diagnostic: error: this function depends on never type fallback being `()` - --> $DIR/never-type-fallback-breaking.rs:28:1 + --> $DIR/never-type-fallback-breaking.rs:32:1 | LL | fn q() -> Option<()> { | ^^^^^^^^^^^^^^^^^^^^ @@ -128,7 +128,7 @@ LL | fn q() -> Option<()> { = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail - --> $DIR/never-type-fallback-breaking.rs:35:5 + --> $DIR/never-type-fallback-breaking.rs:39:5 | LL | deserialize()?; | ^^^^^^^^^^^^^ @@ -140,7 +140,7 @@ LL | deserialize::<()>()?; Future breakage diagnostic: error: this function depends on never type fallback being `()` - --> $DIR/never-type-fallback-breaking.rs:45:1 + --> $DIR/never-type-fallback-breaking.rs:49:1 | LL | fn meow() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL | fn meow() -> Result<(), ()> { = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `(): From` will fail - --> $DIR/never-type-fallback-breaking.rs:48:5 + --> $DIR/never-type-fallback-breaking.rs:52:5 | LL | help(1)?; | ^^^^^^^ @@ -161,7 +161,7 @@ LL | help::<(), _>(1)?; Future breakage diagnostic: error: this function depends on never type fallback being `()` - --> $DIR/never-type-fallback-breaking.rs:57:1 + --> $DIR/never-type-fallback-breaking.rs:61:1 | LL | pub fn fallback_return() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL | pub fn fallback_return() -> Result<(), ()> { = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail - --> $DIR/never-type-fallback-breaking.rs:60:19 + --> $DIR/never-type-fallback-breaking.rs:64:19 | LL | takes_apit(|| Default::default())?; | ^^^^^^^^^^^^^^^^^^ @@ -182,7 +182,7 @@ LL | takes_apit::<()>(|| Default::default())?; Future breakage diagnostic: error: this function depends on never type fallback being `()` - --> $DIR/never-type-fallback-breaking.rs:71:1 + --> $DIR/never-type-fallback-breaking.rs:75:1 | LL | fn fully_apit() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -191,7 +191,7 @@ LL | fn fully_apit() -> Result<(), ()> { = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail - --> $DIR/never-type-fallback-breaking.rs:74:17 + --> $DIR/never-type-fallback-breaking.rs:78:17 | LL | takes_apit2(mk()?); | ^^^^^ diff --git a/tests/ui/editions/never-type-fallback-breaking.e2024.stderr b/tests/ui/editions/never-type-fallback-breaking.e2024.stderr index 4c6740df5d4d..65be5d90d011 100644 --- a/tests/ui/editions/never-type-fallback-breaking.e2024.stderr +++ b/tests/ui/editions/never-type-fallback-breaking.e2024.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `!: Default` is not satisfied - --> $DIR/never-type-fallback-breaking.rs:20:17 + --> $DIR/never-type-fallback-breaking.rs:24:17 | LL | true => Default::default(), | ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `!` @@ -8,7 +8,7 @@ LL | true => Default::default(), = help: you might have intended to use the type `()` here instead error[E0277]: the trait bound `!: Default` is not satisfied - --> $DIR/never-type-fallback-breaking.rs:35:5 + --> $DIR/never-type-fallback-breaking.rs:39:5 | LL | deserialize()?; | ^^^^^^^^^^^^^ the trait `Default` is not implemented for `!` @@ -16,13 +16,13 @@ LL | deserialize()?; = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 for more information) = help: you might have intended to use the type `()` here instead note: required by a bound in `deserialize` - --> $DIR/never-type-fallback-breaking.rs:31:23 + --> $DIR/never-type-fallback-breaking.rs:35:23 | LL | fn deserialize() -> Option { | ^^^^^^^ required by this bound in `deserialize` error[E0277]: the trait bound `(): From` is not satisfied - --> $DIR/never-type-fallback-breaking.rs:48:5 + --> $DIR/never-type-fallback-breaking.rs:52:5 | LL | help(1)?; | ^^^^^^^ the trait `From` is not implemented for `()` @@ -39,13 +39,13 @@ LL | help(1)?; and 4 others = note: required for `!` to implement `Into<()>` note: required by a bound in `help` - --> $DIR/never-type-fallback-breaking.rs:42:20 + --> $DIR/never-type-fallback-breaking.rs:46:20 | LL | fn help<'a: 'a, T: Into<()>, U>(_: U) -> Result { | ^^^^^^^^ required by this bound in `help` error[E0277]: the trait bound `!: Default` is not satisfied - --> $DIR/never-type-fallback-breaking.rs:60:19 + --> $DIR/never-type-fallback-breaking.rs:64:19 | LL | takes_apit(|| Default::default())?; | ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `!` @@ -54,7 +54,7 @@ LL | takes_apit(|| Default::default())?; = help: you might have intended to use the type `()` here instead error[E0277]: the trait bound `!: Default` is not satisfied - --> $DIR/never-type-fallback-breaking.rs:74:17 + --> $DIR/never-type-fallback-breaking.rs:78:17 | LL | takes_apit2(mk()?); | ----------- ^^^^^ the trait `Default` is not implemented for `!` @@ -64,7 +64,7 @@ LL | takes_apit2(mk()?); = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 for more information) = help: you might have intended to use the type `()` here instead note: required by a bound in `takes_apit2` - --> $DIR/never-type-fallback-breaking.rs:69:25 + --> $DIR/never-type-fallback-breaking.rs:73:25 | LL | fn takes_apit2(_x: impl Default) {} | ^^^^^^^ required by this bound in `takes_apit2` diff --git a/tests/ui/editions/never-type-fallback-breaking.rs b/tests/ui/editions/never-type-fallback-breaking.rs index 5554df41f3bc..ae31b436f566 100644 --- a/tests/ui/editions/never-type-fallback-breaking.rs +++ b/tests/ui/editions/never-type-fallback-breaking.rs @@ -1,3 +1,7 @@ +// This is a test for various ways in which the change to the never type +// fallback can break things and for the `dependency_on_unit_never_type_fallback` +// lint. +// //@ revisions: e2021 e2024 // //@[e2021] edition: 2021 @@ -75,10 +79,3 @@ fn fully_apit() -> Result<(), ()> { //[e2024]~^ error: the trait bound `!: Default` is not satisfied Ok(()) } - -fn return_as_argument() { - //[e2021]~^ error: this function depends on never type fallback being `()` - //[e2021]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - takes_apit2(return); - //[e2024]~^ error: trait bound `!: Test` is not satisfied -} diff --git a/tests/ui/never_type/exhaustive_patterns.rs b/tests/ui/never_type/exhaustive_patterns.rs index b56eab6cb9d9..4f9e55c3d8dc 100644 --- a/tests/ui/never_type/exhaustive_patterns.rs +++ b/tests/ui/never_type/exhaustive_patterns.rs @@ -1,3 +1,6 @@ +// Check that we don't consider types which aren't publicly uninhabited as +// uninhabited for purposes of pattern matching. +// //@ check-fail #![feature(exhaustive_patterns, never_type)] diff --git a/tests/ui/never_type/exhaustive_patterns.stderr b/tests/ui/never_type/exhaustive_patterns.stderr index 1f22b9e61986..f8b582d1b50b 100644 --- a/tests/ui/never_type/exhaustive_patterns.stderr +++ b/tests/ui/never_type/exhaustive_patterns.stderr @@ -1,5 +1,5 @@ error[E0005]: refutable pattern in local binding - --> $DIR/exhaustive_patterns.rs:21:9 + --> $DIR/exhaustive_patterns.rs:24:9 | LL | let Either::A(()) = foo(); | ^^^^^^^^^^^^^ pattern `Either::B(_)` not covered @@ -7,7 +7,7 @@ LL | let Either::A(()) = foo(); = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html note: `Either<(), !>` defined here - --> $DIR/exhaustive_patterns.rs:9:6 + --> $DIR/exhaustive_patterns.rs:12:6 | LL | enum Either { | ^^^^^^ diff --git a/tests/ui/never_type/never-result.rs b/tests/ui/never_type/never-result.rs index 98ad14046662..ffcd44339346 100644 --- a/tests/ui/never_type/never-result.rs +++ b/tests/ui/never_type/never-result.rs @@ -1,3 +1,6 @@ +// Test that `!` can be coerced to multiple different types after getting it +// from pattern matching. +// //@ run-pass #![allow(unused_variables)] diff --git a/tests/ui/never_type/never-type-rvalues.rs b/tests/ui/never_type/never-type-rvalues.rs index d3f6f628e1a7..943de2563ef8 100644 --- a/tests/ui/never_type/never-type-rvalues.rs +++ b/tests/ui/never_type/never-type-rvalues.rs @@ -1,3 +1,5 @@ +// Check that the never type can be used in various positions. +// //@ run-pass #![feature(never_type)] From 3f606fac007550927614dda38436570ff223be11 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Nov 2025 23:24:32 +0100 Subject: [PATCH 211/585] minor test improvements --- tests/ui/never_type/call-fn-never-arg.rs | 2 +- tests/ui/never_type/exhaustive_patterns.rs | 2 +- tests/ui/never_type/impl-for-never.rs | 1 + tests/ui/never_type/impl-for-never.run.stdout | 2 ++ tests/ui/never_type/never-assign-dead-code.rs | 2 +- tests/ui/never_type/never-assign-wrong-type.rs | 1 - tests/ui/never_type/never-assign-wrong-type.stderr | 2 +- tests/ui/never_type/never-result.rs | 6 ++---- tests/ui/never_type/never_transmute_never.rs | 4 ++-- 9 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 tests/ui/never_type/impl-for-never.run.stdout diff --git a/tests/ui/never_type/call-fn-never-arg.rs b/tests/ui/never_type/call-fn-never-arg.rs index d64370f2ece6..546b37fb52f5 100644 --- a/tests/ui/never_type/call-fn-never-arg.rs +++ b/tests/ui/never_type/call-fn-never-arg.rs @@ -3,7 +3,7 @@ //@ check-pass #![feature(never_type)] -#![allow(unreachable_code)] +#![expect(unreachable_code)] fn foo(x: !) -> ! { x diff --git a/tests/ui/never_type/exhaustive_patterns.rs b/tests/ui/never_type/exhaustive_patterns.rs index 4f9e55c3d8dc..0562575d511e 100644 --- a/tests/ui/never_type/exhaustive_patterns.rs +++ b/tests/ui/never_type/exhaustive_patterns.rs @@ -3,7 +3,7 @@ // //@ check-fail -#![feature(exhaustive_patterns, never_type)] +#![feature(never_type)] mod inner { pub struct Wrapper(T); diff --git a/tests/ui/never_type/impl-for-never.rs b/tests/ui/never_type/impl-for-never.rs index dad3002c9a0c..e908d2a62547 100644 --- a/tests/ui/never_type/impl-for-never.rs +++ b/tests/ui/never_type/impl-for-never.rs @@ -1,6 +1,7 @@ // Test that we can call static methods on ! both directly and when it appears in a generic // //@ run-pass +//@ check-run-results #![feature(never_type)] diff --git a/tests/ui/never_type/impl-for-never.run.stdout b/tests/ui/never_type/impl-for-never.run.stdout new file mode 100644 index 000000000000..8f23a337b392 --- /dev/null +++ b/tests/ui/never_type/impl-for-never.run.stdout @@ -0,0 +1,2 @@ +! is ! +None is none diff --git a/tests/ui/never_type/never-assign-dead-code.rs b/tests/ui/never_type/never-assign-dead-code.rs index 0aae868c29b5..05e5d5551336 100644 --- a/tests/ui/never_type/never-assign-dead-code.rs +++ b/tests/ui/never_type/never-assign-dead-code.rs @@ -3,7 +3,7 @@ //@ check-pass #![feature(never_type)] -#![allow(dropping_copy_types)] +#![expect(dropping_copy_types)] #![warn(unused)] fn main() { diff --git a/tests/ui/never_type/never-assign-wrong-type.rs b/tests/ui/never_type/never-assign-wrong-type.rs index 67e26f5663f4..ccc2f872dab4 100644 --- a/tests/ui/never_type/never-assign-wrong-type.rs +++ b/tests/ui/never_type/never-assign-wrong-type.rs @@ -1,7 +1,6 @@ // Test that we can't use another type in place of ! #![feature(never_type)] -#![deny(warnings)] fn main() { let x: ! = "hello"; //~ ERROR mismatched types diff --git a/tests/ui/never_type/never-assign-wrong-type.stderr b/tests/ui/never_type/never-assign-wrong-type.stderr index f59de5d2a428..dd890e4d163b 100644 --- a/tests/ui/never_type/never-assign-wrong-type.stderr +++ b/tests/ui/never_type/never-assign-wrong-type.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/never-assign-wrong-type.rs:7:16 + --> $DIR/never-assign-wrong-type.rs:6:16 | LL | let x: ! = "hello"; | - ^^^^^^^ expected `!`, found `&str` diff --git a/tests/ui/never_type/never-result.rs b/tests/ui/never_type/never-result.rs index ffcd44339346..34b7cd67a55a 100644 --- a/tests/ui/never_type/never-result.rs +++ b/tests/ui/never_type/never-result.rs @@ -3,11 +3,9 @@ // //@ run-pass -#![allow(unused_variables)] -#![allow(unreachable_code)] -#![allow(unreachable_patterns)] -// Test that we can extract a ! through pattern matching then use it as several different types. #![feature(never_type)] +#![expect(unused_variables)] +#![expect(unreachable_code)] fn main() { let x: Result = Ok(123); diff --git a/tests/ui/never_type/never_transmute_never.rs b/tests/ui/never_type/never_transmute_never.rs index 096aadd8f04a..6d32a12bc44a 100644 --- a/tests/ui/never_type/never_transmute_never.rs +++ b/tests/ui/never_type/never_transmute_never.rs @@ -2,8 +2,8 @@ #![feature(never_type)] #![allow(dead_code)] -#![allow(unreachable_code)] -#![allow(unused_variables)] +#![expect(unreachable_code)] +#![expect(unused_variables)] struct Foo; From cb5318d03735dd0481cd0e3ee42ae0573633ac72 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Fri, 14 Nov 2025 00:16:12 +0100 Subject: [PATCH 212/585] stop using "nofallback" revision terminology --- ...fallback-unconstrained-return.e2021.stderr | 43 +++++++++++++++++++ ...fallback-unconstrained-return.e2024.stderr | 24 +++++++++++ ...diverging-fallback-unconstrained-return.rs | 10 ++--- .../fallback-closure-wrap.e2024.stderr | 15 +++++++ tests/ui/never_type/fallback-closure-wrap.rs | 13 +++--- 5 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 tests/ui/never_type/diverging-fallback-unconstrained-return.e2021.stderr create mode 100644 tests/ui/never_type/diverging-fallback-unconstrained-return.e2024.stderr create mode 100644 tests/ui/never_type/fallback-closure-wrap.e2024.stderr diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.e2021.stderr b/tests/ui/never_type/diverging-fallback-unconstrained-return.e2021.stderr new file mode 100644 index 000000000000..eb79cf5dd155 --- /dev/null +++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.e2021.stderr @@ -0,0 +1,43 @@ +error: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-unconstrained-return.rs:26:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see + = help: specify the types explicitly +note: in edition 2024, the requirement `!: UnitReturn` will fail + --> $DIR/diverging-fallback-unconstrained-return.rs:37:23 + | +LL | let _ = if true { unconstrained_return() } else { panic!() }; + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default +help: use `()` annotations to avoid fallback changes + | +LL | let _: () = if true { unconstrained_return() } else { panic!() }; + | ++++ + +error: aborting due to 1 previous error + +Future incompatibility report: Future breakage diagnostic: +error: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-unconstrained-return.rs:26:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see + = help: specify the types explicitly +note: in edition 2024, the requirement `!: UnitReturn` will fail + --> $DIR/diverging-fallback-unconstrained-return.rs:37:23 + | +LL | let _ = if true { unconstrained_return() } else { panic!() }; + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(dependency_on_unit_never_type_fallback)]` (part of `#[deny(rust_2024_compatibility)]`) on by default +help: use `()` annotations to avoid fallback changes + | +LL | let _: () = if true { unconstrained_return() } else { panic!() }; + | ++++ + diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.e2024.stderr b/tests/ui/never_type/diverging-fallback-unconstrained-return.e2024.stderr new file mode 100644 index 000000000000..d28f5d7de92f --- /dev/null +++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.e2024.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `!: UnitReturn` is not satisfied + --> $DIR/diverging-fallback-unconstrained-return.rs:37:23 + | +LL | let _ = if true { unconstrained_return() } else { panic!() }; + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `UnitReturn` is not implemented for `!` + | +help: the following other types implement trait `UnitReturn` + --> $DIR/diverging-fallback-unconstrained-return.rs:15:1 + | +LL | impl UnitReturn for i32 {} + | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` +LL | impl UnitReturn for () {} + | ^^^^^^^^^^^^^^^^^^^^^^ `()` + = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 for more information) + = help: you might have intended to use the type `()` here instead +note: required by a bound in `unconstrained_return` + --> $DIR/diverging-fallback-unconstrained-return.rs:18:28 + | +LL | fn unconstrained_return() -> T { + | ^^^^^^^^^^ required by this bound in `unconstrained_return` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.rs b/tests/ui/never_type/diverging-fallback-unconstrained-return.rs index 565fac34bd78..1c8ce71080bf 100644 --- a/tests/ui/never_type/diverging-fallback-unconstrained-return.rs +++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.rs @@ -4,8 +4,8 @@ // in the objc crate, where changing the fallback from `!` to `()` // resulted in unsoundness. // -//@ revisions: nofallback fallback -//@[fallback] edition: 2024 +//@ revisions: e2021 e2024 +//@[e2024] edition: 2024 #![expect(unit_bindings)] @@ -24,8 +24,8 @@ fn unconstrained_return() -> T { } fn main() { - //[nofallback]~^ error: this function depends on never type fallback being `()` - //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + //[e2021]~^ error: this function depends on never type fallback being `()` + //[e2021]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! // In Ye Olde Days, the `T` parameter of `unconstrained_return` // winds up "entangled" with the `!` type that results from @@ -34,5 +34,5 @@ fn main() { // idea was to change that fallback to `!`, but that would have resulted // in this code no longer compiling (or worse, in some cases it injected // unsound results). - let _ = if true { unconstrained_return() } else { panic!() }; //[fallback]~ error: the trait bound `!: UnitReturn` is not satisfied + let _ = if true { unconstrained_return() } else { panic!() }; //[e2024]~ error: the trait bound `!: UnitReturn` is not satisfied } diff --git a/tests/ui/never_type/fallback-closure-wrap.e2024.stderr b/tests/ui/never_type/fallback-closure-wrap.e2024.stderr new file mode 100644 index 000000000000..b55f9c99ae50 --- /dev/null +++ b/tests/ui/never_type/fallback-closure-wrap.e2024.stderr @@ -0,0 +1,15 @@ +error[E0271]: expected `{closure@fallback-closure-wrap.rs:16:40}` to return `()`, but it returns `!` + --> $DIR/fallback-closure-wrap.rs:17:9 + | +LL | let error = Closure::wrap(Box::new(move || { + | ------- this closure +LL | panic!("Can't connect to server."); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `!` + | + = note: expected unit type `()` + found type `!` + = note: required for the cast from `Box<{closure@$DIR/fallback-closure-wrap.rs:16:40: 16:47}>` to `Box` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/never_type/fallback-closure-wrap.rs b/tests/ui/never_type/fallback-closure-wrap.rs index 77546bb93c28..51be6ac06cc2 100644 --- a/tests/ui/never_type/fallback-closure-wrap.rs +++ b/tests/ui/never_type/fallback-closure-wrap.rs @@ -1,22 +1,21 @@ // This is a minified example from Crater breakage observed when attempting to // stabilize never type, nstoddard/webgl-gui @ 22f0169f. // -// This particular test case currently fails as the inference to `()` rather -// than `!` happens as a result of an `as` cast, which is not currently tracked. // Crater did not find many cases of this occurring, but it is included for // awareness. // -//@ revisions: nofallback fallback -//@[fallback] edition: 2024 -//@[nofallback] check-pass -//@[fallback] check-fail +//@ revisions: e2021 e2024 +//@[e2021] edition: 2021 +//@[e2024] edition: 2024 +// +//@[e2021] check-pass use std::marker::PhantomData; fn main() { let error = Closure::wrap(Box::new(move || { panic!("Can't connect to server."); - //[fallback]~^ ERROR to return `()`, but it returns `!` + //[e2024]~^ ERROR to return `()`, but it returns `!` }) as Box); } From 85b6c380d6afe9d1644816db8f2dc12c05fd1a5b Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 1 Dec 2025 13:14:48 +0100 Subject: [PATCH 213/585] remember the main thread ID before performing platform initialisation --- library/std/src/rt.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 2717b7b469ce..11c0a0b9daf7 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -109,14 +109,14 @@ fn handle_rt_panic(e: Box) -> T { // `compiler/rustc_session/src/config/sigpipe.rs`. #[cfg_attr(test, allow(dead_code))] unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { + // Remember the main thread ID to give it the correct name. + // SAFETY: this is the only time and place where we call this function. + unsafe { main_thread::set(thread::current_id()) }; + #[cfg_attr(target_os = "teeos", allow(unused_unsafe))] unsafe { sys::init(argc, argv, sigpipe) }; - - // Remember the main thread ID to give it the correct name. - // SAFETY: this is the only time and place where we call this function. - unsafe { main_thread::set(thread::current_id()) }; } /// Clean up the thread-local runtime state. This *should* be run after all other From 1331c35f0279fb11266003d9859c0bd30216e07b Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 2 Dec 2025 13:56:48 +0530 Subject: [PATCH 214/585] std: sys: fs: uefi: Make time in FileAttr optional At least on OVMF, some files copied over from linux file system seem to have invalid time (year = 1980 and everything else 0). Since Rust allows time to be optional and we can return error, that seems to be the way to go for now. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 28 +++++++------ library/std/src/sys/pal/uefi/time.rs | 59 ++++++++++++++++------------ 2 files changed, 50 insertions(+), 37 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index bd4ae56974f0..44f8b6e80f90 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -18,9 +18,8 @@ pub struct FileAttr { attr: u64, size: u64, - accessed: SystemTime, - modified: SystemTime, - created: SystemTime, + file_time: FileTimes, + created: Option, } pub struct ReadDir(!); @@ -66,15 +65,20 @@ pub fn file_type(&self) -> FileType { } pub fn modified(&self) -> io::Result { - Ok(self.modified) + self.file_time + .modified + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "modification time is not valid")) } pub fn accessed(&self) -> io::Result { - Ok(self.accessed) + self.file_time + .accessed + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "last access time is not valid")) } pub fn created(&self) -> io::Result { - Ok(self.created) + self.created + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "creation time is not valid")) } fn from_uefi(info: helpers::UefiBox) -> Self { @@ -82,8 +86,10 @@ fn from_uefi(info: helpers::UefiBox) -> Self { Self { attr: (*info.as_ptr()).attribute, size: (*info.as_ptr()).file_size, - modified: uefi_fs::uefi_to_systemtime((*info.as_ptr()).modification_time), - accessed: uefi_fs::uefi_to_systemtime((*info.as_ptr()).last_access_time), + file_time: FileTimes { + modified: uefi_fs::uefi_to_systemtime((*info.as_ptr()).modification_time), + accessed: uefi_fs::uefi_to_systemtime((*info.as_ptr()).last_access_time), + }, created: uefi_fs::uefi_to_systemtime((*info.as_ptr()).create_time), } } @@ -627,9 +633,9 @@ pub(crate) fn mkdir(path: &Path) -> io::Result<()> { /// EDK2 FAT driver uses EFI_UNSPECIFIED_TIMEZONE to represent localtime. So for proper /// conversion to SystemTime, we use the current time to get the timezone in such cases. - pub(crate) fn uefi_to_systemtime(mut time: r_efi::efi::Time) -> SystemTime { + pub(crate) fn uefi_to_systemtime(mut time: r_efi::efi::Time) -> Option { time.timezone = if time.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE { - time::system_time_internal::now().unwrap().timezone + time::system_time_internal::now().timezone } else { time.timezone }; @@ -639,7 +645,7 @@ pub(crate) fn uefi_to_systemtime(mut time: r_efi::efi::Time) -> SystemTime { /// Convert to UEFI Time with the current timezone. #[expect(dead_code)] fn systemtime_to_uefi(time: SystemTime) -> r_efi::efi::Time { - let now = time::system_time_internal::now().unwrap(); + let now = time::system_time_internal::now(); time.to_uefi_loose(now.timezone, now.daylight) } } diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index f9f90a454976..28dacbe3068a 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -24,7 +24,8 @@ daylight: 0, pad1: 0, pad2: 0, -}); +}) +.unwrap(); const MAX_UEFI_TIME: SystemTime = SystemTime::from_uefi(r_efi::efi::Time { year: 9999, @@ -38,7 +39,8 @@ daylight: 0, pad1: 0, pad2: 0, -}); +}) +.unwrap(); impl Instant { pub fn now() -> Instant { @@ -68,8 +70,11 @@ pub fn checked_sub_duration(&self, other: &Duration) -> Option { } impl SystemTime { - pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Self { - Self(system_time_internal::from_uefi(&t)) + pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Option { + match system_time_internal::from_uefi(&t) { + Some(x) => Some(Self(x)), + None => None, + } } pub(crate) const fn to_uefi( @@ -96,9 +101,8 @@ pub(crate) fn to_uefi_loose(self, timezone: i16, daylight: u8) -> r_efi::efi::Ti } pub fn now() -> SystemTime { - system_time_internal::now() - .map(Self::from_uefi) - .unwrap_or_else(|| panic!("time not implemented on this platform")) + Self::from_uefi(system_time_internal::now()) + .expect("time incorrectly implemented on this platform") } pub fn sub_time(&self, other: &SystemTime) -> Result { @@ -129,17 +133,18 @@ pub(crate) mod system_time_internal { const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24; const SYSTEMTIME_TIMEZONE: i64 = -1440 * SECS_IN_MINUTE as i64; - pub(crate) fn now() -> Option { @@ -16,7 +16,7 @@ help: you might be missing a type parameter LL | fn mk_array(_x: T) -> [(); >::SIZE] {} | +++ -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/projection-error.rs:14:29 | LL | pub trait Tr { @@ -36,4 +36,4 @@ LL | fn mk_array(_x: T) -> [(); >::SIZE] {} error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/const-generics/parent_generics_of_nested_in_default.stderr b/tests/ui/const-generics/parent_generics_of_nested_in_default.stderr index 24e05482a1a9..00eeecb9595f 100644 --- a/tests/ui/const-generics/parent_generics_of_nested_in_default.stderr +++ b/tests/ui/const-generics/parent_generics_of_nested_in_default.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Tr` in this scope +error[E0425]: cannot find type `Tr` in this scope --> $DIR/parent_generics_of_nested_in_default.rs:1:36 | LL | impl Tr {} @@ -20,5 +20,4 @@ LL | impl Tr {} error: aborting due to 3 previous errors -Some errors have detailed explanations: E0412, E0425. -For more information about an error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/const-generics/trait-resolution-error-with-const-generics-77919.stderr b/tests/ui/const-generics/trait-resolution-error-with-const-generics-77919.stderr index bac8abf46dce..2aa79df09657 100644 --- a/tests/ui/const-generics/trait-resolution-error-with-const-generics-77919.stderr +++ b/tests/ui/const-generics/trait-resolution-error-with-const-generics-77919.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `PhantomData` in this scope +error[E0425]: cannot find type `PhantomData` in this scope --> $DIR/trait-resolution-error-with-const-generics-77919.rs:10:9 | LL | _n: PhantomData, @@ -9,7 +9,7 @@ help: consider importing this struct LL + use std::marker::PhantomData; | -error[E0412]: cannot find type `VAL` in this scope +error[E0425]: cannot find type `VAL` in this scope --> $DIR/trait-resolution-error-with-const-generics-77919.rs:12:63 | LL | impl TypeVal for Multiply where N: TypeVal {} @@ -31,5 +31,5 @@ LL | impl TypeVal for Multiply where N: TypeVal {} error: aborting due to 3 previous errors -Some errors have detailed explanations: E0046, E0412. +Some errors have detailed explanations: E0046, E0425. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/const-generics/type_not_in_scope.stderr b/tests/ui/const-generics/type_not_in_scope.stderr index 5f45550a6279..f676108d37d0 100644 --- a/tests/ui/const-generics/type_not_in_scope.stderr +++ b/tests/ui/const-generics/type_not_in_scope.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `X` in this scope +error[E0425]: cannot find type `X` in this scope --> $DIR/type_not_in_scope.rs:1:6 | LL | impl X { @@ -20,5 +20,5 @@ LL | fn getn() -> [u8; N] {} error: aborting due to 3 previous errors -Some errors have detailed explanations: E0308, E0412, E0573. +Some errors have detailed explanations: E0308, E0425, E0573. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/unknown_adt.stderr b/tests/ui/const-generics/unknown_adt.stderr index 2e8210772e94..b905299daf62 100644 --- a/tests/ui/const-generics/unknown_adt.stderr +++ b/tests/ui/const-generics/unknown_adt.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `UnknownStruct` in this scope +error[E0425]: cannot find type `UnknownStruct` in this scope --> $DIR/unknown_adt.rs:2:12 | LL | let _: UnknownStruct<7>; @@ -6,4 +6,4 @@ LL | let _: UnknownStruct<7>; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr index 586c96011e43..3da0f17dcf80 100644 --- a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr +++ b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr @@ -9,7 +9,7 @@ help: consider introducing lifetime `'a` here LL | pub struct Opcode2<'a>(&'a S); | ++++ -error[E0412]: cannot find type `S` in this scope +error[E0425]: cannot find type `S` in this scope --> $DIR/ice-type-mismatch-when-copying-112824.rs:5:24 | LL | pub struct Opcode2(&'a S); @@ -22,5 +22,5 @@ LL | pub struct Opcode2(&'a S); error: aborting due to 2 previous errors -Some errors have detailed explanations: E0261, E0412. +Some errors have detailed explanations: E0261, E0425. For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/consts/erroneous_type_in_const_return_value.stderr b/tests/ui/consts/erroneous_type_in_const_return_value.stderr index 453f5b640973..9f743fa48efc 100644 --- a/tests/ui/consts/erroneous_type_in_const_return_value.stderr +++ b/tests/ui/consts/erroneous_type_in_const_return_value.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Sum` in this scope +error[E0425]: cannot find type `Sum` in this scope --> $DIR/erroneous_type_in_const_return_value.rs:6:22 | LL | UnusedByTheConst(Sum), @@ -11,4 +11,4 @@ LL + use std::iter::Sum; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/consts/erroneous_type_in_promoted.stderr b/tests/ui/consts/erroneous_type_in_promoted.stderr index 0601fc9ebe7f..ce8d58482fc2 100644 --- a/tests/ui/consts/erroneous_type_in_promoted.stderr +++ b/tests/ui/consts/erroneous_type_in_promoted.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Sum` in this scope +error[E0425]: cannot find type `Sum` in this scope --> $DIR/erroneous_type_in_promoted.rs:6:22 | LL | UnusedByTheConst(Sum), @@ -11,4 +11,4 @@ LL + use std::iter::Sum; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/consts/error-is-freeze.stderr b/tests/ui/consts/error-is-freeze.stderr index f3bfd1ea5e29..51f6b0efec33 100644 --- a/tests/ui/consts/error-is-freeze.stderr +++ b/tests/ui/consts/error-is-freeze.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `UndefinedType` in this scope +error[E0425]: cannot find type `UndefinedType` in this scope --> $DIR/error-is-freeze.rs:4:17 | LL | foo: Option, @@ -11,4 +11,4 @@ LL | struct MyStruct { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/consts/ice-bad-input-type-for-cast-83056.stderr b/tests/ui/consts/ice-bad-input-type-for-cast-83056.stderr index 4fc5972051c2..9eb19a0eaca7 100644 --- a/tests/ui/consts/ice-bad-input-type-for-cast-83056.stderr +++ b/tests/ui/consts/ice-bad-input-type-for-cast-83056.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/ice-bad-input-type-for-cast-83056.rs:5:11 | LL | struct S([bool; f as usize]); @@ -18,4 +18,4 @@ LL | fn f() -> T {} error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr index 887fcf0b73c4..98b80383c3dc 100644 --- a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr +++ b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Set` in this scope +error[E0425]: cannot find type `Set` in this scope --> $DIR/issue-56028-there-is-an-enum-variant.rs:10:15 | LL | fn setup() -> Set { Set } @@ -40,5 +40,4 @@ LL + use PutDown::Set; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0412, E0425. -For more information about an error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.stderr b/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.stderr index ca8f8cc07afb..2e268082cefb 100644 --- a/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.stderr +++ b/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Range` in this scope +error[E0425]: cannot find type `Range` in this scope --> $DIR/sugg-stable-import-first-issue-140240.rs:3:14 | LL | const _: Range = 0..1; @@ -17,4 +17,4 @@ LL + use std::range::Range; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/dropck/drop-on-non-struct.stderr b/tests/ui/dropck/drop-on-non-struct.stderr index 9495642e45e4..6a23c4c174aa 100644 --- a/tests/ui/dropck/drop-on-non-struct.stderr +++ b/tests/ui/dropck/drop-on-non-struct.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Nonexistent` in this scope +error[E0425]: cannot find type `Nonexistent` in this scope --> $DIR/drop-on-non-struct.rs:9:15 | LL | impl Drop for Nonexistent { @@ -24,5 +24,5 @@ LL | impl<'a> Drop for &'a mut isize { error: aborting due to 3 previous errors -Some errors have detailed explanations: E0117, E0120, E0412. +Some errors have detailed explanations: E0117, E0120, E0425. For more information about an error, try `rustc --explain E0117`. diff --git a/tests/ui/dyn-compatibility/erroneous_signature.stderr b/tests/ui/dyn-compatibility/erroneous_signature.stderr index f3b14ffe34c3..8077f224f064 100644 --- a/tests/ui/dyn-compatibility/erroneous_signature.stderr +++ b/tests/ui/dyn-compatibility/erroneous_signature.stderr @@ -1,10 +1,10 @@ -error[E0412]: cannot find type `MissingType` in this scope +error[E0425]: cannot find type `MissingType` in this scope --> $DIR/erroneous_signature.rs:2:22 | LL | fn err(&self) -> MissingType; | ^^^^^^^^^^^ not found in this scope -error[E0412]: cannot find type `MissingType` in this scope +error[E0425]: cannot find type `MissingType` in this scope --> $DIR/erroneous_signature.rs:7:22 | LL | fn err(&self) -> MissingType { @@ -12,4 +12,4 @@ LL | fn err(&self) -> MissingType { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/enum-discriminant/ice-from-type-error-issue-148515.stderr b/tests/ui/enum-discriminant/ice-from-type-error-issue-148515.stderr index d9f40c7c0f73..37a972a6a830 100644 --- a/tests/ui/enum-discriminant/ice-from-type-error-issue-148515.stderr +++ b/tests/ui/enum-discriminant/ice-from-type-error-issue-148515.stderr @@ -1,10 +1,10 @@ -error[E0412]: cannot find type `Foo` in this scope +error[E0425]: cannot find type `Foo` in this scope --> $DIR/ice-from-type-error-issue-148515.rs:7:34 | LL | fn test1(x: impl Iterator) { | ^^^ not found in this scope -error[E0412]: cannot find type `Foo` in this scope +error[E0425]: cannot find type `Foo` in this scope --> $DIR/ice-from-type-error-issue-148515.rs:12:34 | LL | fn test2(_: impl Iterator) { @@ -20,5 +20,5 @@ LL | 0u8 == -3; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0412, E0600. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0600. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/error-codes/E0412.rs b/tests/ui/error-codes/E0412.rs index 5f922a50a68e..2c69c5e6b5cf 100644 --- a/tests/ui/error-codes/E0412.rs +++ b/tests/ui/error-codes/E0412.rs @@ -1,4 +1,4 @@ -impl Something {} //~ ERROR E0412 +impl Something {} //~ ERROR E0425 fn main() { } diff --git a/tests/ui/error-codes/E0412.stderr b/tests/ui/error-codes/E0412.stderr index 7c1172642faf..4a4abf009c84 100644 --- a/tests/ui/error-codes/E0412.stderr +++ b/tests/ui/error-codes/E0412.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Something` in this scope +error[E0425]: cannot find type `Something` in this scope --> $DIR/E0412.rs:1:6 | LL | impl Something {} @@ -6,4 +6,4 @@ LL | impl Something {} error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/extern/issue-112363-extern-item-where-clauses-debug-ice.stderr b/tests/ui/extern/issue-112363-extern-item-where-clauses-debug-ice.stderr index 039e50b5e12d..b63cc29e5606 100644 --- a/tests/ui/extern/issue-112363-extern-item-where-clauses-debug-ice.stderr +++ b/tests/ui/extern/issue-112363-extern-item-where-clauses-debug-ice.stderr @@ -20,13 +20,13 @@ LL | type Item = [T] where [T]: Sized; | = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/issue-112363-extern-item-where-clauses-debug-ice.rs:2:28 | LL | type Item = [T] where [T]: Sized; | ^ not found in this scope -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/issue-112363-extern-item-where-clauses-debug-ice.rs:2:18 | LL | type Item = [T] where [T]: Sized; @@ -44,5 +44,5 @@ LL | type Item = [T] where [T]: Sized; error: aborting due to 5 previous errors -Some errors have detailed explanations: E0412, E0658. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0658. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/fn/trait-fn-generic-mismatch.stderr b/tests/ui/fn/trait-fn-generic-mismatch.stderr index 8384d74e225a..470865ae3a68 100644 --- a/tests/ui/fn/trait-fn-generic-mismatch.stderr +++ b/tests/ui/fn/trait-fn-generic-mismatch.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `XXX` in this scope +error[E0425]: cannot find type `XXX` in this scope --> $DIR/trait-fn-generic-mismatch.rs:5:11 | LL | impl Core { @@ -28,5 +28,5 @@ LL + core.spawn(); error: aborting due to 2 previous errors -Some errors have detailed explanations: E0061, E0412. +Some errors have detailed explanations: E0061, E0425. For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr b/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr index 9d4ea01152cc..af425cc6ed82 100644 --- a/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr +++ b/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/fn-help-with-err-generic-is-not-function.rs:2:13 | LL | impl Struct @@ -9,7 +9,7 @@ help: you might be missing a type parameter LL | impl Struct | +++ -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/fn-help-with-err-generic-is-not-function.rs:7:5 | LL | T: Copy, @@ -17,4 +17,4 @@ LL | T: Copy, error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/generic-associated-types/equality-bound.stderr b/tests/ui/generic-associated-types/equality-bound.stderr index a054c06caebd..03fafe3e21c1 100644 --- a/tests/ui/generic-associated-types/equality-bound.stderr +++ b/tests/ui/generic-associated-types/equality-bound.stderr @@ -110,7 +110,7 @@ LL - fn from_iter(_: T) -> Self where T::Item = A, T: IntoIterator, LL + fn from_iter(_: T) -> Self where T: IntoIterator, | -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/equality-bound.rs:20:79 | LL | fn from_iter(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A, @@ -119,7 +119,7 @@ LL | fn from_iter(_: T) -> Self where T: IntoIterator, IntoIterator::Item LL | struct K {} | -------- similarly named struct `K` defined here -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/equality-bound.rs:31:68 | LL | fn from_iter(_: T) -> Self where T: IntoIterator, T::Item = A, @@ -128,7 +128,7 @@ LL | fn from_iter(_: T) -> Self where T: IntoIterator, T::Item = A, LL | struct K {} | -------- similarly named struct `K` defined here -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/equality-bound.rs:42:76 | LL | fn from_iter(_: T) -> Self where IntoIterator::Item = A, @@ -137,7 +137,7 @@ LL | fn from_iter(_: T) -> Self where IntoIterator::Item = LL | struct K {} | -------- similarly named struct `K` defined here -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/equality-bound.rs:53:65 | LL | struct K {} @@ -146,7 +146,7 @@ LL | struct K {} LL | fn from_iter(_: T) -> Self where T::Item = A, | ^ help: a struct with a similar name exists: `K` -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/equality-bound.rs:64:62 | LL | struct K {} @@ -155,7 +155,7 @@ LL | struct K {} LL | fn from_iter(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator, | ^ help: a struct with a similar name exists: `K` -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/equality-bound.rs:75:51 | LL | struct K {} @@ -175,5 +175,5 @@ LL | fn sum3(i: J) -> i32 where I::Item = i32 { error: aborting due to 16 previous errors -Some errors have detailed explanations: E0412, E0433. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0433. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/hygiene/arguments.stderr b/tests/ui/hygiene/arguments.stderr index fe92daf64379..eff6ecd47a5b 100644 --- a/tests/ui/hygiene/arguments.stderr +++ b/tests/ui/hygiene/arguments.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `S` in this scope +error[E0425]: cannot find type `S` in this scope --> $DIR/arguments.rs:14:8 | LL | struct S; @@ -9,4 +9,4 @@ LL | m!(S, S); error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/hygiene/generate-mod.stderr b/tests/ui/hygiene/generate-mod.stderr index 58b9c642dabe..bfdb72c22cb9 100644 --- a/tests/ui/hygiene/generate-mod.stderr +++ b/tests/ui/hygiene/generate-mod.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `FromOutside` in this scope +error[E0425]: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:35:13 | LL | type A = $FromOutside; @@ -7,7 +7,7 @@ LL | type A = $FromOutside; LL | genmod!(FromOutside, Outer); | ^^^^^^^^^^^ not found in this scope -error[E0412]: cannot find type `Outer` in this scope +error[E0425]: cannot find type `Outer` in this scope --> $DIR/generate-mod.rs:35:26 | LL | struct $Outer; @@ -16,7 +16,7 @@ LL | struct $Outer; LL | genmod!(FromOutside, Outer); | ^^^^^ not found in this scope -error[E0412]: cannot find type `FromOutside` in this scope +error[E0425]: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:19:18 | LL | type A = FromOutside; @@ -27,7 +27,7 @@ LL | genmod_transparent!(); | = note: this error originates in the macro `genmod_transparent` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `Outer` in this scope +error[E0425]: cannot find type `Outer` in this scope --> $DIR/generate-mod.rs:20:22 | LL | type Inner = Outer; @@ -38,7 +38,7 @@ LL | genmod_transparent!(); | = note: this error originates in the macro `genmod_transparent` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `FromOutside` in this scope +error[E0425]: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:28:18 | LL | type A = FromOutside; @@ -49,7 +49,7 @@ LL | genmod_legacy!(); | = note: this error originates in the macro `genmod_legacy` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `Outer` in this scope +error[E0425]: cannot find type `Outer` in this scope --> $DIR/generate-mod.rs:29:22 | LL | type Inner = Outer; @@ -62,4 +62,4 @@ LL | genmod_legacy!(); error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/impl-trait/in-trait/ensure-rpitits-are-created-before-freezing.stderr b/tests/ui/impl-trait/in-trait/ensure-rpitits-are-created-before-freezing.stderr index c172787e6ef2..724576005877 100644 --- a/tests/ui/impl-trait/in-trait/ensure-rpitits-are-created-before-freezing.stderr +++ b/tests/ui/impl-trait/in-trait/ensure-rpitits-are-created-before-freezing.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/ensure-rpitits-are-created-before-freezing.rs:8:19 | LL | impl Iterable for Missing { @@ -6,4 +6,4 @@ LL | impl Iterable for Missing { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/impl-trait/in-trait/refine-err.stderr b/tests/ui/impl-trait/in-trait/refine-err.stderr index 6b4ef74d50af..d667b1209dd0 100644 --- a/tests/ui/impl-trait/in-trait/refine-err.stderr +++ b/tests/ui/impl-trait/in-trait/refine-err.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/refine-err.rs:4:38 | LL | fn prepare(self) -> impl Fn() -> T; @@ -6,4 +6,4 @@ LL | fn prepare(self) -> impl Fn() -> T; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.stderr b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.stderr index e7d38f224064..dd0de45bbf53 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.stderr +++ b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/rpitit-shadowed-by-missing-adt.rs:6:35 | LL | fn w() -> impl Deref>; @@ -6,4 +6,4 @@ LL | fn w() -> impl Deref>; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/impl-trait/issues/issue-54966.stderr b/tests/ui/impl-trait/issues/issue-54966.stderr index 4024c5afa80b..fe20bf42ffc1 100644 --- a/tests/ui/impl-trait/issues/issue-54966.stderr +++ b/tests/ui/impl-trait/issues/issue-54966.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Oper` in this scope +error[E0425]: cannot find type `Oper` in this scope --> $DIR/issue-54966.rs:3:27 | LL | fn generate_duration() -> Oper {} @@ -6,4 +6,4 @@ LL | fn generate_duration() -> Oper {} error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr index 73e7890f91fd..ffa58f4faeee 100644 --- a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr +++ b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr @@ -11,7 +11,7 @@ LL - fn frob() -> impl Fn + '_ {} LL + fn frob() -> impl Fn + 'static {} | -error[E0412]: cannot find type `P` in this scope +error[E0425]: cannot find type `P` in this scope --> $DIR/opaque-used-in-extraneous-argument.rs:5:22 | LL | fn frob() -> impl Fn + '_ {} @@ -22,7 +22,7 @@ help: you might be missing a type parameter LL | fn frob

` (where P is one of the previous types except `Self`) error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/inference_var_self_argument.rs:5:5 + --> $DIR/inference_var_self_argument.rs:5:33 | LL | async fn foo(self: &dyn Foo) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible + | ^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit diff --git a/tests/ui/async-await/issue-64130-3-other.stderr b/tests/ui/async-await/issue-64130-3-other.stderr index d683366ed473..531a7028f7e0 100644 --- a/tests/ui/async-await/issue-64130-3-other.stderr +++ b/tests/ui/async-await/issue-64130-3-other.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future $DIR/issue-64130-3-other.rs:25:12 | LL | async fn bar() { - | -------------- within this `impl Future` + | - within this `impl Future` ... LL | is_qux(bar()); | ^^^^^ unsatisfied trait bound diff --git a/tests/ui/async-await/issues/issue-67893.stderr b/tests/ui/async-await/issues/issue-67893.stderr index 34f28dd53c7b..610ed60bc8fd 100644 --- a/tests/ui/async-await/issues/issue-67893.stderr +++ b/tests/ui/async-await/issues/issue-67893.stderr @@ -6,10 +6,10 @@ LL | g(issue_67893::run()) | | | required by a bound introduced by this call | - ::: $DIR/auxiliary/issue_67893.rs:9:1 + ::: $DIR/auxiliary/issue_67893.rs:9:19 | LL | pub async fn run() { - | ------------------ within this `impl Future` + | - within this `impl Future` | = help: within `impl Future`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, ()>` note: required because it's used within this `async` fn body diff --git a/tests/ui/async-await/partial-drop-partial-reinit.stderr b/tests/ui/async-await/partial-drop-partial-reinit.stderr index cef835f7aed8..cf4b408ad12b 100644 --- a/tests/ui/async-await/partial-drop-partial-reinit.stderr +++ b/tests/ui/async-await/partial-drop-partial-reinit.stderr @@ -7,7 +7,7 @@ LL | gimme_send(foo()); | required by a bound introduced by this call ... LL | async fn foo() { - | -------------- within this `impl Future` + | - within this `impl Future` | help: within `impl Future`, the trait `Send` is not implemented for `NotSend` --> $DIR/partial-drop-partial-reinit.rs:19:1 diff --git a/tests/ui/c-variadic/not-async.stderr b/tests/ui/c-variadic/not-async.stderr index fc5eb10bec4f..bb8cc64e15fa 100644 --- a/tests/ui/c-variadic/not-async.stderr +++ b/tests/ui/c-variadic/not-async.stderr @@ -14,9 +14,9 @@ error[E0700]: hidden type for `impl Future` captures lifetime that --> $DIR/not-async.rs:5:65 | LL | async unsafe extern "C" fn fn_cannot_be_async(x: isize, _: ...) {} - | --------------------------------------------------------------- ^^ - | | - | opaque type defined here + | -^^ + | | + | opaque type defined here | = note: hidden type `{async fn body of fn_cannot_be_async()}` captures lifetime `'_` @@ -24,9 +24,9 @@ error[E0700]: hidden type for `impl Future` captures lifetime that --> $DIR/not-async.rs:12:73 | LL | async unsafe extern "C" fn method_cannot_be_async(x: isize, _: ...) {} - | ------------------------------------------------------------------- ^^ - | | - | opaque type defined here + | -^^ + | | + | opaque type defined here | = note: hidden type `{async fn body of S::method_cannot_be_async()}` captures lifetime `'_` diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/c-variadic.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/c-variadic.stderr index c8f4ef98c124..2a2d769c7cf8 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/c-variadic.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/c-variadic.stderr @@ -25,10 +25,10 @@ LL | async unsafe extern "cmse-nonsecure-entry" fn async_and_c_variadic(_: ...) = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list error[E0798]: `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/c-variadic.rs:26:1 + --> $DIR/c-variadic.rs:26:69 | LL | async unsafe extern "cmse-nonsecure-entry" fn async_is_not_allowed() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ error: aborting due to 4 previous errors diff --git a/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr b/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr index 19ffff9d3f2b..75d722402096 100644 --- a/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr +++ b/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr @@ -1,11 +1,11 @@ error[E0310]: the associated type `impl T` may not live long enough - --> $DIR/async-and-ret-ref.rs:7:5 + --> $DIR/async-and-ret-ref.rs:7:23 | LL | async fn foo() -> &'static impl T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | the associated type `impl T` must be valid for the static lifetime... - | ...so that the reference type `&'static impl T` does not outlive the data it points at + | ^^^^^^^^^^^^^^^ + | | + | the associated type `impl T` must be valid for the static lifetime... + | ...so that the reference type `&'static impl T` does not outlive the data it points at error: aborting due to 1 previous error diff --git a/tests/ui/inference/note-and-explain-ReVar-124973.stderr b/tests/ui/inference/note-and-explain-ReVar-124973.stderr index bb37e6231a32..2b5e79e9a1c6 100644 --- a/tests/ui/inference/note-and-explain-ReVar-124973.stderr +++ b/tests/ui/inference/note-and-explain-ReVar-124973.stderr @@ -8,9 +8,9 @@ error[E0700]: hidden type for `impl Future` captures lifetime that --> $DIR/note-and-explain-ReVar-124973.rs:5:76 | LL | async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, _: ...) {} - | -------------------------------------------------------------------------- ^^ - | | - | opaque type defined here + | -^^ + | | + | opaque type defined here | = note: hidden type `{async fn body of multiple_named_lifetimes<'a, 'b>()}` captures lifetime `'_` diff --git a/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr index 945d38d17f63..bb8e84724257 100644 --- a/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr +++ b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr @@ -34,24 +34,18 @@ LL | for<'a> >::Output: Future + 'a, = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` - --> $DIR/issue-76168-hr-outlives-3.rs:6:1 + --> $DIR/issue-76168-hr-outlives-3.rs:6:26 | -LL | / async fn wrapper(f: F) -... | -LL | | F:, -LL | | for<'a> >::Output: Future + 'a, - | |__________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32` +LL | async fn wrapper(f: F) + | ^ expected an `FnOnce(&'a mut i32)` closure, found `i32` | = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` - --> $DIR/issue-76168-hr-outlives-3.rs:6:1 + --> $DIR/issue-76168-hr-outlives-3.rs:6:26 | -LL | / async fn wrapper(f: F) -... | -LL | | F:, -LL | | for<'a> >::Output: Future + 'a, - | |__________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32` +LL | async fn wrapper(f: F) + | ^ expected an `FnOnce(&'a mut i32)` closure, found `i32` | = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr b/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr index 15902bf16de5..c325718b3033 100644 --- a/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr +++ b/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr @@ -8,15 +8,12 @@ LL | #![feature(non_lifetime_binders)] = note: `#[warn(incomplete_features)]` on by default error[E0309]: the placeholder type `F` may not live long enough - --> $DIR/type-match-with-late-bound.rs:8:1 + --> $DIR/type-match-with-late-bound.rs:8:32 | -LL | async fn walk2<'a, T: 'a>(_: T) - | ^ -- the placeholder type `F` must be valid for the lifetime `'a` as defined here... - | _| - | | -LL | | where -LL | | for F: 'a, - | |_________________^ ...so that the type `F` will meet its required lifetime bounds... +LL | async fn walk2<'a, T: 'a>(_: T) + | -- ^ ...so that the type `F` will meet its required lifetime bounds... + | | + | the placeholder type `F` must be valid for the lifetime `'a` as defined here... | note: ...that is required by this bound --> $DIR/type-match-with-late-bound.rs:10:15 diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr index 2aacf9698379..87313e349524 100644 --- a/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr +++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr @@ -18,10 +18,10 @@ LL | call(operation).await | ^^^^^^^^^^^^^^^ expected `{async fn body of operation()}`, got `FutNothing<'_>` | note: previous use here - --> $DIR/hkl_forbidden4.rs:12:1 + --> $DIR/hkl_forbidden4.rs:12:35 | LL | async fn operation(_: &mut ()) -> () { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ error: aborting due to 2 previous errors From 76f02cf142b24ce73794c72d196094192144d47c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 4 Nov 2025 18:08:36 +0000 Subject: [PATCH 427/585] Add test for `dyn Trait` in `async fn` return type --- .../async-fn/dyn-in-return-type.rs | 10 ++++++++ .../async-fn/dyn-in-return-type.stderr | 25 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 tests/ui/async-await/async-fn/dyn-in-return-type.rs create mode 100644 tests/ui/async-await/async-fn/dyn-in-return-type.stderr diff --git a/tests/ui/async-await/async-fn/dyn-in-return-type.rs b/tests/ui/async-await/async-fn/dyn-in-return-type.rs new file mode 100644 index 000000000000..ec793bf80f28 --- /dev/null +++ b/tests/ui/async-await/async-fn/dyn-in-return-type.rs @@ -0,0 +1,10 @@ +//@ edition:2024 + +async fn f() -> dyn core::fmt::Debug { +//~^ ERROR return type cannot be a trait object without pointer indirection +//~| HELP consider returning an `impl Trait` instead of a `dyn Trait` +//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new` + loop {} +} + +fn main() {} diff --git a/tests/ui/async-await/async-fn/dyn-in-return-type.stderr b/tests/ui/async-await/async-fn/dyn-in-return-type.stderr new file mode 100644 index 000000000000..6b1b092f5555 --- /dev/null +++ b/tests/ui/async-await/async-fn/dyn-in-return-type.stderr @@ -0,0 +1,25 @@ +error[E0746]: return type cannot be a trait object without pointer indirection + --> $DIR/dyn-in-return-type.rs:3:38 + | +LL | async fn f() -> dyn core::fmt::Debug { + | ______________________________________^ +... | +LL | | } + | |_^ doesn't have a size known at compile-time + | +help: consider returning an `impl Trait` instead of a `dyn Trait` + | +LL | async fn f() -> dyn core::fmt::Debug impl { + | ++++ +help: alternatively, box the return type, and wrap all of the returned values in `Box::new` + | +LL ~ async fn f() -> dyn core::fmt::Debug Box + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0746`. From 7868d20bd585906c19557ae7221ae5cc74a8f5e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 4 Nov 2025 18:11:51 +0000 Subject: [PATCH 428/585] Account for `async fn` with `dyn Trait` return type in `impl Trait` suggestion --- .../src/error_reporting/traits/suggestions.rs | 16 +++++++++++++++- .../async-fn/dyn-in-return-type.stderr | 13 +++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 1094f00e42f2..16bb4c186447 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1891,7 +1891,21 @@ pub(super) fn suggest_impl_trait( err.primary_message("return type cannot be a trait object without pointer indirection"); err.children.clear(); - let span = obligation.cause.span; + let mut span = obligation.cause.span; + if let DefKind::Closure = self.tcx.def_kind(obligation.cause.body_id) + && let parent = self.tcx.parent(obligation.cause.body_id.into()) + && let DefKind::Fn = self.tcx.def_kind(parent) + && self.tcx.asyncness(parent).is_async() + && let Some(parent) = parent.as_local() + && let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. }) = + self.tcx.hir_node_by_def_id(parent) + { + // Do not suggest (#147894) + // async fn foo() -> dyn Display impl { .. } + // and + // async fn foo() -> dyn Display Box + span = fn_sig.decl.output.span(); + } let body = self.tcx.hir_body_owned_by(obligation.cause.body_id); let mut visitor = ReturnsVisitor::default(); diff --git a/tests/ui/async-await/async-fn/dyn-in-return-type.stderr b/tests/ui/async-await/async-fn/dyn-in-return-type.stderr index 6b1b092f5555..bd2ee4c208ca 100644 --- a/tests/ui/async-await/async-fn/dyn-in-return-type.stderr +++ b/tests/ui/async-await/async-fn/dyn-in-return-type.stderr @@ -9,16 +9,13 @@ LL | | } | help: consider returning an `impl Trait` instead of a `dyn Trait` | -LL | async fn f() -> dyn core::fmt::Debug impl { - | ++++ +LL - async fn f() -> dyn core::fmt::Debug { +LL + async fn f() -> impl core::fmt::Debug { + | help: alternatively, box the return type, and wrap all of the returned values in `Box::new` | -LL ~ async fn f() -> dyn core::fmt::Debug Box - | +LL | async fn f() -> Box { + | ++++ + error: aborting due to 1 previous error From fabf5746a20876e49a8ce9fce3e6c859ba49f39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 4 Nov 2025 18:31:31 +0000 Subject: [PATCH 429/585] Add test for `type Alias = dyn Trait` in return type --- .../dyn-trait-type-alias-return-type.rs | 8 ++++++++ .../dyn-trait-type-alias-return-type.stderr | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/ui/type-alias/dyn-trait-type-alias-return-type.rs create mode 100644 tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr diff --git a/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs b/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs new file mode 100644 index 000000000000..f96cd989a4ce --- /dev/null +++ b/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs @@ -0,0 +1,8 @@ +type T = dyn core::fmt::Debug; + +fn f() -> T { loop {} } +//~^ ERROR return type cannot be a trait object without pointer indirection +//~| HELP +//~| HELP + +fn main() {} diff --git a/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr b/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr new file mode 100644 index 000000000000..d67ba7759551 --- /dev/null +++ b/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr @@ -0,0 +1,18 @@ +error[E0746]: return type cannot be a trait object without pointer indirection + --> $DIR/dyn-trait-type-alias-return-type.rs:3:11 + | +LL | fn f() -> T { loop {} } + | ^ doesn't have a size known at compile-time + | +help: consider returning an `impl Trait` instead of a `dyn Trait` + | +LL | fn f() -> impl T { loop {} } + | ++++ +help: alternatively, box the return type, and wrap all of the returned values in `Box::new` + | +LL | fn f() -> Box { Box::new(loop {}) } + | +++++++ + +++++++++ + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0746`. From 60b227acccf40cff72df2104fbdedc8185e8a57f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 4 Nov 2025 18:41:04 +0000 Subject: [PATCH 430/585] Recognize `type Alias = dyn Trait` in `fn` return types ``` error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time --> $DIR/dyn-trait-type-alias-return-type.rs:4:11 | LL | fn f() -> T { loop {} } | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)` note: this type alias is unsized --> $DIR/dyn-trait-type-alias-return-type.rs:1:1 | LL | type T = dyn core::fmt::Debug; | ^^^^^^ = note: the return type of a function must have a statically known size ``` --- .../src/error_reporting/traits/suggestions.rs | 13 +++++++ .../clippy/tests/ui/future_not_send.stderr | 37 +++++++++---------- .../dyn-trait-type-alias-return-type.rs | 10 +++-- .../dyn-trait-type-alias-return-type.stderr | 19 +++++----- tests/ui/unsized/issue-91801.rs | 2 +- tests/ui/unsized/issue-91801.stderr | 17 ++++----- 6 files changed, 54 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 16bb4c186447..822025b986b8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1886,6 +1886,19 @@ pub(super) fn suggest_impl_trait( let ty::Dynamic(_, _) = trait_pred.self_ty().skip_binder().kind() else { return false; }; + if let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. }) = + self.tcx.hir_node_by_def_id(obligation.cause.body_id) + && let hir::FnRetTy::Return(ty) = fn_sig.decl.output + && let hir::TyKind::Path(qpath) = ty.kind + && let hir::QPath::Resolved(None, path) = qpath + && let Res::Def(DefKind::TyAlias, def_id) = path.res + { + // Do not suggest + // type T = dyn Trait; + // fn foo() -> impl T { .. } + err.span_note(self.tcx.def_span(def_id), "this type alias is unsized"); + return false; + } err.code(E0746); err.primary_message("return type cannot be a trait object without pointer indirection"); diff --git a/src/tools/clippy/tests/ui/future_not_send.stderr b/src/tools/clippy/tests/ui/future_not_send.stderr index e366dc2d2195..8b8af1ebaed3 100644 --- a/src/tools/clippy/tests/ui/future_not_send.stderr +++ b/src/tools/clippy/tests/ui/future_not_send.stderr @@ -1,8 +1,8 @@ error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:8:1 + --> tests/ui/future_not_send.rs:8:62 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send` + | ^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await --> tests/ui/future_not_send.rs:11:20 @@ -23,10 +23,10 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { = help: to override `-D warnings` add `#[allow(clippy::future_not_send)]` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:14:1 + --> tests/ui/future_not_send.rs:14:41 | LL | pub async fn public_future(rc: Rc<[u8]>) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send` + | ^ future returned by `public_future` is not `Send` | note: future is not `Send` as this value is used across an await --> tests/ui/future_not_send.rs:17:20 @@ -39,10 +39,10 @@ LL | async { true }.await; = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:24:1 + --> tests/ui/future_not_send.rs:24:63 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future2` is not `Send` + | ^^^^ future returned by `private_future2` is not `Send` | note: captured value is not `Send` --> tests/ui/future_not_send.rs:24:26 @@ -58,10 +58,10 @@ LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { = note: `std::cell::Cell` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:30:1 + --> tests/ui/future_not_send.rs:30:42 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future2` is not `Send` + | ^ future returned by `public_future2` is not `Send` | note: captured value is not `Send` --> tests/ui/future_not_send.rs:30:29 @@ -71,10 +71,10 @@ LL | pub async fn public_future2(rc: Rc<[u8]>) {} = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:42:5 + --> tests/ui/future_not_send.rs:42:39 | LL | async fn private_future(&self) -> usize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send` + | ^^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await --> tests/ui/future_not_send.rs:45:24 @@ -87,10 +87,10 @@ LL | async { true }.await; = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:49:5 + --> tests/ui/future_not_send.rs:49:38 | LL | pub async fn public_future(&self) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send` + | ^ future returned by `public_future` is not `Send` | note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` --> tests/ui/future_not_send.rs:49:32 @@ -100,13 +100,10 @@ LL | pub async fn public_future(&self) { = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:61:1 + --> tests/ui/future_not_send.rs:61:37 | -LL | / async fn generic_future(t: T) -> T -LL | | -LL | | where -LL | | T: Send, - | |____________^ future returned by `generic_future` is not `Send` +LL | async fn generic_future(t: T) -> T + | ^ future returned by `generic_future` is not `Send` | note: future is not `Send` as this value is used across an await --> tests/ui/future_not_send.rs:67:20 @@ -118,10 +115,10 @@ LL | async { true }.await; = note: `T` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:83:1 + --> tests/ui/future_not_send.rs:83:51 | LL | async fn generic_future_always_unsend(_: Rc) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `generic_future_always_unsend` is not `Send` + | ^ future returned by `generic_future_always_unsend` is not `Send` | note: future is not `Send` as this value is used across an await --> tests/ui/future_not_send.rs:86:20 diff --git a/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs b/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs index f96cd989a4ce..fe1322a48d65 100644 --- a/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs +++ b/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs @@ -1,8 +1,10 @@ type T = dyn core::fmt::Debug; - +//~^ NOTE this type alias is unsized + fn f() -> T { loop {} } -//~^ ERROR return type cannot be a trait object without pointer indirection -//~| HELP -//~| HELP +//~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time +//~| HELP the trait `Sized` is not implemented for `(dyn Debug + 'static)` +//~| NOTE doesn't have a size known at compile-time +//~| NOTE the return type of a function must have a statically known size fn main() {} diff --git a/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr b/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr index d67ba7759551..fc7f9f49d165 100644 --- a/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr +++ b/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr @@ -1,18 +1,17 @@ -error[E0746]: return type cannot be a trait object without pointer indirection - --> $DIR/dyn-trait-type-alias-return-type.rs:3:11 +error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time + --> $DIR/dyn-trait-type-alias-return-type.rs:4:11 | LL | fn f() -> T { loop {} } | ^ doesn't have a size known at compile-time | -help: consider returning an `impl Trait` instead of a `dyn Trait` + = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)` +note: this type alias is unsized + --> $DIR/dyn-trait-type-alias-return-type.rs:1:1 | -LL | fn f() -> impl T { loop {} } - | ++++ -help: alternatively, box the return type, and wrap all of the returned values in `Box::new` - | -LL | fn f() -> Box { Box::new(loop {}) } - | +++++++ + +++++++++ + +LL | type T = dyn core::fmt::Debug; + | ^^^^^^ + = note: the return type of a function must have a statically known size error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0746`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unsized/issue-91801.rs b/tests/ui/unsized/issue-91801.rs index d906a08a55a2..8b4a3d214d5e 100644 --- a/tests/ui/unsized/issue-91801.rs +++ b/tests/ui/unsized/issue-91801.rs @@ -6,7 +6,7 @@ &[("validate that credits and debits balance", &validate_something)]; fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Validator<'a> { - //~^ ERROR return type cannot be a trait object without pointer indirection + //~^ ERROR E0277 return Box::new(move |something: &'_ Something| -> Result<(), ()> { first(something).or_else(|_| second(something)) }); diff --git a/tests/ui/unsized/issue-91801.stderr b/tests/ui/unsized/issue-91801.stderr index 28e10f9caa41..73f9de92458e 100644 --- a/tests/ui/unsized/issue-91801.stderr +++ b/tests/ui/unsized/issue-91801.stderr @@ -1,18 +1,17 @@ -error[E0746]: return type cannot be a trait object without pointer indirection +error[E0277]: the size for values of type `(dyn Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a)` cannot be known at compilation time --> $DIR/issue-91801.rs:8:77 | LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Validator<'a> { | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | -help: consider returning an `impl Trait` instead of a `dyn Trait` + = help: the trait `Sized` is not implemented for `(dyn Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a)` +note: this type alias is unsized + --> $DIR/issue-91801.rs:3:1 | -LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> impl Validator<'a> { - | ++++ -help: alternatively, box the return type, and wrap all of the returned values in `Box::new` - | -LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Box> { - | +++++++ + +LL | type Validator<'a> = dyn 'a + Send + Sync + Fn(&'a Something) -> Result<(), ()>; + | ^^^^^^^^^^^^^^^^^^ + = note: the return type of a function must have a statically known size error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0746`. +For more information about this error, try `rustc --explain E0277`. From e2168b1da1fbdeb9bfd5bee53cb358552fdbc3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 5 Nov 2025 18:28:44 +0000 Subject: [PATCH 431/585] Point at async fn return type instead of body in E0746 --- .../src/error_reporting/traits/suggestions.rs | 1 + tests/ui/async-await/async-fn/dyn-in-return-type.stderr | 9 +++------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 822025b986b8..e7f588a77f77 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1918,6 +1918,7 @@ pub(super) fn suggest_impl_trait( // and // async fn foo() -> dyn Display Box span = fn_sig.decl.output.span(); + err.span(span); } let body = self.tcx.hir_body_owned_by(obligation.cause.body_id); diff --git a/tests/ui/async-await/async-fn/dyn-in-return-type.stderr b/tests/ui/async-await/async-fn/dyn-in-return-type.stderr index bd2ee4c208ca..341d9561fd7a 100644 --- a/tests/ui/async-await/async-fn/dyn-in-return-type.stderr +++ b/tests/ui/async-await/async-fn/dyn-in-return-type.stderr @@ -1,11 +1,8 @@ error[E0746]: return type cannot be a trait object without pointer indirection - --> $DIR/dyn-in-return-type.rs:3:38 + --> $DIR/dyn-in-return-type.rs:3:17 | -LL | async fn f() -> dyn core::fmt::Debug { - | ______________________________________^ -... | -LL | | } - | |_^ doesn't have a size known at compile-time +LL | async fn f() -> dyn core::fmt::Debug { + | ^^^^^^^^^^^^^^^^^^^^ | help: consider returning an `impl Trait` instead of a `dyn Trait` | From 8c63852f1916cad2a9e5b125e879c38ba401bb84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 5 Nov 2025 18:48:40 +0000 Subject: [PATCH 432/585] Provide boxing suggestion for `type Alias = dyn Trait` return type --- .../src/error_reporting/traits/suggestions.rs | 11 +++++++++++ .../dyn-trait-type-alias-return-type.fixed | 18 ++++++++++++++++++ .../dyn-trait-type-alias-return-type.rs | 10 +++++++++- .../dyn-trait-type-alias-return-type.stderr | 19 ++++++++++++++++--- tests/ui/unsized/issue-91801.stderr | 4 ++++ 5 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 tests/ui/type-alias/dyn-trait-type-alias-return-type.fixed diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index e7f588a77f77..5ef6d05c419c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1897,6 +1897,17 @@ pub(super) fn suggest_impl_trait( // type T = dyn Trait; // fn foo() -> impl T { .. } err.span_note(self.tcx.def_span(def_id), "this type alias is unsized"); + err.multipart_suggestion( + format!( + "consider boxing the return type, and wrapping all of the returned values in \ + `Box::new`", + ), + vec![ + (ty.span.shrink_to_lo(), "Box<".to_string()), + (ty.span.shrink_to_hi(), ">".to_string()), + ], + Applicability::MaybeIncorrect, + ); return false; } diff --git a/tests/ui/type-alias/dyn-trait-type-alias-return-type.fixed b/tests/ui/type-alias/dyn-trait-type-alias-return-type.fixed new file mode 100644 index 000000000000..93472f808a8a --- /dev/null +++ b/tests/ui/type-alias/dyn-trait-type-alias-return-type.fixed @@ -0,0 +1,18 @@ +//@ run-rustfix +type T = dyn core::fmt::Debug; +//~^ NOTE this type alias is unsized + +fn f() -> Box { loop {} } +//~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time +//~| HELP the trait `Sized` is not implemented for `(dyn Debug + 'static)` +//~| NOTE doesn't have a size known at compile-time +//~| NOTE the return type of a function must have a statically known size +//~| HELP consider boxing the return type + +fn main() { + f(); + //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time + //~| HELP the trait `Sized` is not implemented for `(dyn Debug + 'static)` + //~| NOTE doesn't have a size known at compile-time + //~| NOTE the return type of a function must have a statically known size +} diff --git a/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs b/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs index fe1322a48d65..da9f8d07f8e0 100644 --- a/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs +++ b/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs @@ -1,3 +1,4 @@ +//@ run-rustfix type T = dyn core::fmt::Debug; //~^ NOTE this type alias is unsized @@ -6,5 +7,12 @@ fn f() -> T { loop {} } //~| HELP the trait `Sized` is not implemented for `(dyn Debug + 'static)` //~| NOTE doesn't have a size known at compile-time //~| NOTE the return type of a function must have a statically known size +//~| HELP consider boxing the return type -fn main() {} +fn main() { + f(); + //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time + //~| HELP the trait `Sized` is not implemented for `(dyn Debug + 'static)` + //~| NOTE doesn't have a size known at compile-time + //~| NOTE the return type of a function must have a statically known size +} diff --git a/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr b/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr index fc7f9f49d165..658abbe8f780 100644 --- a/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr +++ b/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr @@ -1,17 +1,30 @@ error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time - --> $DIR/dyn-trait-type-alias-return-type.rs:4:11 + --> $DIR/dyn-trait-type-alias-return-type.rs:5:11 | LL | fn f() -> T { loop {} } | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)` note: this type alias is unsized - --> $DIR/dyn-trait-type-alias-return-type.rs:1:1 + --> $DIR/dyn-trait-type-alias-return-type.rs:2:1 | LL | type T = dyn core::fmt::Debug; | ^^^^^^ = note: the return type of a function must have a statically known size +help: consider boxing the return type, and wrapping all of the returned values in `Box::new` + | +LL | fn f() -> Box { loop {} } + | ++++ + -error: aborting due to 1 previous error +error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time + --> $DIR/dyn-trait-type-alias-return-type.rs:13:5 + | +LL | f(); + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)` + = note: the return type of a function must have a statically known size + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unsized/issue-91801.stderr b/tests/ui/unsized/issue-91801.stderr index 73f9de92458e..192cdc767dd9 100644 --- a/tests/ui/unsized/issue-91801.stderr +++ b/tests/ui/unsized/issue-91801.stderr @@ -11,6 +11,10 @@ note: this type alias is unsized LL | type Validator<'a> = dyn 'a + Send + Sync + Fn(&'a Something) -> Result<(), ()>; | ^^^^^^^^^^^^^^^^^^ = note: the return type of a function must have a statically known size +help: consider boxing the return type, and wrapping all of the returned values in `Box::new` + | +LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Box> { + | ++++ + error: aborting due to 1 previous error From f7eaaf79e0520547b128a3066b5a59980f3b5844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 5 Nov 2025 19:59:08 +0000 Subject: [PATCH 433/585] Account for async fn in traits and impls --- .../src/error_reporting/traits/suggestions.rs | 13 ++++-- .../async-fn/dyn-in-return-type.fixed | 30 +++++++++++++ .../async-fn/dyn-in-return-type.rs | 24 ++++++++++- .../async-fn/dyn-in-return-type.stderr | 36 +++++++++++++++- .../dyn-trait-type-alias-return-type.fixed | 21 ++++++++++ .../dyn-trait-type-alias-return-type.rs | 21 ++++++++++ .../dyn-trait-type-alias-return-type.stderr | 42 +++++++++++++++++-- 7 files changed, 176 insertions(+), 11 deletions(-) create mode 100644 tests/ui/async-await/async-fn/dyn-in-return-type.fixed diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 5ef6d05c419c..fd845e31c909 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1886,7 +1886,9 @@ pub(super) fn suggest_impl_trait( let ty::Dynamic(_, _) = trait_pred.self_ty().skip_binder().kind() else { return false; }; - if let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. }) = + if let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. }) + | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(fn_sig, _), .. }) + | Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(fn_sig, _), .. }) = self.tcx.hir_node_by_def_id(obligation.cause.body_id) && let hir::FnRetTy::Return(ty) = fn_sig.decl.output && let hir::TyKind::Path(qpath) = ty.kind @@ -1918,11 +1920,14 @@ pub(super) fn suggest_impl_trait( let mut span = obligation.cause.span; if let DefKind::Closure = self.tcx.def_kind(obligation.cause.body_id) && let parent = self.tcx.parent(obligation.cause.body_id.into()) - && let DefKind::Fn = self.tcx.def_kind(parent) + && let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(parent) && self.tcx.asyncness(parent).is_async() && let Some(parent) = parent.as_local() - && let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. }) = - self.tcx.hir_node_by_def_id(parent) + && let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. }) + | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(fn_sig, _), .. }) + | Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(fn_sig, _), .. + }) = self.tcx.hir_node_by_def_id(parent) { // Do not suggest (#147894) // async fn foo() -> dyn Display impl { .. } diff --git a/tests/ui/async-await/async-fn/dyn-in-return-type.fixed b/tests/ui/async-await/async-fn/dyn-in-return-type.fixed new file mode 100644 index 000000000000..6a717f628460 --- /dev/null +++ b/tests/ui/async-await/async-fn/dyn-in-return-type.fixed @@ -0,0 +1,30 @@ +//@ edition:2024 +//@ run-rustfix + +async fn f() -> Box { +//~^ ERROR return type cannot be a trait object without pointer indirection +//~| HELP consider returning an `impl Trait` instead of a `dyn Trait` +//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new` + Box::new("") +} +trait T { + async fn f(&self) -> Box { + //~^ ERROR return type cannot be a trait object without pointer indirection + //~| HELP consider returning an `impl Trait` instead of a `dyn Trait` + //~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new` + Box::new("") + } +} +impl T for () { + async fn f(&self) -> Box { + //~^ ERROR return type cannot be a trait object without pointer indirection + //~| HELP consider returning an `impl Trait` instead of a `dyn Trait` + //~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new` + Box::new("") + } +} + +fn main() { + let _ = f(); + let _ = ().f(); +} diff --git a/tests/ui/async-await/async-fn/dyn-in-return-type.rs b/tests/ui/async-await/async-fn/dyn-in-return-type.rs index ec793bf80f28..47d5e371f55f 100644 --- a/tests/ui/async-await/async-fn/dyn-in-return-type.rs +++ b/tests/ui/async-await/async-fn/dyn-in-return-type.rs @@ -1,10 +1,30 @@ //@ edition:2024 +//@ run-rustfix async fn f() -> dyn core::fmt::Debug { //~^ ERROR return type cannot be a trait object without pointer indirection //~| HELP consider returning an `impl Trait` instead of a `dyn Trait` //~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new` - loop {} + Box::new("") +} +trait T { + async fn f(&self) -> dyn core::fmt::Debug { + //~^ ERROR return type cannot be a trait object without pointer indirection + //~| HELP consider returning an `impl Trait` instead of a `dyn Trait` + //~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new` + Box::new("") + } +} +impl T for () { + async fn f(&self) -> dyn core::fmt::Debug { + //~^ ERROR return type cannot be a trait object without pointer indirection + //~| HELP consider returning an `impl Trait` instead of a `dyn Trait` + //~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new` + Box::new("") + } } -fn main() {} +fn main() { + let _ = f(); + let _ = ().f(); +} diff --git a/tests/ui/async-await/async-fn/dyn-in-return-type.stderr b/tests/ui/async-await/async-fn/dyn-in-return-type.stderr index 341d9561fd7a..0d8a92d33cf9 100644 --- a/tests/ui/async-await/async-fn/dyn-in-return-type.stderr +++ b/tests/ui/async-await/async-fn/dyn-in-return-type.stderr @@ -1,5 +1,5 @@ error[E0746]: return type cannot be a trait object without pointer indirection - --> $DIR/dyn-in-return-type.rs:3:17 + --> $DIR/dyn-in-return-type.rs:4:17 | LL | async fn f() -> dyn core::fmt::Debug { | ^^^^^^^^^^^^^^^^^^^^ @@ -14,6 +14,38 @@ help: alternatively, box the return type, and wrap all of the returned values in LL | async fn f() -> Box { | ++++ + -error: aborting due to 1 previous error +error[E0746]: return type cannot be a trait object without pointer indirection + --> $DIR/dyn-in-return-type.rs:11:26 + | +LL | async fn f(&self) -> dyn core::fmt::Debug { + | ^^^^^^^^^^^^^^^^^^^^ + | +help: consider returning an `impl Trait` instead of a `dyn Trait` + | +LL - async fn f(&self) -> dyn core::fmt::Debug { +LL + async fn f(&self) -> impl core::fmt::Debug { + | +help: alternatively, box the return type, and wrap all of the returned values in `Box::new` + | +LL | async fn f(&self) -> Box { + | ++++ + + +error[E0746]: return type cannot be a trait object without pointer indirection + --> $DIR/dyn-in-return-type.rs:19:26 + | +LL | async fn f(&self) -> dyn core::fmt::Debug { + | ^^^^^^^^^^^^^^^^^^^^ + | +help: consider returning an `impl Trait` instead of a `dyn Trait` + | +LL - async fn f(&self) -> dyn core::fmt::Debug { +LL + async fn f(&self) -> impl core::fmt::Debug { + | +help: alternatively, box the return type, and wrap all of the returned values in `Box::new` + | +LL | async fn f(&self) -> Box { + | ++++ + + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0746`. diff --git a/tests/ui/type-alias/dyn-trait-type-alias-return-type.fixed b/tests/ui/type-alias/dyn-trait-type-alias-return-type.fixed index 93472f808a8a..ba94e1967df3 100644 --- a/tests/ui/type-alias/dyn-trait-type-alias-return-type.fixed +++ b/tests/ui/type-alias/dyn-trait-type-alias-return-type.fixed @@ -1,6 +1,8 @@ //@ run-rustfix type T = dyn core::fmt::Debug; //~^ NOTE this type alias is unsized +//~| NOTE this type alias is unsized +//~| NOTE this type alias is unsized fn f() -> Box { loop {} } //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time @@ -9,10 +11,29 @@ fn f() -> Box { loop {} } //~| NOTE the return type of a function must have a statically known size //~| HELP consider boxing the return type +trait X { + fn f(&self) -> Box { loop {} } + //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time + //~| HELP the trait `Sized` is not implemented for `(dyn Debug + 'static)` + //~| NOTE doesn't have a size known at compile-time + //~| NOTE the return type of a function must have a statically known size + //~| HELP consider boxing the return type +} + +impl X for () { + fn f(&self) -> Box { loop {} } + //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time + //~| HELP the trait `Sized` is not implemented for `(dyn Debug + 'static)` + //~| NOTE doesn't have a size known at compile-time + //~| NOTE the return type of a function must have a statically known size + //~| HELP consider boxing the return type +} + fn main() { f(); //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time //~| HELP the trait `Sized` is not implemented for `(dyn Debug + 'static)` //~| NOTE doesn't have a size known at compile-time //~| NOTE the return type of a function must have a statically known size + ().f(); } diff --git a/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs b/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs index da9f8d07f8e0..76f6e7c44342 100644 --- a/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs +++ b/tests/ui/type-alias/dyn-trait-type-alias-return-type.rs @@ -1,6 +1,8 @@ //@ run-rustfix type T = dyn core::fmt::Debug; //~^ NOTE this type alias is unsized +//~| NOTE this type alias is unsized +//~| NOTE this type alias is unsized fn f() -> T { loop {} } //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time @@ -9,10 +11,29 @@ fn f() -> T { loop {} } //~| NOTE the return type of a function must have a statically known size //~| HELP consider boxing the return type +trait X { + fn f(&self) -> T { loop {} } + //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time + //~| HELP the trait `Sized` is not implemented for `(dyn Debug + 'static)` + //~| NOTE doesn't have a size known at compile-time + //~| NOTE the return type of a function must have a statically known size + //~| HELP consider boxing the return type +} + +impl X for () { + fn f(&self) -> T { loop {} } + //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time + //~| HELP the trait `Sized` is not implemented for `(dyn Debug + 'static)` + //~| NOTE doesn't have a size known at compile-time + //~| NOTE the return type of a function must have a statically known size + //~| HELP consider boxing the return type +} + fn main() { f(); //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time //~| HELP the trait `Sized` is not implemented for `(dyn Debug + 'static)` //~| NOTE doesn't have a size known at compile-time //~| NOTE the return type of a function must have a statically known size + ().f(); } diff --git a/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr b/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr index 658abbe8f780..bb6951687048 100644 --- a/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr +++ b/tests/ui/type-alias/dyn-trait-type-alias-return-type.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time - --> $DIR/dyn-trait-type-alias-return-type.rs:5:11 + --> $DIR/dyn-trait-type-alias-return-type.rs:7:11 | LL | fn f() -> T { loop {} } | ^ doesn't have a size known at compile-time @@ -17,7 +17,43 @@ LL | fn f() -> Box { loop {} } | ++++ + error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time - --> $DIR/dyn-trait-type-alias-return-type.rs:13:5 + --> $DIR/dyn-trait-type-alias-return-type.rs:24:20 + | +LL | fn f(&self) -> T { loop {} } + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)` +note: this type alias is unsized + --> $DIR/dyn-trait-type-alias-return-type.rs:2:1 + | +LL | type T = dyn core::fmt::Debug; + | ^^^^^^ + = note: the return type of a function must have a statically known size +help: consider boxing the return type, and wrapping all of the returned values in `Box::new` + | +LL | fn f(&self) -> Box { loop {} } + | ++++ + + +error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time + --> $DIR/dyn-trait-type-alias-return-type.rs:15:20 + | +LL | fn f(&self) -> T { loop {} } + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)` +note: this type alias is unsized + --> $DIR/dyn-trait-type-alias-return-type.rs:2:1 + | +LL | type T = dyn core::fmt::Debug; + | ^^^^^^ + = note: the return type of a function must have a statically known size +help: consider boxing the return type, and wrapping all of the returned values in `Box::new` + | +LL | fn f(&self) -> Box { loop {} } + | ++++ + + +error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time + --> $DIR/dyn-trait-type-alias-return-type.rs:33:5 | LL | f(); | ^^^ doesn't have a size known at compile-time @@ -25,6 +61,6 @@ LL | f(); = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)` = note: the return type of a function must have a statically known size -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. From 94aa13a09c940202da24ad0a1ffcd986e4df2df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 4 Nov 2025 18:41:04 +0000 Subject: [PATCH 434/585] Recognize `type Alias = dyn Trait` in `fn` return types ``` error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time --> $DIR/dyn-trait-type-alias-return-type.rs:4:11 | LL | fn f() -> T { loop {} } | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)` note: this type alias is unsized --> $DIR/dyn-trait-type-alias-return-type.rs:1:1 | LL | type T = dyn core::fmt::Debug; | ^^^^^^ = note: the return type of a function must have a statically known size ``` --- tests/ui/future_not_send.stderr | 37 +++++++++++++++------------------ 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/tests/ui/future_not_send.stderr b/tests/ui/future_not_send.stderr index e366dc2d2195..8b8af1ebaed3 100644 --- a/tests/ui/future_not_send.stderr +++ b/tests/ui/future_not_send.stderr @@ -1,8 +1,8 @@ error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:8:1 + --> tests/ui/future_not_send.rs:8:62 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send` + | ^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await --> tests/ui/future_not_send.rs:11:20 @@ -23,10 +23,10 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { = help: to override `-D warnings` add `#[allow(clippy::future_not_send)]` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:14:1 + --> tests/ui/future_not_send.rs:14:41 | LL | pub async fn public_future(rc: Rc<[u8]>) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send` + | ^ future returned by `public_future` is not `Send` | note: future is not `Send` as this value is used across an await --> tests/ui/future_not_send.rs:17:20 @@ -39,10 +39,10 @@ LL | async { true }.await; = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:24:1 + --> tests/ui/future_not_send.rs:24:63 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future2` is not `Send` + | ^^^^ future returned by `private_future2` is not `Send` | note: captured value is not `Send` --> tests/ui/future_not_send.rs:24:26 @@ -58,10 +58,10 @@ LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { = note: `std::cell::Cell` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:30:1 + --> tests/ui/future_not_send.rs:30:42 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future2` is not `Send` + | ^ future returned by `public_future2` is not `Send` | note: captured value is not `Send` --> tests/ui/future_not_send.rs:30:29 @@ -71,10 +71,10 @@ LL | pub async fn public_future2(rc: Rc<[u8]>) {} = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:42:5 + --> tests/ui/future_not_send.rs:42:39 | LL | async fn private_future(&self) -> usize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send` + | ^^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await --> tests/ui/future_not_send.rs:45:24 @@ -87,10 +87,10 @@ LL | async { true }.await; = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:49:5 + --> tests/ui/future_not_send.rs:49:38 | LL | pub async fn public_future(&self) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send` + | ^ future returned by `public_future` is not `Send` | note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` --> tests/ui/future_not_send.rs:49:32 @@ -100,13 +100,10 @@ LL | pub async fn public_future(&self) { = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:61:1 + --> tests/ui/future_not_send.rs:61:37 | -LL | / async fn generic_future(t: T) -> T -LL | | -LL | | where -LL | | T: Send, - | |____________^ future returned by `generic_future` is not `Send` +LL | async fn generic_future(t: T) -> T + | ^ future returned by `generic_future` is not `Send` | note: future is not `Send` as this value is used across an await --> tests/ui/future_not_send.rs:67:20 @@ -118,10 +115,10 @@ LL | async { true }.await; = note: `T` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:83:1 + --> tests/ui/future_not_send.rs:83:51 | LL | async fn generic_future_always_unsend(_: Rc) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `generic_future_always_unsend` is not `Send` + | ^ future returned by `generic_future_always_unsend` is not `Send` | note: future is not `Send` as this value is used across an await --> tests/ui/future_not_send.rs:86:20 From 06500aa2ddba47bc3511236dcdca640c83ee5252 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 9 Dec 2025 17:59:24 +0100 Subject: [PATCH 435/585] Add message when running clippy with `--no-default-features` for cg_gcc --- src/bootstrap/src/core/build_steps/clippy.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index f80cf58fbb2a..085c2d952e30 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -394,6 +394,7 @@ fn run(self, builder: &Builder<'_>) -> Self::Output { &[], ); self.build_compiler.configure_cargo(&mut cargo); + println!("Now running clippy on `rustc_codegen_gcc` with `--no-default-features`"); cargo.arg("--no-default-features"); run_cargo(builder, cargo, args, &stamp, vec![], true, false); } From 6cd44a472c7a9374c975921815cf8a88029108d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Dec 2025 16:20:07 +0000 Subject: [PATCH 436/585] Make typo in field and name suggestions verbose --- compiler/rustc_hir_typeck/src/pat.rs | 2 +- compiler/rustc_resolve/src/diagnostics.rs | 2 +- .../diagnostic-derive.stderr | 24 +++- .../argument-suggestions/issue-109831.stderr | 8 +- tests/ui/associated-item/issue-87638.stderr | 22 +-- tests/ui/associated-types/issue-19883.stderr | 11 +- tests/ui/associated-types/issue-22037.stderr | 11 +- .../attributes/align-on-fields-143987.stderr | 8 +- ...ruct-pattern-box-pattern-ice-121463.stderr | 20 +-- tests/ui/closures/issue-90871.stderr | 6 +- .../ui-testing-optout.stderr | 16 ++- .../generic_const_exprs/error_in_ty.stderr | 8 +- .../unevaluated-const-ice-119731.stderr | 24 +++- ...arent_generics_of_nested_in_default.stderr | 8 +- .../ice-unhandled-type-122191.stderr | 8 +- .../const-pattern-rewrite-error-32086.stderr | 16 ++- tests/ui/delegation/bad-resolve.stderr | 16 ++- .../deriving-meta-unknown-trait.stderr | 14 +- tests/ui/did_you_mean/println-typo.stderr | 7 +- .../typo-suggestion-improvement-46332.stderr | 8 +- tests/ui/expr/if/bad-if-let-suggestion.stderr | 32 ++++- .../format-args-capture-issue-102057.stderr | 40 +++++- .../format-args-capture-issue-94010.stderr | 16 ++- .../equality-bound.stderr | 59 ++++++-- .../hygiene/rustc-macro-transparency.stderr | 11 +- tests/ui/imports/glob-resolve1.stderr | 21 ++- tests/ui/macros/macro-context.stderr | 6 +- tests/ui/macros/macro-name-typo.stderr | 7 +- .../macros/macro-path-prelude-fail-3.stderr | 7 +- tests/ui/macros/macro-reexport-removed.stderr | 8 +- tests/ui/macros/macro_undefined.stderr | 7 +- tests/ui/parser/emoji-identifiers.stderr | 8 +- tests/ui/parser/kw-in-trait-bounds.stderr | 32 ++++- .../ui/parser/recover/raw-no-const-mut.stderr | 8 +- ...h-enum-struct-variant-field-missing.stderr | 11 +- .../ui/pattern/pattern-error-continue.stderr | 11 +- .../name-resolution.stderr | 120 ++++++++++++++-- ...n-with-missing-fields-resolve-error.stderr | 8 +- .../proc-macro/gen-macro-rules-hygiene.stderr | 14 +- .../ui/proc-macro/lints_in_proc_macros.stderr | 7 +- tests/ui/proc-macro/mixed-site-span.stderr | 14 +- .../ui/proc-macro/parent-source-spans.stderr | 21 ++- tests/ui/proc-macro/resolve-error.stderr | 76 +++++++++-- tests/ui/regions/outlives-with-missing.stderr | 8 +- tests/ui/resolve/112590-2.stderr | 10 +- tests/ui/resolve/issue-10200.stderr | 7 +- tests/ui/resolve/issue-49074.stderr | 8 +- tests/ui/resolve/levenshtein.stderr | 53 +++++++- tests/ui/resolve/privacy-enum-ctor.stderr | 28 +++- tests/ui/resolve/privacy-struct-ctor.stderr | 11 +- ...uggest-path-instead-of-mod-dot-item.stderr | 30 ++-- tests/ui/resolve/tuple-struct-alias.stderr | 8 +- ...e-with-name-similar-to-struct-field.stderr | 23 +++- .../typo-suggestion-mistyped-in-path.stderr | 30 ++-- tests/ui/span/suggestion-raw-68962.stderr | 16 ++- tests/ui/span/typo-suggestion.stderr | 8 +- .../stability-attribute/issue-109177.stderr | 8 +- .../struct-fields-shorthand-unresolved.stderr | 8 +- tests/ui/suggestions/attribute-typos.stderr | 21 ++- .../case-difference-suggestions.stderr | 128 +++++++++++++++--- ...-to-add-suggestions-with-no-changes.stderr | 7 +- .../issue-66968-suggest-sorted-words.stderr | 8 +- .../assoc_type_bound_with_struct.stderr | 6 +- .../ice-120503-async-const-method.stderr | 8 +- .../mismatched_generic_args.stderr | 8 +- tests/ui/traits/impl-for-module.stderr | 8 +- .../type-error-drop-elaboration.stderr | 8 +- tests/ui/type/issue-7607-1.stderr | 7 +- ...114423-ice-regression-in-suggestion.stderr | 8 +- tests/ui/typeck/issue-120856.stderr | 19 +-- tests/ui/typeck/issue-83693.stderr | 6 +- tests/ui/typeck/issue-88844.stderr | 7 +- tests/ui/ufcs/ufcs-partially-resolved.stderr | 110 ++++++++++++--- ...mismatch-closure-from-another-scope.stderr | 8 +- 74 files changed, 1165 insertions(+), 241 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 0e9ff962435f..06fd89837d51 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -2296,7 +2296,7 @@ fn error_inexistent_fields( let suggested_name = find_best_match_for_name(&[field.name], pat_field.ident.name, None); if let Some(suggested_name) = suggested_name { - err.span_suggestion( + err.span_suggestion_verbose( pat_field.ident.span, "a field with a similar name exists", suggested_name, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 33c111708e36..44d71947db85 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1963,7 +1963,7 @@ pub(crate) fn add_typo_suggestion( }; (span, msg, suggestion.candidate.to_ident_string()) }; - err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect); + err.span_suggestion_verbose(span, msg, sugg, Applicability::MaybeIncorrect); true } diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 59b48e9f0ecc..8a0e753a9c52 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -570,19 +570,37 @@ error: cannot find attribute `warn_` in this scope --> $DIR/diagnostic-derive.rs:590:3 | LL | #[warn_(no_crate_example, code = E0123)] - | ^^^^^ help: a built-in attribute with a similar name exists: `warn` + | ^^^^^ + | +help: a built-in attribute with a similar name exists + | +LL - #[warn_(no_crate_example, code = E0123)] +LL + #[warn(no_crate_example, code = E0123)] + | error: cannot find attribute `lint` in this scope --> $DIR/diagnostic-derive.rs:597:3 | LL | #[lint(no_crate_example, code = E0123)] - | ^^^^ help: a built-in attribute with a similar name exists: `link` + | ^^^^ + | +help: a built-in attribute with a similar name exists + | +LL - #[lint(no_crate_example, code = E0123)] +LL + #[link(no_crate_example, code = E0123)] + | error: cannot find attribute `lint` in this scope --> $DIR/diagnostic-derive.rs:604:3 | LL | #[lint(no_crate_example, code = E0123)] - | ^^^^ help: a built-in attribute with a similar name exists: `link` + | ^^^^ + | +help: a built-in attribute with a similar name exists + | +LL - #[lint(no_crate_example, code = E0123)] +LL + #[link(no_crate_example, code = E0123)] + | error: cannot find attribute `multipart_suggestion` in this scope --> $DIR/diagnostic-derive.rs:644:3 diff --git a/tests/ui/argument-suggestions/issue-109831.stderr b/tests/ui/argument-suggestions/issue-109831.stderr index 6c25236ebb1b..852016c983f7 100644 --- a/tests/ui/argument-suggestions/issue-109831.stderr +++ b/tests/ui/argument-suggestions/issue-109831.stderr @@ -24,7 +24,13 @@ LL | struct A; | --------- similarly named unit struct `A` defined here ... LL | f(A, A, B, C); - | ^ help: a unit struct with a similar name exists: `A` + | ^ + | +help: a unit struct with a similar name exists + | +LL - f(A, A, B, C); +LL + f(A, A, B, A); + | error[E0061]: this function takes 3 arguments but 4 arguments were supplied --> $DIR/issue-109831.rs:7:5 diff --git a/tests/ui/associated-item/issue-87638.stderr b/tests/ui/associated-item/issue-87638.stderr index cf6083444b0e..cce20318a23b 100644 --- a/tests/ui/associated-item/issue-87638.stderr +++ b/tests/ui/associated-item/issue-87638.stderr @@ -5,10 +5,13 @@ LL | type Target; | ------------ associated type `Target` defined here ... LL | let _: ::Output; - | ^^^^^^ - | | - | not found in `Trait` - | help: maybe you meant this associated type: `Target` + | ^^^^^^ not found in `Trait` + | +help: maybe you meant this associated type + | +LL - let _: ::Output; +LL + let _: ::Target; + | error[E0576]: cannot find method or associated constant `BAR` in trait `Trait` --> $DIR/issue-87638.rs:20:27 @@ -17,10 +20,13 @@ LL | const FOO: usize; | ----------------- associated constant `FOO` defined here ... LL | let _ = ::BAR; - | ^^^ - | | - | not found in `Trait` - | help: maybe you meant this associated constant: `FOO` + | ^^^ not found in `Trait` + | +help: maybe you meant this associated constant + | +LL - let _ = ::BAR; +LL + let _ = ::FOO; + | error: aborting due to 2 previous errors diff --git a/tests/ui/associated-types/issue-19883.stderr b/tests/ui/associated-types/issue-19883.stderr index 35184e852cfe..435c2933e361 100644 --- a/tests/ui/associated-types/issue-19883.stderr +++ b/tests/ui/associated-types/issue-19883.stderr @@ -5,10 +5,13 @@ LL | type Output; | ------------ associated type `Output` defined here ... LL | >::Dst - | ^^^ - | | - | not found in `From` - | help: maybe you meant this associated type: `Output` + | ^^^ not found in `From` + | +help: maybe you meant this associated type + | +LL - >::Dst +LL + >::Output + | error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/issue-22037.stderr b/tests/ui/associated-types/issue-22037.stderr index b02dad97d354..0b5f18f81c0b 100644 --- a/tests/ui/associated-types/issue-22037.stderr +++ b/tests/ui/associated-types/issue-22037.stderr @@ -4,10 +4,13 @@ error[E0576]: cannot find associated type `X` in trait `A` LL | type Output; | ------------ associated type `Output` defined here LL | fn a(&self) -> ::X; - | ^ - | | - | not found in `A` - | help: maybe you meant this associated type: `Output` + | ^ not found in `A` + | +help: maybe you meant this associated type + | +LL - fn a(&self) -> ::X; +LL + fn a(&self) -> ::Output; + | error: aborting due to 1 previous error diff --git a/tests/ui/attributes/align-on-fields-143987.stderr b/tests/ui/attributes/align-on-fields-143987.stderr index c95543a74c1a..1ffbf4a37cb9 100644 --- a/tests/ui/attributes/align-on-fields-143987.stderr +++ b/tests/ui/attributes/align-on-fields-143987.stderr @@ -2,7 +2,13 @@ error[E0425]: cannot find type `usize8` in this scope --> $DIR/align-on-fields-143987.rs:17:8 | LL | x: usize8, - | ^^^^^^ help: a builtin type with a similar name exists: `usize` + | ^^^^^^ + | +help: a builtin type with a similar name exists + | +LL - x: usize8, +LL + x: usize, + | error: `#[rustc_align]` attribute cannot be used on struct fields --> $DIR/align-on-fields-143987.rs:10:5 diff --git a/tests/ui/borrowck/non-ADT-struct-pattern-box-pattern-ice-121463.stderr b/tests/ui/borrowck/non-ADT-struct-pattern-box-pattern-ice-121463.stderr index 349546606a57..ae5c67eae9a6 100644 --- a/tests/ui/borrowck/non-ADT-struct-pattern-box-pattern-ice-121463.stderr +++ b/tests/ui/borrowck/non-ADT-struct-pattern-box-pattern-ice-121463.stderr @@ -2,19 +2,23 @@ error[E0433]: failed to resolve: use of undeclared type `E` --> $DIR/non-ADT-struct-pattern-box-pattern-ice-121463.rs:6:17 | LL | let mut a = E::StructVar { boxed: Box::new(5_i32) }; - | ^ - | | - | use of undeclared type `E` - | help: a trait with a similar name exists: `Eq` + | ^ use of undeclared type `E` + | +help: a trait with a similar name exists + | +LL | let mut a = Eq::StructVar { boxed: Box::new(5_i32) }; + | + error[E0433]: failed to resolve: use of undeclared type `E` --> $DIR/non-ADT-struct-pattern-box-pattern-ice-121463.rs:9:9 | LL | E::StructVar { box boxed } => { } - | ^ - | | - | use of undeclared type `E` - | help: a trait with a similar name exists: `Eq` + | ^ use of undeclared type `E` + | +help: a trait with a similar name exists + | +LL | Eq::StructVar { box boxed } => { } + | + error: aborting due to 2 previous errors diff --git a/tests/ui/closures/issue-90871.stderr b/tests/ui/closures/issue-90871.stderr index 071694def413..140f24982140 100644 --- a/tests/ui/closures/issue-90871.stderr +++ b/tests/ui/closures/issue-90871.stderr @@ -2,11 +2,15 @@ error[E0425]: cannot find type `n` in this scope --> $DIR/issue-90871.rs:4:22 | LL | type_ascribe!(2, n([u8; || 1])) - | ^ help: a trait with a similar name exists: `Fn` + | ^ | --> $SRC_DIR/core/src/ops/function.rs:LL:COL | = note: similarly named trait `Fn` defined here +help: a trait with a similar name exists + | +LL | type_ascribe!(2, Fn([u8; || 1])) + | + error[E0308]: mismatched types --> $DIR/issue-90871.rs:4:29 diff --git a/tests/ui/compiletest-self-test/ui-testing-optout.stderr b/tests/ui/compiletest-self-test/ui-testing-optout.stderr index b0d495edfb62..6a4950c55afd 100644 --- a/tests/ui/compiletest-self-test/ui-testing-optout.stderr +++ b/tests/ui/compiletest-self-test/ui-testing-optout.stderr @@ -11,7 +11,13 @@ error[E0425]: cannot find type `D` in this scope | ----------- similarly named type alias `A` defined here ... 7 | type C = D; - | ^ help: a type alias with a similar name exists: `A` + | ^ + | +help: a type alias with a similar name exists + | +7 - type C = D; +7 + type C = A; + | error[E0425]: cannot find type `F` in this scope --> $DIR/ui-testing-optout.rs:92:10 @@ -20,7 +26,13 @@ error[E0425]: cannot find type `F` in this scope | ----------- similarly named type alias `A` defined here ... 92 | type E = F; - | ^ help: a type alias with a similar name exists: `A` + | ^ + | +help: a type alias with a similar name exists + | +92 - type E = F; +92 + type E = A; + | error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr b/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr index d822fa5894a5..58f0d31b0960 100644 --- a/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr +++ b/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr @@ -2,9 +2,15 @@ error[E0425]: cannot find value `x` in this scope --> $DIR/error_in_ty.rs:6:31 | LL | pub struct A {} - | - ^ help: a const parameter with a similar name exists: `z` + | - ^ | | | similarly named const parameter `z` defined here + | +help: a const parameter with a similar name exists + | +LL - pub struct A {} +LL + pub struct A {} + | error: `[usize; x]` is forbidden as the type of a const generic parameter --> $DIR/error_in_ty.rs:6:23 diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr index d3a7e286fdd6..b547bdd7d07a 100644 --- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr +++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr @@ -20,7 +20,13 @@ LL | pub type v11 = [[usize; v4]; v4]; | --------------------------------- similarly named type alias `v11` defined here ... LL | pub const fn v21() -> v18 {} - | ^^^ help: a type alias with a similar name exists: `v11` + | ^^^ + | +help: a type alias with a similar name exists + | +LL - pub const fn v21() -> v18 {} +LL + pub const fn v21() -> v11 {} + | error[E0425]: cannot find type `v18` in this scope --> $DIR/unevaluated-const-ice-119731.rs:35:31 @@ -29,7 +35,13 @@ LL | pub type v11 = [[usize; v4]; v4]; | --------------------------------- similarly named type alias `v11` defined here ... LL | pub const fn v21() -> v18 { - | ^^^ help: a type alias with a similar name exists: `v11` + | ^^^ + | +help: a type alias with a similar name exists + | +LL - pub const fn v21() -> v18 { +LL + pub const fn v21() -> v11 { + | error[E0422]: cannot find struct, variant or union type `v18` in this scope --> $DIR/unevaluated-const-ice-119731.rs:37:13 @@ -38,7 +50,13 @@ LL | pub type v11 = [[usize; v4]; v4]; | --------------------------------- similarly named type alias `v11` defined here ... LL | v18 { _p: () } - | ^^^ help: a type alias with a similar name exists: `v11` + | ^^^ + | +help: a type alias with a similar name exists + | +LL - v18 { _p: () } +LL + v11 { _p: () } + | warning: type `v11` should have an upper camel case name --> $DIR/unevaluated-const-ice-119731.rs:9:14 diff --git a/tests/ui/const-generics/parent_generics_of_nested_in_default.stderr b/tests/ui/const-generics/parent_generics_of_nested_in_default.stderr index 00eeecb9595f..9452e747a755 100644 --- a/tests/ui/const-generics/parent_generics_of_nested_in_default.stderr +++ b/tests/ui/const-generics/parent_generics_of_nested_in_default.stderr @@ -8,9 +8,15 @@ error[E0425]: cannot find value `B` in this scope --> $DIR/parent_generics_of_nested_in_default.rs:1:30 | LL | impl Tr {} - | - ^ help: a const parameter with a similar name exists: `A` + | - ^ | | | similarly named const parameter `A` defined here + | +help: a const parameter with a similar name exists + | +LL - impl Tr {} +LL + impl Tr {} + | error: defaults for generic parameters are not allowed here --> $DIR/parent_generics_of_nested_in_default.rs:1:6 diff --git a/tests/ui/consts/const-eval/ice-unhandled-type-122191.stderr b/tests/ui/consts/const-eval/ice-unhandled-type-122191.stderr index bcb6a80a8f2b..5e2e3524ae9e 100644 --- a/tests/ui/consts/const-eval/ice-unhandled-type-122191.stderr +++ b/tests/ui/consts/const-eval/ice-unhandled-type-122191.stderr @@ -22,10 +22,16 @@ error[E0425]: cannot find function `value` in this scope --> $DIR/ice-unhandled-type-122191.rs:9:5 | LL | value() - | ^^^^^ help: a constant with a similar name exists: `VALUE` + | ^^^^^ ... LL | const VALUE: Foo = foo(); | ------------------------- similarly named constant `VALUE` defined here + | +help: a constant with a similar name exists + | +LL - value() +LL + VALUE() + | error[E0308]: mismatched types --> $DIR/ice-unhandled-type-122191.rs:17:9 diff --git a/tests/ui/consts/const-pattern-rewrite-error-32086.stderr b/tests/ui/consts/const-pattern-rewrite-error-32086.stderr index 47616b066321..9c8ac7008709 100644 --- a/tests/ui/consts/const-pattern-rewrite-error-32086.stderr +++ b/tests/ui/consts/const-pattern-rewrite-error-32086.stderr @@ -5,7 +5,13 @@ LL | struct S(u8); | ------------- similarly named tuple struct `S` defined here ... LL | let C(a) = S(11); - | ^ help: a tuple struct with a similar name exists: `S` + | ^ + | +help: a tuple struct with a similar name exists + | +LL - let C(a) = S(11); +LL + let S(a) = S(11); + | error[E0532]: expected tuple struct or tuple variant, found constant `C` --> $DIR/const-pattern-rewrite-error-32086.rs:7:9 @@ -14,7 +20,13 @@ LL | struct S(u8); | ------------- similarly named tuple struct `S` defined here ... LL | let C(..) = S(11); - | ^ help: a tuple struct with a similar name exists: `S` + | ^ + | +help: a tuple struct with a similar name exists + | +LL - let C(..) = S(11); +LL + let S(..) = S(11); + | error: aborting due to 2 previous errors diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr index fc6811292a6f..4c015c226b18 100644 --- a/tests/ui/delegation/bad-resolve.stderr +++ b/tests/ui/delegation/bad-resolve.stderr @@ -53,7 +53,13 @@ LL | fn bar() {} | -------- similarly named associated function `bar` defined here ... LL | reuse ::baz; - | ^^^ help: an associated function with a similar name exists: `bar` + | ^^^ + | +help: an associated function with a similar name exists + | +LL - reuse ::baz; +LL + reuse ::bar; + | error[E0425]: cannot find function `foo` in this scope --> $DIR/bad-resolve.rs:35:11 @@ -68,7 +74,13 @@ LL | fn foo(&self, x: i32) -> i32 { x } | ---------------------------- similarly named associated function `foo` defined here ... LL | reuse Trait::foo2 { self.0 } - | ^^^^ help: an associated function with a similar name exists: `foo` + | ^^^^ + | +help: an associated function with a similar name exists + | +LL - reuse Trait::foo2 { self.0 } +LL + reuse Trait::foo { self.0 } + | error[E0046]: not all trait items implemented, missing: `Type` --> $DIR/bad-resolve.rs:22:1 diff --git a/tests/ui/derives/deriving-meta-unknown-trait.stderr b/tests/ui/derives/deriving-meta-unknown-trait.stderr index 7ee90ae9eb0c..1cf31502dfb8 100644 --- a/tests/ui/derives/deriving-meta-unknown-trait.stderr +++ b/tests/ui/derives/deriving-meta-unknown-trait.stderr @@ -2,23 +2,33 @@ error: cannot find derive macro `Eqr` in this scope --> $DIR/deriving-meta-unknown-trait.rs:1:10 | LL | #[derive(Eqr)] - | ^^^ help: a derive macro with a similar name exists: `Eq` + | ^^^ | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named derive macro `Eq` defined here +help: a derive macro with a similar name exists + | +LL - #[derive(Eqr)] +LL + #[derive(Eq)] + | error: cannot find derive macro `Eqr` in this scope --> $DIR/deriving-meta-unknown-trait.rs:1:10 | LL | #[derive(Eqr)] - | ^^^ help: a derive macro with a similar name exists: `Eq` + | ^^^ | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named derive macro `Eq` defined here | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: a derive macro with a similar name exists + | +LL - #[derive(Eqr)] +LL + #[derive(Eq)] + | error: aborting due to 2 previous errors diff --git a/tests/ui/did_you_mean/println-typo.stderr b/tests/ui/did_you_mean/println-typo.stderr index 7dd6fbba620b..471d49b6ee2e 100644 --- a/tests/ui/did_you_mean/println-typo.stderr +++ b/tests/ui/did_you_mean/println-typo.stderr @@ -2,11 +2,16 @@ error: cannot find macro `prinltn` in this scope --> $DIR/println-typo.rs:4:5 | LL | prinltn!(); - | ^^^^^^^ help: a macro with a similar name exists: `println` + | ^^^^^^^ | --> $SRC_DIR/std/src/macros.rs:LL:COL | = note: similarly named macro `println` defined here +help: a macro with a similar name exists + | +LL - prinltn!(); +LL + println!(); + | error: aborting due to 1 previous error diff --git a/tests/ui/did_you_mean/typo-suggestion-improvement-46332.stderr b/tests/ui/did_you_mean/typo-suggestion-improvement-46332.stderr index 502f81518785..d677152314dc 100644 --- a/tests/ui/did_you_mean/typo-suggestion-improvement-46332.stderr +++ b/tests/ui/did_you_mean/typo-suggestion-improvement-46332.stderr @@ -5,7 +5,13 @@ LL | struct TyUint {} | ------------- similarly named struct `TyUint` defined here ... LL | TyUInt {}; - | ^^^^^^ help: a struct with a similar name exists (notice the capitalization): `TyUint` + | ^^^^^^ + | +help: a struct with a similar name exists (notice the capitalization) + | +LL - TyUInt {}; +LL + TyUint {}; + | error: aborting due to 1 previous error diff --git a/tests/ui/expr/if/bad-if-let-suggestion.stderr b/tests/ui/expr/if/bad-if-let-suggestion.stderr index 0d1f895bd82b..4244a3bb06ee 100644 --- a/tests/ui/expr/if/bad-if-let-suggestion.stderr +++ b/tests/ui/expr/if/bad-if-let-suggestion.stderr @@ -27,7 +27,13 @@ LL | fn a() { | ------ similarly named function `a` defined here ... LL | if (i + j) = i {} - | ^ help: a function with a similar name exists: `a` + | ^ + | +help: a function with a similar name exists + | +LL - if (i + j) = i {} +LL + if (a + j) = i {} + | error[E0425]: cannot find value `j` in this scope --> $DIR/bad-if-let-suggestion.rs:9:13 @@ -36,7 +42,13 @@ LL | fn a() { | ------ similarly named function `a` defined here ... LL | if (i + j) = i {} - | ^ help: a function with a similar name exists: `a` + | ^ + | +help: a function with a similar name exists + | +LL - if (i + j) = i {} +LL + if (i + a) = i {} + | error[E0425]: cannot find value `i` in this scope --> $DIR/bad-if-let-suggestion.rs:9:18 @@ -45,7 +57,13 @@ LL | fn a() { | ------ similarly named function `a` defined here ... LL | if (i + j) = i {} - | ^ help: a function with a similar name exists: `a` + | ^ + | +help: a function with a similar name exists + | +LL - if (i + j) = i {} +LL + if (i + j) = a {} + | error[E0425]: cannot find value `x` in this scope --> $DIR/bad-if-let-suggestion.rs:16:8 @@ -54,7 +72,13 @@ LL | fn a() { | ------ similarly named function `a` defined here ... LL | if x[0] = 1 {} - | ^ help: a function with a similar name exists: `a` + | ^ + | +help: a function with a similar name exists + | +LL - if x[0] = 1 {} +LL + if a[0] = 1 {} + | error[E0308]: mismatched types --> $DIR/bad-if-let-suggestion.rs:2:8 diff --git a/tests/ui/fmt/format-args-capture-issue-102057.stderr b/tests/ui/fmt/format-args-capture-issue-102057.stderr index f2d625e7f8dc..9a5bc5365df7 100644 --- a/tests/ui/fmt/format-args-capture-issue-102057.stderr +++ b/tests/ui/fmt/format-args-capture-issue-102057.stderr @@ -14,31 +14,61 @@ error[E0425]: cannot find value `b` in this scope --> $DIR/format-args-capture-issue-102057.rs:9:22 | LL | format!("\x7Ba} {b}"); - | ^ help: a local variable with a similar name exists: `a` + | ^ + | +help: a local variable with a similar name exists + | +LL - format!("\x7Ba} {b}"); +LL + format!("\x7Ba} {a}"); + | error[E0425]: cannot find value `b` in this scope --> $DIR/format-args-capture-issue-102057.rs:11:25 | LL | format!("\x7Ba\x7D {b}"); - | ^ help: a local variable with a similar name exists: `a` + | ^ + | +help: a local variable with a similar name exists + | +LL - format!("\x7Ba\x7D {b}"); +LL + format!("\x7Ba\x7D {a}"); + | error[E0425]: cannot find value `b` in this scope --> $DIR/format-args-capture-issue-102057.rs:13:25 | LL | format!("\x7Ba} \x7Bb}"); - | ^ help: a local variable with a similar name exists: `a` + | ^ + | +help: a local variable with a similar name exists + | +LL - format!("\x7Ba} \x7Bb}"); +LL + format!("\x7Ba} \x7Ba}"); + | error[E0425]: cannot find value `b` in this scope --> $DIR/format-args-capture-issue-102057.rs:15:28 | LL | format!("\x7Ba\x7D \x7Bb}"); - | ^ help: a local variable with a similar name exists: `a` + | ^ + | +help: a local variable with a similar name exists + | +LL - format!("\x7Ba\x7D \x7Bb}"); +LL + format!("\x7Ba\x7D \x7Ba}"); + | error[E0425]: cannot find value `b` in this scope --> $DIR/format-args-capture-issue-102057.rs:17:28 | LL | format!("\x7Ba\x7D \x7Bb\x7D"); - | ^ help: a local variable with a similar name exists: `a` + | ^ + | +help: a local variable with a similar name exists + | +LL - format!("\x7Ba\x7D \x7Bb\x7D"); +LL + format!("\x7Ba\x7D \x7Ba\x7D"); + | error: aborting due to 7 previous errors diff --git a/tests/ui/fmt/format-args-capture-issue-94010.stderr b/tests/ui/fmt/format-args-capture-issue-94010.stderr index ed90dc855360..ccdaf0c67b2b 100644 --- a/tests/ui/fmt/format-args-capture-issue-94010.stderr +++ b/tests/ui/fmt/format-args-capture-issue-94010.stderr @@ -4,7 +4,13 @@ error[E0425]: cannot find value `foo` in this scope LL | const FOO: i32 = 123; | --------------------- similarly named constant `FOO` defined here LL | println!("{foo:X}"); - | ^^^ help: a constant with a similar name exists (notice the capitalization): `FOO` + | ^^^ + | +help: a constant with a similar name exists (notice the capitalization) + | +LL - println!("{foo:X}"); +LL + println!("{FOO:X}"); + | error[E0425]: cannot find value `foo` in this scope --> $DIR/format-args-capture-issue-94010.rs:5:18 @@ -13,7 +19,13 @@ LL | const FOO: i32 = 123; | --------------------- similarly named constant `FOO` defined here ... LL | println!("{:.foo$}", 0); - | ^^^ help: a constant with a similar name exists (notice the capitalization): `FOO` + | ^^^ + | +help: a constant with a similar name exists (notice the capitalization) + | +LL - println!("{:.foo$}", 0); +LL + println!("{:.FOO$}", 0); + | error: aborting due to 2 previous errors diff --git a/tests/ui/generic-associated-types/equality-bound.stderr b/tests/ui/generic-associated-types/equality-bound.stderr index 03fafe3e21c1..265c86ac5bb6 100644 --- a/tests/ui/generic-associated-types/equality-bound.stderr +++ b/tests/ui/generic-associated-types/equality-bound.stderr @@ -114,28 +114,46 @@ error[E0425]: cannot find type `A` in this scope --> $DIR/equality-bound.rs:20:79 | LL | fn from_iter(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A, - | ^ help: a struct with a similar name exists: `K` + | ^ ... LL | struct K {} | -------- similarly named struct `K` defined here + | +help: a struct with a similar name exists + | +LL - fn from_iter(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A, +LL + fn from_iter(_: T) -> Self where T: IntoIterator, IntoIterator::Item = K, + | error[E0425]: cannot find type `A` in this scope --> $DIR/equality-bound.rs:31:68 | LL | fn from_iter(_: T) -> Self where T: IntoIterator, T::Item = A, - | ^ help: a struct with a similar name exists: `K` + | ^ ... LL | struct K {} | -------- similarly named struct `K` defined here + | +help: a struct with a similar name exists + | +LL - fn from_iter(_: T) -> Self where T: IntoIterator, T::Item = A, +LL + fn from_iter(_: T) -> Self where T: IntoIterator, T::Item = K, + | error[E0425]: cannot find type `A` in this scope --> $DIR/equality-bound.rs:42:76 | LL | fn from_iter(_: T) -> Self where IntoIterator::Item = A, - | ^ help: a struct with a similar name exists: `K` + | ^ ... LL | struct K {} | -------- similarly named struct `K` defined here + | +help: a struct with a similar name exists + | +LL - fn from_iter(_: T) -> Self where IntoIterator::Item = A, +LL + fn from_iter(_: T) -> Self where IntoIterator::Item = K, + | error[E0425]: cannot find type `A` in this scope --> $DIR/equality-bound.rs:53:65 @@ -144,7 +162,13 @@ LL | struct K {} | -------- similarly named struct `K` defined here ... LL | fn from_iter(_: T) -> Self where T::Item = A, - | ^ help: a struct with a similar name exists: `K` + | ^ + | +help: a struct with a similar name exists + | +LL - fn from_iter(_: T) -> Self where T::Item = A, +LL + fn from_iter(_: T) -> Self where T::Item = K, + | error[E0425]: cannot find type `A` in this scope --> $DIR/equality-bound.rs:64:62 @@ -153,7 +177,13 @@ LL | struct K {} | -------- similarly named struct `K` defined here ... LL | fn from_iter(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator, - | ^ help: a struct with a similar name exists: `K` + | ^ + | +help: a struct with a similar name exists + | +LL - fn from_iter(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator, +LL + fn from_iter(_: T) -> Self where IntoIterator::Item = K, T: IntoIterator, + | error[E0425]: cannot find type `A` in this scope --> $DIR/equality-bound.rs:75:51 @@ -162,16 +192,25 @@ LL | struct K {} | -------- similarly named struct `K` defined here ... LL | fn from_iter(_: T) -> Self where T::Item = A, T: IntoIterator, - | ^ help: a struct with a similar name exists: `K` + | ^ + | +help: a struct with a similar name exists + | +LL - fn from_iter(_: T) -> Self where T::Item = A, T: IntoIterator, +LL + fn from_iter(_: T) -> Self where T::Item = K, T: IntoIterator, + | error[E0433]: failed to resolve: use of undeclared type `I` --> $DIR/equality-bound.rs:9:41 | LL | fn sum3(i: J) -> i32 where I::Item = i32 { - | ^ - | | - | use of undeclared type `I` - | help: a type parameter with a similar name exists: `J` + | ^ use of undeclared type `I` + | +help: a type parameter with a similar name exists + | +LL - fn sum3(i: J) -> i32 where I::Item = i32 { +LL + fn sum3(i: J) -> i32 where J::Item = i32 { + | error: aborting due to 16 previous errors diff --git a/tests/ui/hygiene/rustc-macro-transparency.stderr b/tests/ui/hygiene/rustc-macro-transparency.stderr index 1bea8a0ee4f3..af67bfe66cc8 100644 --- a/tests/ui/hygiene/rustc-macro-transparency.stderr +++ b/tests/ui/hygiene/rustc-macro-transparency.stderr @@ -11,10 +11,13 @@ LL | struct SemiOpaque; | ------------------ similarly named unit struct `SemiOpaque` defined here ... LL | semiopaque; - | ^^^^^^^^^^ - | | - | not a value - | help: a unit struct with a similar name exists (notice the capitalization): `SemiOpaque` + | ^^^^^^^^^^ not a value + | +help: a unit struct with a similar name exists (notice the capitalization) + | +LL - semiopaque; +LL + SemiOpaque; + | error[E0423]: expected value, found macro `opaque` --> $DIR/rustc-macro-transparency.rs:30:5 diff --git a/tests/ui/imports/glob-resolve1.stderr b/tests/ui/imports/glob-resolve1.stderr index 1356255a0850..5e02c933836d 100644 --- a/tests/ui/imports/glob-resolve1.stderr +++ b/tests/ui/imports/glob-resolve1.stderr @@ -75,13 +75,18 @@ LL | pub enum B { | ---------- similarly named enum `B` defined here ... LL | foo::(); - | ^ help: an enum with a similar name exists: `B` + | ^ | note: enum `bar::A` exists but is inaccessible --> $DIR/glob-resolve1.rs:12:5 | LL | enum A { | ^^^^^^ not accessible +help: an enum with a similar name exists + | +LL - foo::(); +LL + foo::(); + | error[E0425]: cannot find type `C` in this scope --> $DIR/glob-resolve1.rs:34:11 @@ -90,13 +95,18 @@ LL | pub enum B { | ---------- similarly named enum `B` defined here ... LL | foo::(); - | ^ help: an enum with a similar name exists: `B` + | ^ | note: struct `bar::C` exists but is inaccessible --> $DIR/glob-resolve1.rs:19:5 | LL | struct C; | ^^^^^^^^^ not accessible +help: an enum with a similar name exists + | +LL - foo::(); +LL + foo::(); + | error[E0425]: cannot find type `D` in this scope --> $DIR/glob-resolve1.rs:35:11 @@ -105,13 +115,18 @@ LL | pub enum B { | ---------- similarly named enum `B` defined here ... LL | foo::(); - | ^ help: an enum with a similar name exists: `B` + | ^ | note: type alias `bar::D` exists but is inaccessible --> $DIR/glob-resolve1.rs:21:5 | LL | type D = isize; | ^^^^^^^^^^^^^^^ not accessible +help: an enum with a similar name exists + | +LL - foo::(); +LL + foo::(); + | error: aborting due to 8 previous errors diff --git a/tests/ui/macros/macro-context.stderr b/tests/ui/macros/macro-context.stderr index edddfef9de3b..3ec1af3a82f8 100644 --- a/tests/ui/macros/macro-context.stderr +++ b/tests/ui/macros/macro-context.stderr @@ -46,12 +46,16 @@ error[E0425]: cannot find type `i` in this scope --> $DIR/macro-context.rs:3:13 | LL | () => ( i ; typeof ); - | ^ help: a builtin type with a similar name exists: `i8` + | ^ ... LL | let a: m!(); | ---- in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: a builtin type with a similar name exists + | +LL | () => ( i8 ; typeof ); + | + error[E0425]: cannot find value `i` in this scope --> $DIR/macro-context.rs:3:13 diff --git a/tests/ui/macros/macro-name-typo.stderr b/tests/ui/macros/macro-name-typo.stderr index 1cc7ea6ec1b6..bca7dbe9369c 100644 --- a/tests/ui/macros/macro-name-typo.stderr +++ b/tests/ui/macros/macro-name-typo.stderr @@ -2,11 +2,16 @@ error: cannot find macro `printlx` in this scope --> $DIR/macro-name-typo.rs:2:5 | LL | printlx!("oh noes!"); - | ^^^^^^^ help: a macro with a similar name exists: `println` + | ^^^^^^^ | --> $SRC_DIR/std/src/macros.rs:LL:COL | = note: similarly named macro `println` defined here +help: a macro with a similar name exists + | +LL - printlx!("oh noes!"); +LL + println!("oh noes!"); + | error: aborting due to 1 previous error diff --git a/tests/ui/macros/macro-path-prelude-fail-3.stderr b/tests/ui/macros/macro-path-prelude-fail-3.stderr index 3d0a074deeb0..7bf166d0e56f 100644 --- a/tests/ui/macros/macro-path-prelude-fail-3.stderr +++ b/tests/ui/macros/macro-path-prelude-fail-3.stderr @@ -2,13 +2,18 @@ error: cannot find macro `inline` in this scope --> $DIR/macro-path-prelude-fail-3.rs:2:5 | LL | inline!(); - | ^^^^^^ help: a macro with a similar name exists: `line` + | ^^^^^^ | --> $SRC_DIR/core/src/macros/mod.rs:LL:COL | = note: similarly named macro `line` defined here | = note: `inline` is in scope, but it is an attribute: `#[inline]` +help: a macro with a similar name exists + | +LL - inline!(); +LL + line!(); + | error: aborting due to 1 previous error diff --git a/tests/ui/macros/macro-reexport-removed.stderr b/tests/ui/macros/macro-reexport-removed.stderr index 8130fe0c4bda..752133162214 100644 --- a/tests/ui/macros/macro-reexport-removed.stderr +++ b/tests/ui/macros/macro-reexport-removed.stderr @@ -11,7 +11,13 @@ error: cannot find attribute `macro_reexport` in this scope --> $DIR/macro-reexport-removed.rs:5:3 | LL | #[macro_reexport(macro_one)] - | ^^^^^^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_export` + | ^^^^^^^^^^^^^^ + | +help: a built-in attribute with a similar name exists + | +LL - #[macro_reexport(macro_one)] +LL + #[macro_export(macro_one)] + | error: aborting due to 2 previous errors diff --git a/tests/ui/macros/macro_undefined.stderr b/tests/ui/macros/macro_undefined.stderr index cc3efacbc541..ed58be8808b2 100644 --- a/tests/ui/macros/macro_undefined.stderr +++ b/tests/ui/macros/macro_undefined.stderr @@ -5,7 +5,12 @@ LL | macro_rules! kl { | --------------- similarly named macro `kl` defined here ... LL | k!(); - | ^ help: a macro with a similar name exists: `kl` + | ^ + | +help: a macro with a similar name exists + | +LL | kl!(); + | + error: aborting due to 1 previous error diff --git a/tests/ui/parser/emoji-identifiers.stderr b/tests/ui/parser/emoji-identifiers.stderr index ef4e647b9f50..016ed0401caf 100644 --- a/tests/ui/parser/emoji-identifiers.stderr +++ b/tests/ui/parser/emoji-identifiers.stderr @@ -91,7 +91,13 @@ LL | fn i_like_to_😅_a_lot() -> 👀 { | ----------------------------- similarly named function `i_like_to_😅_a_lot` defined here ... LL | let _ = i_like_to_😄_a_lot() ➖ 4; - | ^^^^^^^^^^^^^^^^^^ help: a function with a similar name exists: `i_like_to_😅_a_lot` + | ^^^^^^^^^^^^^^^^^^ + | +help: a function with a similar name exists + | +LL - let _ = i_like_to_😄_a_lot() ➖ 4; +LL + let _ = i_like_to_😅_a_lot() ➖ 4; + | error: aborting due to 10 previous errors diff --git a/tests/ui/parser/kw-in-trait-bounds.stderr b/tests/ui/parser/kw-in-trait-bounds.stderr index 5a4adf3e37b4..5f86b1430616 100644 --- a/tests/ui/parser/kw-in-trait-bounds.stderr +++ b/tests/ui/parser/kw-in-trait-bounds.stderr @@ -94,37 +94,61 @@ error[E0405]: cannot find trait `r#struct` in this scope --> $DIR/kw-in-trait-bounds.rs:16:10 | LL | fn _g(_: impl struct, _: &dyn struct) - | ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct` + | ^^^^^^ ... LL | trait Struct {} | ------------ similarly named trait `Struct` defined here + | +help: a trait with a similar name exists (notice the capitalization) + | +LL - fn _g(_: impl struct, _: &dyn struct) +LL + fn _g(_: impl struct, _: &dyn struct) + | error[E0405]: cannot find trait `r#struct` in this scope --> $DIR/kw-in-trait-bounds.rs:30:8 | LL | B: struct, - | ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct` + | ^^^^^^ ... LL | trait Struct {} | ------------ similarly named trait `Struct` defined here + | +help: a trait with a similar name exists (notice the capitalization) + | +LL - B: struct, +LL + B: Struct, + | error[E0405]: cannot find trait `r#struct` in this scope --> $DIR/kw-in-trait-bounds.rs:16:29 | LL | fn _g(_: impl struct, _: &dyn struct) - | ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct` + | ^^^^^^ ... LL | trait Struct {} | ------------ similarly named trait `Struct` defined here + | +help: a trait with a similar name exists (notice the capitalization) + | +LL - fn _g(_: impl struct, _: &dyn struct) +LL + fn _g(_: impl Struct, _: &dyn struct) + | error[E0405]: cannot find trait `r#struct` in this scope --> $DIR/kw-in-trait-bounds.rs:16:45 | LL | fn _g(_: impl struct, _: &dyn struct) - | ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct` + | ^^^^^^ ... LL | trait Struct {} | ------------ similarly named trait `Struct` defined here + | +help: a trait with a similar name exists (notice the capitalization) + | +LL - fn _g(_: impl struct, _: &dyn struct) +LL + fn _g(_: impl struct, _: &dyn Struct) + | error: aborting due to 12 previous errors diff --git a/tests/ui/parser/recover/raw-no-const-mut.stderr b/tests/ui/parser/recover/raw-no-const-mut.stderr index 65032c807953..3007134f7f5c 100644 --- a/tests/ui/parser/recover/raw-no-const-mut.stderr +++ b/tests/ui/parser/recover/raw-no-const-mut.stderr @@ -101,7 +101,13 @@ LL | fn a() { | ------ similarly named function `a` defined here ... LL | f(&raw 2); - | ^ help: a function with a similar name exists: `a` + | ^ + | +help: a function with a similar name exists + | +LL - f(&raw 2); +LL + a(&raw 2); + | error: aborting due to 9 previous errors diff --git a/tests/ui/pattern/match-enum-struct-variant-field-missing.stderr b/tests/ui/pattern/match-enum-struct-variant-field-missing.stderr index 326595a7cb70..f449f00a6982 100644 --- a/tests/ui/pattern/match-enum-struct-variant-field-missing.stderr +++ b/tests/ui/pattern/match-enum-struct-variant-field-missing.stderr @@ -2,10 +2,13 @@ error[E0026]: variant `A::A` does not have a field named `fob` --> $DIR/match-enum-struct-variant-field-missing.rs:12:16 | LL | A::A { fob } => { - | ^^^ - | | - | variant `A::A` does not have this field - | help: a field with a similar name exists: `foo` + | ^^^ variant `A::A` does not have this field + | +help: a field with a similar name exists + | +LL - A::A { fob } => { +LL + A::A { foo } => { + | error: aborting due to 1 previous error diff --git a/tests/ui/pattern/pattern-error-continue.stderr b/tests/ui/pattern/pattern-error-continue.stderr index a9ac96e3eaff..de90d99a0ff1 100644 --- a/tests/ui/pattern/pattern-error-continue.stderr +++ b/tests/ui/pattern/pattern-error-continue.stderr @@ -56,10 +56,13 @@ error[E0433]: failed to resolve: use of undeclared type `E` --> $DIR/pattern-error-continue.rs:35:9 | LL | E::V => {} - | ^ - | | - | use of undeclared type `E` - | help: an enum with a similar name exists: `A` + | ^ use of undeclared type `E` + | +help: an enum with a similar name exists + | +LL - E::V => {} +LL + A::V => {} + | error: aborting due to 5 previous errors diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr index a5d9fd2b1a6e..44e42f142707 100644 --- a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr +++ b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr @@ -38,43 +38,85 @@ error[E0425]: cannot find value `x` in this scope --> $DIR/name-resolution.rs:10:34 | LL | fn bad_fn_item_1(x: bool, ((y if x) | y): bool) {} - | ^ help: a local variable with a similar name exists: `y` + | ^ + | +help: a local variable with a similar name exists + | +LL - fn bad_fn_item_1(x: bool, ((y if x) | y): bool) {} +LL + fn bad_fn_item_1(x: bool, ((y if y) | y): bool) {} + | error[E0425]: cannot find value `y` in this scope --> $DIR/name-resolution.rs:12:25 | LL | fn bad_fn_item_2(((x if y) | x): bool, y: bool) {} - | ^ help: a local variable with a similar name exists: `x` + | ^ + | +help: a local variable with a similar name exists + | +LL - fn bad_fn_item_2(((x if y) | x): bool, y: bool) {} +LL + fn bad_fn_item_2(((x if x) | x): bool, y: bool) {} + | error[E0425]: cannot find value `x` in this scope --> $DIR/name-resolution.rs:20:18 | LL | (x, y if x) => x && y, - | ^ help: a local variable with a similar name exists: `y` + | ^ + | +help: a local variable with a similar name exists + | +LL - (x, y if x) => x && y, +LL + (x, y if y) => x && y, + | error[E0425]: cannot find value `y` in this scope --> $DIR/name-resolution.rs:22:15 | LL | (x if y, y) => x && y, - | ^ help: a local variable with a similar name exists: `x` + | ^ + | +help: a local variable with a similar name exists + | +LL - (x if y, y) => x && y, +LL + (x if x, y) => x && y, + | error[E0425]: cannot find value `x` in this scope --> $DIR/name-resolution.rs:29:20 | LL | (x @ (y if x),) => x && y, - | ^ help: a local variable with a similar name exists: `y` + | ^ + | +help: a local variable with a similar name exists + | +LL - (x @ (y if x),) => x && y, +LL + (x @ (y if y),) => x && y, + | error[E0425]: cannot find value `y` in this scope --> $DIR/name-resolution.rs:37:20 | LL | ((Ok(x) if y) | (Err(y) if x),) => x && y, - | ^ help: a local variable with a similar name exists: `x` + | ^ + | +help: a local variable with a similar name exists + | +LL - ((Ok(x) if y) | (Err(y) if x),) => x && y, +LL + ((Ok(x) if x) | (Err(y) if x),) => x && y, + | error[E0425]: cannot find value `x` in this scope --> $DIR/name-resolution.rs:37:36 | LL | ((Ok(x) if y) | (Err(y) if x),) => x && y, - | ^ help: a local variable with a similar name exists: `y` + | ^ + | +help: a local variable with a similar name exists + | +LL - ((Ok(x) if y) | (Err(y) if x),) => x && y, +LL + ((Ok(x) if y) | (Err(y) if y),) => x && y, + | error[E0425]: cannot find value `nonexistent` in this scope --> $DIR/name-resolution.rs:44:15 @@ -86,49 +128,97 @@ error[E0425]: cannot find value `x` in this scope --> $DIR/name-resolution.rs:46:22 | LL | if let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } - | ^ help: a local variable with a similar name exists: `y` + | ^ + | +help: a local variable with a similar name exists + | +LL - if let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } +LL + if let ((x, y if y) | (x if y, y)) = (true, true) { x && y; } + | error[E0425]: cannot find value `y` in this scope --> $DIR/name-resolution.rs:46:33 | LL | if let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } - | ^ help: a local variable with a similar name exists: `x` + | ^ + | +help: a local variable with a similar name exists + | +LL - if let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } +LL + if let ((x, y if x) | (x if x, y)) = (true, true) { x && y; } + | error[E0425]: cannot find value `x` in this scope --> $DIR/name-resolution.rs:49:25 | LL | while let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } - | ^ help: a local variable with a similar name exists: `y` + | ^ + | +help: a local variable with a similar name exists + | +LL - while let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } +LL + while let ((x, y if y) | (x if y, y)) = (true, true) { x && y; } + | error[E0425]: cannot find value `y` in this scope --> $DIR/name-resolution.rs:49:36 | LL | while let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } - | ^ help: a local variable with a similar name exists: `x` + | ^ + | +help: a local variable with a similar name exists + | +LL - while let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } +LL + while let ((x, y if x) | (x if x, y)) = (true, true) { x && y; } + | error[E0425]: cannot find value `x` in this scope --> $DIR/name-resolution.rs:52:19 | LL | for ((x, y if x) | (x if y, y)) in [(true, true)] { x && y; } - | ^ help: a local variable with a similar name exists: `y` + | ^ + | +help: a local variable with a similar name exists + | +LL - for ((x, y if x) | (x if y, y)) in [(true, true)] { x && y; } +LL + for ((x, y if y) | (x if y, y)) in [(true, true)] { x && y; } + | error[E0425]: cannot find value `y` in this scope --> $DIR/name-resolution.rs:52:30 | LL | for ((x, y if x) | (x if y, y)) in [(true, true)] { x && y; } - | ^ help: a local variable with a similar name exists: `x` + | ^ + | +help: a local variable with a similar name exists + | +LL - for ((x, y if x) | (x if y, y)) in [(true, true)] { x && y; } +LL + for ((x, y if x) | (x if x, y)) in [(true, true)] { x && y; } + | error[E0425]: cannot find value `y` in this scope --> $DIR/name-resolution.rs:57:13 | LL | (|(x if y), (y if x)| x && y)(true, true); - | ^ help: a local variable with a similar name exists: `x` + | ^ + | +help: a local variable with a similar name exists + | +LL - (|(x if y), (y if x)| x && y)(true, true); +LL + (|(x if x), (y if x)| x && y)(true, true); + | error[E0425]: cannot find value `x` in this scope --> $DIR/name-resolution.rs:57:23 | LL | (|(x if y), (y if x)| x && y)(true, true); - | ^ help: a local variable with a similar name exists: `y` + | ^ + | +help: a local variable with a similar name exists + | +LL - (|(x if y), (y if x)| x && y)(true, true); +LL + (|(x if y), (y if y)| x && y)(true, true); + | error[E0308]: mismatched types --> $DIR/name-resolution.rs:75:18 diff --git a/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.stderr b/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.stderr index b985b771754e..b8c6f1d867a1 100644 --- a/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.stderr +++ b/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.stderr @@ -20,7 +20,13 @@ error[E0425]: cannot find value `a` in this scope LL | if let Foo::Bar { .. } = x { | --------------- this pattern doesn't include `a`, which is available in `Bar` LL | println!("{a}"); - | ^ help: a local variable with a similar name exists: `x` + | ^ + | +help: a local variable with a similar name exists + | +LL - println!("{a}"); +LL + println!("{x}"); + | error: aborting due to 3 previous errors diff --git a/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr b/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr index ed8ee4dc52cb..46cdbaccaeb6 100644 --- a/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr +++ b/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr @@ -13,7 +13,7 @@ error[E0425]: cannot find value `local_use` in this scope --> $DIR/gen-macro-rules-hygiene.rs:13:1 | LL | gen_macro_rules!(); - | ^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def` + | ^^^^^^^^^^^^^^^^^^ ... LL | generated!(); | ------------ in this macro invocation @@ -24,12 +24,17 @@ help: an identifier with the same name exists, but is not accessible due to macr LL | let local_use = 1; | ^^^^^^^^^ = note: this error originates in the macro `generated` (in Nightly builds, run with -Z macro-backtrace for more info) +help: a local variable with a similar name exists + | +LL - gen_macro_rules!(); +LL + local_def; + | error[E0425]: cannot find value `local_def` in this scope --> $DIR/gen-macro-rules-hygiene.rs:22:9 | LL | local_def; - | ^^^^^^^^^ help: a local variable with a similar name exists: `local_use` + | ^^^^^^^^^ | help: an identifier with the same name is defined here, but is not accessible due to macro hygiene --> $DIR/gen-macro-rules-hygiene.rs:13:1 @@ -40,6 +45,11 @@ LL | gen_macro_rules!(); LL | generated!(); | ------------ in this macro invocation = note: this error originates in the macro `generated` (in Nightly builds, run with -Z macro-backtrace for more info) +help: a local variable with a similar name exists + | +LL - local_def; +LL + local_use; + | error: aborting due to 3 previous errors diff --git a/tests/ui/proc-macro/lints_in_proc_macros.stderr b/tests/ui/proc-macro/lints_in_proc_macros.stderr index 016b236bda88..0b8df1b348d7 100644 --- a/tests/ui/proc-macro/lints_in_proc_macros.stderr +++ b/tests/ui/proc-macro/lints_in_proc_macros.stderr @@ -2,9 +2,14 @@ error[E0425]: cannot find value `foobar2` in this scope --> $DIR/lints_in_proc_macros.rs:10:5 | LL | bang_proc_macro2!(); - | ^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `foobar` + | ^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `bang_proc_macro2` (in Nightly builds, run with -Z macro-backtrace for more info) +help: a local variable with a similar name exists + | +LL - bang_proc_macro2!(); +LL + foobar; + | error: aborting due to 1 previous error diff --git a/tests/ui/proc-macro/mixed-site-span.stderr b/tests/ui/proc-macro/mixed-site-span.stderr index 97e3f3e3dea8..2cc7ff8a8867 100644 --- a/tests/ui/proc-macro/mixed-site-span.stderr +++ b/tests/ui/proc-macro/mixed-site-span.stderr @@ -592,7 +592,7 @@ error[E0425]: cannot find value `local_use` in this scope --> $DIR/mixed-site-span.rs:23:9 | LL | proc_macro_rules!(); - | ^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def` + | ^^^^^^^^^^^^^^^^^^^ | help: an identifier with the same name exists, but is not accessible due to macro hygiene --> $DIR/mixed-site-span.rs:22:13 @@ -600,12 +600,17 @@ help: an identifier with the same name exists, but is not accessible due to macr LL | let local_use = 1; | ^^^^^^^^^ = note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) +help: a local variable with a similar name exists + | +LL - proc_macro_rules!(); +LL + local_def; + | error[E0425]: cannot find value `local_def` in this scope --> $DIR/mixed-site-span.rs:28:9 | LL | local_def; - | ^^^^^^^^^ help: a local variable with a similar name exists: `local_use` + | ^^^^^^^^^ | help: an identifier with the same name is defined here, but is not accessible due to macro hygiene --> $DIR/mixed-site-span.rs:23:9 @@ -613,6 +618,11 @@ help: an identifier with the same name is defined here, but is not accessible du LL | proc_macro_rules!(); | ^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) +help: a local variable with a similar name exists + | +LL - local_def; +LL + local_use; + | error: aborting due to 52 previous errors diff --git a/tests/ui/proc-macro/parent-source-spans.stderr b/tests/ui/proc-macro/parent-source-spans.stderr index 28a70eea873d..87b8dae74f48 100644 --- a/tests/ui/proc-macro/parent-source-spans.stderr +++ b/tests/ui/proc-macro/parent-source-spans.stderr @@ -140,7 +140,7 @@ error[E0425]: cannot find value `ok` in this scope --> $DIR/parent-source-spans.rs:30:5 | LL | parent_source_spans!($($tokens)*); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | one!("hello", "world"); | ---------------------- in this macro invocation @@ -150,12 +150,17 @@ LL | one!("hello", "world"); = note: similarly named tuple variant `Ok` defined here | = note: this error originates in the macro `parent_source_spans` which comes from the expansion of the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info) +help: a tuple variant with a similar name exists + | +LL - parent_source_spans!($($tokens)*); +LL + Ok; + | error[E0425]: cannot find value `ok` in this scope --> $DIR/parent-source-spans.rs:30:5 | LL | parent_source_spans!($($tokens)*); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | two!("yay", "rust"); | ------------------- in this macro invocation @@ -165,12 +170,17 @@ LL | two!("yay", "rust"); = note: similarly named tuple variant `Ok` defined here | = note: this error originates in the macro `parent_source_spans` which comes from the expansion of the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info) +help: a tuple variant with a similar name exists + | +LL - parent_source_spans!($($tokens)*); +LL + Ok; + | error[E0425]: cannot find value `ok` in this scope --> $DIR/parent-source-spans.rs:30:5 | LL | parent_source_spans!($($tokens)*); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | three!("hip", "hop"); | -------------------- in this macro invocation @@ -180,6 +190,11 @@ LL | three!("hip", "hop"); = note: similarly named tuple variant `Ok` defined here | = note: this error originates in the macro `parent_source_spans` which comes from the expansion of the macro `three` (in Nightly builds, run with -Z macro-backtrace for more info) +help: a tuple variant with a similar name exists + | +LL - parent_source_spans!($($tokens)*); +LL + Ok; + | error: aborting due to 21 previous errors diff --git a/tests/ui/proc-macro/resolve-error.stderr b/tests/ui/proc-macro/resolve-error.stderr index 45b71a3e7b3a..7efb751caaec 100644 --- a/tests/ui/proc-macro/resolve-error.stderr +++ b/tests/ui/proc-macro/resolve-error.stderr @@ -2,12 +2,18 @@ error: cannot find macro `bang_proc_macrp` in this scope --> $DIR/resolve-error.rs:60:5 | LL | bang_proc_macrp!(); - | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `bang_proc_macro` + | ^^^^^^^^^^^^^^^ | ::: $DIR/auxiliary/test-macros.rs:10:1 | LL | pub fn empty(_: TokenStream) -> TokenStream { | ------------------------------------------- similarly named macro `bang_proc_macro` defined here + | +help: a macro with a similar name exists + | +LL - bang_proc_macrp!(); +LL + bang_proc_macro!(); + | error: cannot find macro `Dlona` in this scope --> $DIR/resolve-error.rs:57:5 @@ -22,7 +28,13 @@ LL | macro_rules! attr_proc_mac { | -------------------------- similarly named macro `attr_proc_mac` defined here ... LL | attr_proc_macra!(); - | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `attr_proc_mac` + | ^^^^^^^^^^^^^^^ + | +help: a macro with a similar name exists + | +LL - attr_proc_macra!(); +LL + attr_proc_mac!(); + | error: cannot find macro `FooWithLongNama` in this scope --> $DIR/resolve-error.rs:51:5 @@ -31,7 +43,13 @@ LL | macro_rules! FooWithLongNam { | --------------------------- similarly named macro `FooWithLongNam` defined here ... LL | FooWithLongNama!(); - | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `FooWithLongNam` + | ^^^^^^^^^^^^^^^ + | +help: a macro with a similar name exists + | +LL - FooWithLongNama!(); +LL + FooWithLongNam!(); + | error: cannot find derive macro `attr_proc_macra` in this scope --> $DIR/resolve-error.rs:45:10 @@ -51,18 +69,24 @@ error: cannot find derive macro `Dlona` in this scope --> $DIR/resolve-error.rs:40:10 | LL | #[derive(Dlona)] - | ^^^^^ help: a derive macro with a similar name exists: `Clona` + | ^^^^^ | ::: $DIR/auxiliary/derive-clona.rs:6:1 | LL | pub fn derive_clonea(input: TokenStream) -> TokenStream { | ------------------------------------------------------- similarly named derive macro `Clona` defined here + | +help: a derive macro with a similar name exists + | +LL - #[derive(Dlona)] +LL + #[derive(Clona)] + | error: cannot find derive macro `Dlona` in this scope --> $DIR/resolve-error.rs:40:10 | LL | #[derive(Dlona)] - | ^^^^^ help: a derive macro with a similar name exists: `Clona` + | ^^^^^ | ::: $DIR/auxiliary/derive-clona.rs:6:1 | @@ -70,28 +94,43 @@ LL | pub fn derive_clonea(input: TokenStream) -> TokenStream { | ------------------------------------------------------- similarly named derive macro `Clona` defined here | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: a derive macro with a similar name exists + | +LL - #[derive(Dlona)] +LL + #[derive(Clona)] + | error: cannot find derive macro `Dlone` in this scope --> $DIR/resolve-error.rs:35:10 | LL | #[derive(Dlone)] - | ^^^^^ help: a derive macro with a similar name exists: `Clone` + | ^^^^^ | --> $SRC_DIR/core/src/clone.rs:LL:COL | = note: similarly named derive macro `Clone` defined here +help: a derive macro with a similar name exists + | +LL - #[derive(Dlone)] +LL + #[derive(Clone)] + | error: cannot find derive macro `Dlone` in this scope --> $DIR/resolve-error.rs:35:10 | LL | #[derive(Dlone)] - | ^^^^^ help: a derive macro with a similar name exists: `Clone` + | ^^^^^ | --> $SRC_DIR/core/src/clone.rs:LL:COL | = note: similarly named derive macro `Clone` defined here | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: a derive macro with a similar name exists + | +LL - #[derive(Dlone)] +LL + #[derive(Clone)] + | error: cannot find attribute `FooWithLongNan` in this scope --> $DIR/resolve-error.rs:32:3 @@ -103,29 +142,41 @@ error: cannot find attribute `attr_proc_macra` in this scope --> $DIR/resolve-error.rs:28:3 | LL | #[attr_proc_macra] - | ^^^^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `attr_proc_macro` + | ^^^^^^^^^^^^^^^ | ::: $DIR/auxiliary/test-macros.rs:15:1 | LL | pub fn empty_attr(_: TokenStream, _: TokenStream) -> TokenStream { | ---------------------------------------------------------------- similarly named attribute macro `attr_proc_macro` defined here + | +help: an attribute macro with a similar name exists + | +LL - #[attr_proc_macra] +LL + #[attr_proc_macro] + | error: cannot find derive macro `FooWithLongNan` in this scope --> $DIR/resolve-error.rs:22:10 | LL | #[derive(FooWithLongNan)] - | ^^^^^^^^^^^^^^ help: a derive macro with a similar name exists: `FooWithLongName` + | ^^^^^^^^^^^^^^ | ::: $DIR/auxiliary/derive-foo.rs:6:1 | LL | pub fn derive_foo(input: TokenStream) -> TokenStream { | ---------------------------------------------------- similarly named derive macro `FooWithLongName` defined here + | +help: a derive macro with a similar name exists + | +LL - #[derive(FooWithLongNan)] +LL + #[derive(FooWithLongName)] + | error: cannot find derive macro `FooWithLongNan` in this scope --> $DIR/resolve-error.rs:22:10 | LL | #[derive(FooWithLongNan)] - | ^^^^^^^^^^^^^^ help: a derive macro with a similar name exists: `FooWithLongName` + | ^^^^^^^^^^^^^^ | ::: $DIR/auxiliary/derive-foo.rs:6:1 | @@ -133,6 +184,11 @@ LL | pub fn derive_foo(input: TokenStream) -> TokenStream { | ---------------------------------------------------- similarly named derive macro `FooWithLongName` defined here | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: a derive macro with a similar name exists + | +LL - #[derive(FooWithLongNan)] +LL + #[derive(FooWithLongName)] + | error: aborting due to 14 previous errors diff --git a/tests/ui/regions/outlives-with-missing.stderr b/tests/ui/regions/outlives-with-missing.stderr index b8762e9cb8f3..25fac1970635 100644 --- a/tests/ui/regions/outlives-with-missing.stderr +++ b/tests/ui/regions/outlives-with-missing.stderr @@ -5,7 +5,13 @@ LL | impl HandlerWrapper { | - similarly named type parameter `H` defined here ... LL | T: Send + Sync + 'static, - | ^ help: a type parameter with a similar name exists: `H` + | ^ + | +help: a type parameter with a similar name exists + | +LL - T: Send + Sync + 'static, +LL + H: Send + Sync + 'static, + | error: aborting due to 1 previous error diff --git a/tests/ui/resolve/112590-2.stderr b/tests/ui/resolve/112590-2.stderr index 28d23ccf8537..d6f4a8f22a45 100644 --- a/tests/ui/resolve/112590-2.stderr +++ b/tests/ui/resolve/112590-2.stderr @@ -63,12 +63,14 @@ error[E0433]: failed to resolve: use of unresolved module or unlinked crate `vec --> $DIR/112590-2.rs:24:24 | LL | let _t: Vec = vec::new(); - | ^^^ - | | - | use of unresolved module or unlinked crate `vec` - | help: a struct with a similar name exists (notice the capitalization): `Vec` + | ^^^ use of unresolved module or unlinked crate `vec` | = help: you might be missing a crate named `vec` +help: a struct with a similar name exists (notice the capitalization) + | +LL - let _t: Vec = vec::new(); +LL + let _t: Vec = Vec::new(); + | error: aborting due to 5 previous errors diff --git a/tests/ui/resolve/issue-10200.stderr b/tests/ui/resolve/issue-10200.stderr index 4b6d9b6f1dfa..62731960191f 100644 --- a/tests/ui/resolve/issue-10200.stderr +++ b/tests/ui/resolve/issue-10200.stderr @@ -5,9 +5,14 @@ LL | struct Foo(bool); | ----------------- similarly named tuple struct `Foo` defined here ... LL | foo(x) - | ^^^ help: a tuple struct with a similar name exists (notice the capitalization): `Foo` + | ^^^ | = note: function calls are not allowed in patterns: +help: a tuple struct with a similar name exists (notice the capitalization) + | +LL - foo(x) +LL + Foo(x) + | error: aborting due to 1 previous error diff --git a/tests/ui/resolve/issue-49074.stderr b/tests/ui/resolve/issue-49074.stderr index bbfeb4ea9483..16a4ede0c0b5 100644 --- a/tests/ui/resolve/issue-49074.stderr +++ b/tests/ui/resolve/issue-49074.stderr @@ -10,7 +10,13 @@ error: cannot find attribute `marco_use` in this scope --> $DIR/issue-49074.rs:3:3 | LL | #[marco_use] // typo - | ^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_use` + | ^^^^^^^^^ + | +help: a built-in attribute with a similar name exists + | +LL - #[marco_use] // typo +LL + #[macro_use] // typo + | error: aborting due to 2 previous errors diff --git a/tests/ui/resolve/levenshtein.stderr b/tests/ui/resolve/levenshtein.stderr index 7a1abd134330..48515b9e6bd5 100644 --- a/tests/ui/resolve/levenshtein.stderr +++ b/tests/ui/resolve/levenshtein.stderr @@ -2,7 +2,13 @@ error[E0425]: cannot find type `esize` in this scope --> $DIR/levenshtein.rs:5:11 | LL | fn foo(c: esize) {} // Misspelled primitive type name. - | ^^^^^ help: a builtin type with a similar name exists: `isize` + | ^^^^^ + | +help: a builtin type with a similar name exists + | +LL - fn foo(c: esize) {} // Misspelled primitive type name. +LL + fn foo(c: isize) {} // Misspelled primitive type name. + | error[E0425]: cannot find type `Baz` in this scope --> $DIR/levenshtein.rs:10:10 @@ -11,17 +17,28 @@ LL | enum Bar { } | -------- similarly named enum `Bar` defined here LL | LL | type A = Baz; // Misspelled type name. - | ^^^ help: an enum with a similar name exists: `Bar` + | ^^^ + | +help: an enum with a similar name exists + | +LL - type A = Baz; // Misspelled type name. +LL + type A = Bar; // Misspelled type name. + | error[E0425]: cannot find type `Opiton` in this scope --> $DIR/levenshtein.rs:12:10 | LL | type B = Opiton; // Misspelled type name from the prelude. - | ^^^^^^ help: an enum with a similar name exists: `Option` + | ^^^^^^ | --> $SRC_DIR/core/src/option.rs:LL:COL | = note: similarly named enum `Option` defined here +help: an enum with a similar name exists + | +LL - type B = Opiton; // Misspelled type name from the prelude. +LL + type B = Option; // Misspelled type name from the prelude. + | error[E0425]: cannot find type `Baz` in this scope --> $DIR/levenshtein.rs:16:14 @@ -36,7 +53,12 @@ LL | const MAX_ITEM: usize = 10; | --------------------------- similarly named constant `MAX_ITEM` defined here ... LL | let v = [0u32; MAXITEM]; // Misspelled constant name. - | ^^^^^^^ help: a constant with a similar name exists: `MAX_ITEM` + | ^^^^^^^ + | +help: a constant with a similar name exists + | +LL | let v = [0u32; MAX_ITEM]; // Misspelled constant name. + | + error[E0425]: cannot find type `first` in module `m` --> $DIR/levenshtein.rs:28:15 @@ -45,7 +67,13 @@ LL | pub struct First; | ----------------- similarly named struct `First` defined here ... LL | let b: m::first = m::second; // Misspelled item in module. - | ^^^^^ help: a struct with a similar name exists (notice the capitalization): `First` + | ^^^^^ + | +help: a struct with a similar name exists (notice the capitalization) + | +LL - let b: m::first = m::second; // Misspelled item in module. +LL + let b: m::First = m::second; // Misspelled item in module. + | error[E0425]: cannot find value `second` in module `m` --> $DIR/levenshtein.rs:28:26 @@ -54,7 +82,13 @@ LL | pub struct Second; | ------------------ similarly named unit struct `Second` defined here ... LL | let b: m::first = m::second; // Misspelled item in module. - | ^^^^^^ help: a unit struct with a similar name exists (notice the capitalization): `Second` + | ^^^^^^ + | +help: a unit struct with a similar name exists (notice the capitalization) + | +LL - let b: m::first = m::second; // Misspelled item in module. +LL + let b: m::first = m::Second; // Misspelled item in module. + | error[E0425]: cannot find function `foobar` in this scope --> $DIR/levenshtein.rs:26:5 @@ -63,7 +97,12 @@ LL | fn foo_bar() {} | ------------ similarly named function `foo_bar` defined here ... LL | foobar(); // Misspelled function name. - | ^^^^^^ help: a function with a similar name exists: `foo_bar` + | ^^^^^^ + | +help: a function with a similar name exists + | +LL | foo_bar(); // Misspelled function name. + | + error: aborting due to 8 previous errors diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr index 81356c5040f8..5349108065dc 100644 --- a/tests/ui/resolve/privacy-enum-ctor.stderr +++ b/tests/ui/resolve/privacy-enum-ctor.stderr @@ -149,13 +149,18 @@ LL | pub enum E { | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z; - | ^ help: an enum with a similar name exists: `E` + | ^ | note: enum `m::Z` exists but is inaccessible --> $DIR/privacy-enum-ctor.rs:12:9 | LL | pub(in crate::m) enum Z { | ^^^^^^^^^^^^^^^^^^^^^^^ not accessible +help: an enum with a similar name exists + | +LL - let _: Z = m::n::Z; +LL + let _: E = m::n::Z; + | error[E0423]: expected value, found enum `m::n::Z` --> $DIR/privacy-enum-ctor.rs:58:16 @@ -192,13 +197,18 @@ LL | pub enum E { | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z::Fn; - | ^ help: an enum with a similar name exists: `E` + | ^ | note: enum `m::Z` exists but is inaccessible --> $DIR/privacy-enum-ctor.rs:12:9 | LL | pub(in crate::m) enum Z { | ^^^^^^^^^^^^^^^^^^^^^^^ not accessible +help: an enum with a similar name exists + | +LL - let _: Z = m::n::Z::Fn; +LL + let _: E = m::n::Z::Fn; + | error[E0425]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:65:12 @@ -207,13 +217,18 @@ LL | pub enum E { | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z::Struct; - | ^ help: an enum with a similar name exists: `E` + | ^ | note: enum `m::Z` exists but is inaccessible --> $DIR/privacy-enum-ctor.rs:12:9 | LL | pub(in crate::m) enum Z { | ^^^^^^^^^^^^^^^^^^^^^^^ not accessible +help: an enum with a similar name exists + | +LL - let _: Z = m::n::Z::Struct; +LL + let _: E = m::n::Z::Struct; + | error[E0425]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:69:12 @@ -222,13 +237,18 @@ LL | pub enum E { | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z::Unit {}; - | ^ help: an enum with a similar name exists: `E` + | ^ | note: enum `m::Z` exists but is inaccessible --> $DIR/privacy-enum-ctor.rs:12:9 | LL | pub(in crate::m) enum Z { | ^^^^^^^^^^^^^^^^^^^^^^^ not accessible +help: an enum with a similar name exists + | +LL - let _: Z = m::n::Z::Unit {}; +LL + let _: E = m::n::Z::Unit {}; + | error[E0603]: enum `Z` is private --> $DIR/privacy-enum-ctor.rs:58:22 diff --git a/tests/ui/resolve/privacy-struct-ctor.stderr b/tests/ui/resolve/privacy-struct-ctor.stderr index 96c3e6e5122d..5a01d51d24ff 100644 --- a/tests/ui/resolve/privacy-struct-ctor.stderr +++ b/tests/ui/resolve/privacy-struct-ctor.stderr @@ -5,10 +5,13 @@ LL | pub struct S(u8); | ----------------- similarly named tuple struct `S` defined here ... LL | Z; - | ^ - | | - | constructor is not visible here due to private fields - | help: a tuple struct with a similar name exists: `S` + | ^ constructor is not visible here due to private fields + | +help: a tuple struct with a similar name exists + | +LL - Z; +LL + S; + | error[E0423]: expected value, found struct `S` --> $DIR/privacy-struct-ctor.rs:34:5 diff --git a/tests/ui/resolve/suggestions/suggest-path-instead-of-mod-dot-item.stderr b/tests/ui/resolve/suggestions/suggest-path-instead-of-mod-dot-item.stderr index 5db943cd10d0..89c0cd54faee 100644 --- a/tests/ui/resolve/suggestions/suggest-path-instead-of-mod-dot-item.stderr +++ b/tests/ui/resolve/suggestions/suggest-path-instead-of-mod-dot-item.stderr @@ -73,9 +73,13 @@ LL | pub const I: i32 = 1; | --------------------- similarly named constant `I` defined here ... LL | v.push(a::b); - | ^^^- - | | - | help: a constant with a similar name exists: `I` + | ^^^^ + | +help: a constant with a similar name exists + | +LL - v.push(a::b); +LL + v.push(a::I); + | error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:52:5 @@ -104,9 +108,13 @@ LL | pub const I: i32 = 1; | --------------------- similarly named constant `I` defined here ... LL | a::b - | ^^^- - | | - | help: a constant with a similar name exists: `I` + | ^^^^ + | +help: a constant with a similar name exists + | +LL - a::b +LL + a::I + | error[E0423]: expected function, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:65:5 @@ -115,9 +123,13 @@ LL | pub const I: i32 = 1; | --------------------- similarly named constant `I` defined here ... LL | a::b() - | ^^^- - | | - | help: a constant with a similar name exists: `I` + | ^^^^ + | +help: a constant with a similar name exists + | +LL - a::b() +LL + a::I() + | error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:72:9 diff --git a/tests/ui/resolve/tuple-struct-alias.stderr b/tests/ui/resolve/tuple-struct-alias.stderr index bf026a499b8c..89b536708372 100644 --- a/tests/ui/resolve/tuple-struct-alias.stderr +++ b/tests/ui/resolve/tuple-struct-alias.stderr @@ -5,7 +5,13 @@ LL | struct S(u8, u16); | ------------------ similarly named tuple struct `S` defined here ... LL | A(..) => {} - | ^ help: a tuple struct with a similar name exists: `S` + | ^ + | +help: a tuple struct with a similar name exists + | +LL - A(..) => {} +LL + S(..) => {} + | error[E0423]: expected function, tuple struct or tuple variant, found type alias `A` --> $DIR/tuple-struct-alias.rs:5:13 diff --git a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr index 039410f8795f..9c874d980cbe 100644 --- a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr +++ b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr @@ -5,7 +5,13 @@ LL | config: String, | ------ a field by that name exists in `Self` ... LL | Self { config } - | ^^^^^^ help: a local variable with a similar name exists: `cofig` + | ^^^^^^ + | +help: a local variable with a similar name exists + | +LL - Self { config } +LL + Self { cofig } + | error[E0425]: cannot find value `config` in this scope --> $DIR/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs:11:20 @@ -14,15 +20,26 @@ LL | config: String, | ------ a field by that name exists in `Self` ... LL | println!("{config}"); - | ^^^^^^ help: a local variable with a similar name exists: `cofig` + | ^^^^^^ + | +help: a local variable with a similar name exists + | +LL - println!("{config}"); +LL + println!("{cofig}"); + | error[E0425]: cannot find value `config` in this scope --> $DIR/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs:15:20 | LL | println!("{config}"); - | ^^^^^^ help: a local variable with a similar name exists: `cofig` + | ^^^^^^ | = help: you might have meant to use the available field in a format string: `"{}", self.config` +help: a local variable with a similar name exists + | +LL - println!("{config}"); +LL + println!("{cofig}"); + | error[E0425]: cannot find value `bah` in this scope --> $DIR/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs:33:9 diff --git a/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr b/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr index 2d0d0d0f3867..fef1f52b86b7 100644 --- a/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr +++ b/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr @@ -2,10 +2,12 @@ error[E0433]: failed to resolve: could not find `Struc` in `module` --> $DIR/typo-suggestion-mistyped-in-path.rs:35:13 | LL | module::Struc::foo(); - | ^^^^^ - | | - | could not find `Struc` in `module` - | help: a struct with a similar name exists: `Struct` + | ^^^^^ could not find `Struc` in `module` + | +help: a struct with a similar name exists + | +LL | module::Struct::foo(); + | + error[E0599]: no function or associated item named `fob` found for struct `Struct` in the current scope --> $DIR/typo-suggestion-mistyped-in-path.rs:23:13 @@ -26,10 +28,12 @@ error[E0433]: failed to resolve: use of undeclared type `Struc` --> $DIR/typo-suggestion-mistyped-in-path.rs:27:5 | LL | Struc::foo(); - | ^^^^^ - | | - | use of undeclared type `Struc` - | help: a struct with a similar name exists: `Struct` + | ^^^^^ use of undeclared type `Struc` + | +help: a struct with a similar name exists + | +LL | Struct::foo(); + | + error[E0433]: failed to resolve: use of unresolved module or unlinked crate `modul` --> $DIR/typo-suggestion-mistyped-in-path.rs:31:5 @@ -46,10 +50,12 @@ error[E0433]: failed to resolve: use of undeclared type `Trai` --> $DIR/typo-suggestion-mistyped-in-path.rs:39:5 | LL | Trai::foo(); - | ^^^^ - | | - | use of undeclared type `Trai` - | help: a trait with a similar name exists: `Trait` + | ^^^^ use of undeclared type `Trai` + | +help: a trait with a similar name exists + | +LL | Trait::foo(); + | + error: aborting due to 5 previous errors diff --git a/tests/ui/span/suggestion-raw-68962.stderr b/tests/ui/span/suggestion-raw-68962.stderr index 2e25f5cbdf58..2271acf15a80 100644 --- a/tests/ui/span/suggestion-raw-68962.stderr +++ b/tests/ui/span/suggestion-raw-68962.stderr @@ -2,7 +2,13 @@ error[E0425]: cannot find value `fina` in this scope --> $DIR/suggestion-raw-68962.rs:7:5 | LL | fina; - | ^^^^ help: a local variable with a similar name exists: `r#final` + | ^^^^ + | +help: a local variable with a similar name exists + | +LL - fina; +LL + r#final; + | error[E0425]: cannot find function `f` in this scope --> $DIR/suggestion-raw-68962.rs:10:5 @@ -11,7 +17,13 @@ LL | fn r#fn() {} | --------- similarly named function `r#fn` defined here ... LL | f(); - | ^ help: a function with a similar name exists: `r#fn` + | ^ + | +help: a function with a similar name exists + | +LL - f(); +LL + r#fn(); + | error: aborting due to 2 previous errors diff --git a/tests/ui/span/typo-suggestion.stderr b/tests/ui/span/typo-suggestion.stderr index 61d4e06119c4..1f679221c002 100644 --- a/tests/ui/span/typo-suggestion.stderr +++ b/tests/ui/span/typo-suggestion.stderr @@ -8,7 +8,13 @@ error[E0425]: cannot find value `fob` in this scope --> $DIR/typo-suggestion.rs:8:26 | LL | println!("Hello {}", fob); - | ^^^ help: a local variable with a similar name exists: `foo` + | ^^^ + | +help: a local variable with a similar name exists + | +LL - println!("Hello {}", fob); +LL + println!("Hello {}", foo); + | error: aborting due to 2 previous errors diff --git a/tests/ui/stability-attribute/issue-109177.stderr b/tests/ui/stability-attribute/issue-109177.stderr index 9c2ac591ace0..6f89bde7f894 100644 --- a/tests/ui/stability-attribute/issue-109177.stderr +++ b/tests/ui/stability-attribute/issue-109177.stderr @@ -2,12 +2,18 @@ error[E0425]: cannot find function `foo1` in crate `similar_unstable_method` --> $DIR/issue-109177.rs:7:30 | LL | similar_unstable_method::foo1(); - | ^^^^ help: a function with a similar name exists: `foo` + | ^^^^ | ::: $DIR/auxiliary/similar-unstable-method.rs:5:1 | LL | pub fn foo() {} | ------------ similarly named function `foo` defined here + | +help: a function with a similar name exists + | +LL - similar_unstable_method::foo1(); +LL + similar_unstable_method::foo(); + | error[E0599]: no method named `foo1` found for struct `Foo` in the current scope --> $DIR/issue-109177.rs:11:9 diff --git a/tests/ui/structs/struct-fields-shorthand-unresolved.stderr b/tests/ui/structs/struct-fields-shorthand-unresolved.stderr index b485c17c1b27..5d8321130958 100644 --- a/tests/ui/structs/struct-fields-shorthand-unresolved.stderr +++ b/tests/ui/structs/struct-fields-shorthand-unresolved.stderr @@ -2,7 +2,13 @@ error[E0425]: cannot find value `y` in this scope --> $DIR/struct-fields-shorthand-unresolved.rs:10:9 | LL | y - | ^ help: a local variable with a similar name exists: `x` + | ^ + | +help: a local variable with a similar name exists + | +LL - y +LL + x + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/attribute-typos.stderr b/tests/ui/suggestions/attribute-typos.stderr index 1816a27dcdc8..960e0b0f620f 100644 --- a/tests/ui/suggestions/attribute-typos.stderr +++ b/tests/ui/suggestions/attribute-typos.stderr @@ -8,23 +8,38 @@ error: cannot find attribute `rustc_dumm` in this scope --> $DIR/attribute-typos.rs:7:3 | LL | #[rustc_dumm] - | ^^^^^^^^^^ help: a built-in attribute with a similar name exists: `rustc_dummy` + | ^^^^^^^^^^ + | +help: a built-in attribute with a similar name exists + | +LL | #[rustc_dummy] + | + error: cannot find attribute `tests` in this scope --> $DIR/attribute-typos.rs:4:3 | LL | #[tests] - | ^^^^^ help: an attribute macro with a similar name exists: `test` + | ^^^^^ | --> $SRC_DIR/core/src/macros/mod.rs:LL:COL | = note: similarly named attribute macro `test` defined here +help: an attribute macro with a similar name exists + | +LL - #[tests] +LL + #[test] + | error: cannot find attribute `deprcated` in this scope --> $DIR/attribute-typos.rs:1:3 | LL | #[deprcated] - | ^^^^^^^^^ help: a built-in attribute with a similar name exists: `deprecated` + | ^^^^^^^^^ + | +help: a built-in attribute with a similar name exists + | +LL | #[deprecated] + | + error: aborting due to 4 previous errors diff --git a/tests/ui/suggestions/case-difference-suggestions.stderr b/tests/ui/suggestions/case-difference-suggestions.stderr index c3d2410a6eb2..198c3c7a38c9 100644 --- a/tests/ui/suggestions/case-difference-suggestions.stderr +++ b/tests/ui/suggestions/case-difference-suggestions.stderr @@ -2,97 +2,193 @@ error[E0425]: cannot find value `Hello` in this scope --> $DIR/case-difference-suggestions.rs:5:20 | LL | println!("{}", Hello); - | ^^^^^ help: a local variable with a similar name exists: `hello` + | ^^^^^ + | +help: a local variable with a similar name exists + | +LL - println!("{}", Hello); +LL + println!("{}", hello); + | error[E0425]: cannot find value `myvariable` in this scope --> $DIR/case-difference-suggestions.rs:9:20 | LL | println!("{}", myvariable); - | ^^^^^^^^^^ help: a local variable with a similar name exists (notice the capitalization): `myVariable` + | ^^^^^^^^^^ + | +help: a local variable with a similar name exists (notice the capitalization) + | +LL - println!("{}", myvariable); +LL + println!("{}", myVariable); + | error[E0425]: cannot find value `User_Name` in this scope --> $DIR/case-difference-suggestions.rs:13:20 | LL | println!("{}", User_Name); - | ^^^^^^^^^ help: a local variable with a similar name exists: `user_name` + | ^^^^^^^^^ + | +help: a local variable with a similar name exists + | +LL - println!("{}", User_Name); +LL + println!("{}", user_name); + | error[E0425]: cannot find value `foo` in this scope --> $DIR/case-difference-suggestions.rs:17:20 | LL | println!("{}", foo); - | ^^^ help: a local variable with a similar name exists (notice the capitalization): `FOO` + | ^^^ + | +help: a local variable with a similar name exists (notice the capitalization) + | +LL - println!("{}", foo); +LL + println!("{}", FOO); + | error[E0425]: cannot find value `FFOO` in this scope --> $DIR/case-difference-suggestions.rs:22:20 | LL | println!("{}", FFOO); - | ^^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `FFO0` + | ^^^^ + | +help: a local variable with a similar name exists (notice the digit/letter confusion) + | +LL - println!("{}", FFOO); +LL + println!("{}", FFO0); + | error[E0425]: cannot find value `list` in this scope --> $DIR/case-difference-suggestions.rs:25:20 | LL | println!("{}", list); - | ^^^^ help: a local variable with a similar name exists: `l1st` + | ^^^^ + | +help: a local variable with a similar name exists + | +LL - println!("{}", list); +LL + println!("{}", l1st); + | error[E0425]: cannot find value `SS` in this scope --> $DIR/case-difference-suggestions.rs:28:20 | LL | println!("{}", SS); - | ^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `S5` + | ^^ + | +help: a local variable with a similar name exists (notice the digit/letter confusion) + | +LL - println!("{}", SS); +LL + println!("{}", S5); + | error[E0425]: cannot find value `a55` in this scope --> $DIR/case-difference-suggestions.rs:31:20 | LL | println!("{}", a55); - | ^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `aS5` + | ^^^ + | +help: a local variable with a similar name exists (notice the digit/letter confusion) + | +LL - println!("{}", a55); +LL + println!("{}", aS5); + | error[E0425]: cannot find value `BB` in this scope --> $DIR/case-difference-suggestions.rs:34:20 | LL | println!("{}", BB); - | ^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `B8` + | ^^ + | +help: a local variable with a similar name exists (notice the digit/letter confusion) + | +LL - println!("{}", BB); +LL + println!("{}", B8); + | error[E0425]: cannot find value `gg` in this scope --> $DIR/case-difference-suggestions.rs:37:20 | LL | println!("{}", gg); - | ^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `g9` + | ^^ + | +help: a local variable with a similar name exists (notice the digit/letter confusion) + | +LL - println!("{}", gg); +LL + println!("{}", g9); + | error[E0425]: cannot find value `old` in this scope --> $DIR/case-difference-suggestions.rs:40:20 | LL | println!("{}", old); - | ^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `o1d` + | ^^^ + | +help: a local variable with a similar name exists (notice the digit/letter confusion) + | +LL - println!("{}", old); +LL + println!("{}", o1d); + | error[E0425]: cannot find value `newl` in this scope --> $DIR/case-difference-suggestions.rs:43:20 | LL | println!("{}", newl); - | ^^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `new1` + | ^^^^ + | +help: a local variable with a similar name exists (notice the digit/letter confusion) + | +LL - println!("{}", newl); +LL + println!("{}", new1); + | error[E0425]: cannot find value `app1e` in this scope --> $DIR/case-difference-suggestions.rs:46:20 | LL | println!("{}", app1e); - | ^^^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `apple` + | ^^^^^ + | +help: a local variable with a similar name exists (notice the digit/letter confusion) + | +LL - println!("{}", app1e); +LL + println!("{}", apple); + | error[E0425]: cannot find value `A` in this scope --> $DIR/case-difference-suggestions.rs:49:20 | LL | println!("{}", A); - | ^ help: a local variable with a similar name exists: `a` + | ^ + | +help: a local variable with a similar name exists + | +LL - println!("{}", A); +LL + println!("{}", a); + | error[E0425]: cannot find value `world1U` in this scope --> $DIR/case-difference-suggestions.rs:52:20 | LL | println!("{}", world1U); - | ^^^^^^^ help: a local variable with a similar name exists (notice the capitalization and digit/letter confusion): `worldlu` + | ^^^^^^^ + | +help: a local variable with a similar name exists (notice the capitalization and digit/letter confusion) + | +LL - println!("{}", world1U); +LL + println!("{}", worldlu); + | error[E0425]: cannot find value `myv4r1able` in this scope --> $DIR/case-difference-suggestions.rs:55:20 | LL | println!("{}", myv4r1able); - | ^^^^^^^^^^ help: a local variable with a similar name exists (notice the capitalization and digit/letter confusion): `myV4rlable` + | ^^^^^^^^^^ + | +help: a local variable with a similar name exists (notice the capitalization and digit/letter confusion) + | +LL - println!("{}", myv4r1able); +LL + println!("{}", myV4rlable); + | error: aborting due to 16 previous errors diff --git a/tests/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.stderr b/tests/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.stderr index 112ed6fffd50..e54e5acffe8f 100644 --- a/tests/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.stderr +++ b/tests/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.stderr @@ -2,11 +2,16 @@ error[E0573]: expected type, found module `result` --> $DIR/do-not-attempt-to-add-suggestions-with-no-changes.rs:3:6 | LL | impl result { - | ^^^^^^ help: an enum with a similar name exists: `Result` + | ^^^^^^ | --> $SRC_DIR/core/src/result.rs:LL:COL | = note: similarly named enum `Result` defined here +help: an enum with a similar name exists + | +LL - impl result { +LL + impl Result { + | error[E0573]: expected type, found variant `Err` --> $DIR/do-not-attempt-to-add-suggestions-with-no-changes.rs:4:25 diff --git a/tests/ui/suggestions/issue-66968-suggest-sorted-words.stderr b/tests/ui/suggestions/issue-66968-suggest-sorted-words.stderr index ce0087fbfcba..b55353c9e6e4 100644 --- a/tests/ui/suggestions/issue-66968-suggest-sorted-words.stderr +++ b/tests/ui/suggestions/issue-66968-suggest-sorted-words.stderr @@ -2,7 +2,13 @@ error[E0425]: cannot find value `a_variable_longer_name` in this scope --> $DIR/issue-66968-suggest-sorted-words.rs:3:20 | LL | println!("{}", a_variable_longer_name); - | ^^^^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `a_longer_variable_name` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: a local variable with a similar name exists + | +LL - println!("{}", a_variable_longer_name); +LL + println!("{}", a_longer_variable_name); + | error: aborting due to 1 previous error diff --git a/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr b/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr index 40936ce1ec34..660bbc120d0e 100644 --- a/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr +++ b/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr @@ -84,11 +84,15 @@ error[E0404]: expected trait, found struct `String` --> $DIR/assoc_type_bound_with_struct.rs:19:51 | LL | fn issue_95327() where ::Assoc: String {} - | ^^^^^^ help: a trait with a similar name exists: `ToString` + | ^^^^^^ | --> $SRC_DIR/alloc/src/string.rs:LL:COL | = note: similarly named trait `ToString` defined here +help: a trait with a similar name exists + | +LL | fn issue_95327() where ::Assoc: ToString {} + | ++ error: aborting due to 6 previous errors diff --git a/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr b/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr index e499451d8971..d2eea3a805d9 100644 --- a/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr +++ b/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr @@ -42,10 +42,16 @@ error[E0425]: cannot find function `main8` in this scope --> $DIR/ice-120503-async-const-method.rs:11:9 | LL | main8().await; - | ^^^^^ help: a function with a similar name exists: `main` + | ^^^^^ ... LL | fn main() {} | --------- similarly named function `main` defined here + | +help: a function with a similar name exists + | +LL - main8().await; +LL + main().await; + | error: aborting due to 5 previous errors diff --git a/tests/ui/traits/const-traits/mismatched_generic_args.stderr b/tests/ui/traits/const-traits/mismatched_generic_args.stderr index 8e12b40381fd..e8103313dc4f 100644 --- a/tests/ui/traits/const-traits/mismatched_generic_args.stderr +++ b/tests/ui/traits/const-traits/mismatched_generic_args.stderr @@ -5,7 +5,13 @@ LL | pub fn add(x: Quantity) -> Quantity { | - similarly named const parameter `U` defined here LL | LL | x + y - | ^ help: a const parameter with a similar name exists: `U` + | ^ + | +help: a const parameter with a similar name exists + | +LL - x + y +LL + x + U + | warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/mismatched_generic_args.rs:1:12 diff --git a/tests/ui/traits/impl-for-module.stderr b/tests/ui/traits/impl-for-module.stderr index b715c699e89f..1011a913a4ab 100644 --- a/tests/ui/traits/impl-for-module.stderr +++ b/tests/ui/traits/impl-for-module.stderr @@ -5,7 +5,13 @@ LL | trait A { | ------- similarly named trait `A` defined here ... LL | impl A for a { - | ^ help: a trait with a similar name exists: `A` + | ^ + | +help: a trait with a similar name exists + | +LL - impl A for a { +LL + impl A for A { + | error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/type-error-drop-elaboration.stderr b/tests/ui/type-alias-impl-trait/type-error-drop-elaboration.stderr index 1cb33eabd902..e5c35d58b72d 100644 --- a/tests/ui/type-alias-impl-trait/type-error-drop-elaboration.stderr +++ b/tests/ui/type-alias-impl-trait/type-error-drop-elaboration.stderr @@ -2,10 +2,16 @@ error[E0425]: cannot find function `value` in this scope --> $DIR/type-error-drop-elaboration.rs:12:5 | LL | value() - | ^^^^^ help: a constant with a similar name exists: `VALUE` + | ^^^^^ ... LL | const VALUE: Foo = foo(); | ------------------------- similarly named constant `VALUE` defined here + | +help: a constant with a similar name exists + | +LL - value() +LL + VALUE() + | error: aborting due to 1 previous error diff --git a/tests/ui/type/issue-7607-1.stderr b/tests/ui/type/issue-7607-1.stderr index ac6034da75f1..8edd0d31d791 100644 --- a/tests/ui/type/issue-7607-1.stderr +++ b/tests/ui/type/issue-7607-1.stderr @@ -2,11 +2,16 @@ error[E0425]: cannot find type `Fo` in this scope --> $DIR/issue-7607-1.rs:5:6 | LL | impl Fo { - | ^^ help: a trait with a similar name exists: `Fn` + | ^^ | --> $SRC_DIR/core/src/ops/function.rs:LL:COL | = note: similarly named trait `Fn` defined here +help: a trait with a similar name exists + | +LL - impl Fo { +LL + impl Fn { + | error: aborting due to 1 previous error diff --git a/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.stderr b/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.stderr index 4ccfacfb0052..1d766e6e5cdb 100644 --- a/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.stderr +++ b/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.stderr @@ -14,7 +14,13 @@ error[E0425]: cannot find value `g` in this scope --> $DIR/issue-114423-ice-regression-in-suggestion.rs:11:22 | LL | let _ = RGB { r, g, b }; - | ^ help: a local variable with a similar name exists: `b` + | ^ + | +help: a local variable with a similar name exists + | +LL - let _ = RGB { r, g, b }; +LL + let _ = RGB { r, b, b }; + | error[E0308]: mismatched types --> $DIR/issue-114423-ice-regression-in-suggestion.rs:7:50 diff --git a/tests/ui/typeck/issue-120856.stderr b/tests/ui/typeck/issue-120856.stderr index e366744409f4..4ff9f345c48b 100644 --- a/tests/ui/typeck/issue-120856.stderr +++ b/tests/ui/typeck/issue-120856.stderr @@ -2,23 +2,26 @@ error[E0433]: failed to resolve: use of unresolved module or unlinked crate `n` --> $DIR/issue-120856.rs:1:37 | LL | pub type Archived = ::Archived; - | ^ - | | - | use of unresolved module or unlinked crate `n` - | help: a trait with a similar name exists: `Fn` + | ^ use of unresolved module or unlinked crate `n` | = help: you might be missing a crate named `n` +help: a trait with a similar name exists + | +LL | pub type Archived = ::Archived; + | + error[E0433]: failed to resolve: use of unresolved module or unlinked crate `m` --> $DIR/issue-120856.rs:1:25 | LL | pub type Archived = ::Archived; - | ^ - | | - | use of unresolved module or unlinked crate `m` - | help: a type parameter with a similar name exists: `T` + | ^ use of unresolved module or unlinked crate `m` | = help: you might be missing a crate named `m` +help: a type parameter with a similar name exists + | +LL - pub type Archived = ::Archived; +LL + pub type Archived = ::Archived; + | error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/issue-83693.stderr b/tests/ui/typeck/issue-83693.stderr index 521288c43402..2f83e5daff97 100644 --- a/tests/ui/typeck/issue-83693.stderr +++ b/tests/ui/typeck/issue-83693.stderr @@ -2,11 +2,15 @@ error[E0425]: cannot find type `F` in this scope --> $DIR/issue-83693.rs:6:6 | LL | impl F { - | ^ help: a trait with a similar name exists: `Fn` + | ^ | --> $SRC_DIR/core/src/ops/function.rs:LL:COL | = note: similarly named trait `Fn` defined here +help: a trait with a similar name exists + | +LL | impl Fn { + | + error[E0425]: cannot find type `TestResult` in this scope --> $DIR/issue-83693.rs:9:22 diff --git a/tests/ui/typeck/issue-88844.stderr b/tests/ui/typeck/issue-88844.stderr index a5f4310c34dd..6d21317dfd7f 100644 --- a/tests/ui/typeck/issue-88844.stderr +++ b/tests/ui/typeck/issue-88844.stderr @@ -5,7 +5,12 @@ LL | struct Struct { value: i32 } | ------------- similarly named struct `Struct` defined here ... LL | impl Stuct { - | ^^^^^ help: a struct with a similar name exists: `Struct` + | ^^^^^ + | +help: a struct with a similar name exists + | +LL | impl Struct { + | + error: aborting due to 1 previous error diff --git a/tests/ui/ufcs/ufcs-partially-resolved.stderr b/tests/ui/ufcs/ufcs-partially-resolved.stderr index a854ecb06222..e1df200feccf 100644 --- a/tests/ui/ufcs/ufcs-partially-resolved.stderr +++ b/tests/ui/ufcs/ufcs-partially-resolved.stderr @@ -5,17 +5,27 @@ LL | type Y = u16; | ------------- similarly named associated type `Y` defined here ... LL | let _: ::N; - | ^ help: an associated type with a similar name exists: `Y` + | ^ + | +help: an associated type with a similar name exists + | +LL - let _: ::N; +LL + let _: ::Y; + | error[E0404]: expected trait, found enum `E` --> $DIR/ufcs-partially-resolved.rs:20:19 | LL | let _: ::N; - | ^ help: a trait with a similar name exists: `Eq` + | ^ | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here +help: a trait with a similar name exists + | +LL | let _: ::N; + | + error[E0404]: expected trait, found type alias `A` --> $DIR/ufcs-partially-resolved.rs:21:19 @@ -36,17 +46,27 @@ LL | fn Y() {} | ------ similarly named associated function `Y` defined here ... LL | ::N; - | ^ help: an associated function with a similar name exists: `Y` + | ^ + | +help: an associated function with a similar name exists + | +LL - ::N; +LL + ::Y; + | error[E0404]: expected trait, found enum `E` --> $DIR/ufcs-partially-resolved.rs:23:12 | LL | ::N; - | ^ help: a trait with a similar name exists: `Eq` + | ^ | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here +help: a trait with a similar name exists + | +LL | ::N; + | + error[E0404]: expected trait, found type alias `A` --> $DIR/ufcs-partially-resolved.rs:24:12 @@ -64,21 +84,29 @@ error[E0404]: expected trait, found enum `E` --> $DIR/ufcs-partially-resolved.rs:26:19 | LL | let _: ::Y; - | ^ help: a trait with a similar name exists: `Eq` + | ^ | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here +help: a trait with a similar name exists + | +LL | let _: ::Y; + | + error[E0404]: expected trait, found enum `E` --> $DIR/ufcs-partially-resolved.rs:28:12 | LL | ::Y; - | ^ help: a trait with a similar name exists: `Eq` + | ^ | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here +help: a trait with a similar name exists + | +LL | ::Y; + | + error[E0576]: cannot find associated type `N` in trait `Tr` --> $DIR/ufcs-partially-resolved.rs:30:24 @@ -87,17 +115,27 @@ LL | type Y = u16; | ------------- similarly named associated type `Y` defined here ... LL | let _: ::N::NN; - | ^ help: an associated type with a similar name exists: `Y` + | ^ + | +help: an associated type with a similar name exists + | +LL - let _: ::N::NN; +LL + let _: ::Y::NN; + | error[E0404]: expected trait, found enum `E` --> $DIR/ufcs-partially-resolved.rs:31:19 | LL | let _: ::N::NN; - | ^ help: a trait with a similar name exists: `Eq` + | ^ | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here +help: a trait with a similar name exists + | +LL | let _: ::N::NN; + | + error[E0404]: expected trait, found type alias `A` --> $DIR/ufcs-partially-resolved.rs:32:19 @@ -118,17 +156,27 @@ LL | type Y = u16; | ------------- similarly named associated type `Y` defined here ... LL | ::N::NN; - | ^ help: an associated type with a similar name exists: `Y` + | ^ + | +help: an associated type with a similar name exists + | +LL - ::N::NN; +LL + ::Y::NN; + | error[E0404]: expected trait, found enum `E` --> $DIR/ufcs-partially-resolved.rs:34:12 | LL | ::N::NN; - | ^ help: a trait with a similar name exists: `Eq` + | ^ | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here +help: a trait with a similar name exists + | +LL | ::N::NN; + | + error[E0404]: expected trait, found type alias `A` --> $DIR/ufcs-partially-resolved.rs:35:12 @@ -146,21 +194,29 @@ error[E0404]: expected trait, found enum `E` --> $DIR/ufcs-partially-resolved.rs:37:19 | LL | let _: ::Y::NN; - | ^ help: a trait with a similar name exists: `Eq` + | ^ | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here +help: a trait with a similar name exists + | +LL | let _: ::Y::NN; + | + error[E0404]: expected trait, found enum `E` --> $DIR/ufcs-partially-resolved.rs:39:12 | LL | ::Y::NN; - | ^ help: a trait with a similar name exists: `Eq` + | ^ | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here +help: a trait with a similar name exists + | +LL | ::Y::NN; + | + error[E0405]: cannot find trait `N` in trait `Tr` --> $DIR/ufcs-partially-resolved.rs:41:23 @@ -229,9 +285,13 @@ LL | type X = u16; | ------------- similarly named associated type `X` defined here ... LL | let _: ::Z; - | ^^^^^^^^^^^^- - | | - | help: an associated type with a similar name exists: `X` + | ^^^^^^^^^^^^^ + | +help: an associated type with a similar name exists + | +LL - let _: ::Z; +LL + let _: ::X; + | error[E0575]: expected method or associated constant, found associated type `Dr::X` --> $DIR/ufcs-partially-resolved.rs:53:5 @@ -240,9 +300,13 @@ LL | fn Z() {} | ------ similarly named associated function `Z` defined here ... LL | ::X; - | ^^^^^^^^^^^^- - | | - | help: an associated function with a similar name exists: `Z` + | ^^^^^^^^^^^^^ + | +help: an associated function with a similar name exists + | +LL - ::X; +LL + ::Z; + | error[E0575]: expected associated type, found associated function `Dr::Z` --> $DIR/ufcs-partially-resolved.rs:54:12 @@ -251,9 +315,13 @@ LL | type X = u16; | ------------- similarly named associated type `X` defined here ... LL | let _: ::Z::N; - | ^^^^^^^^^^^^-^^^ - | | - | help: an associated type with a similar name exists: `X` + | ^^^^^^^^^^^^^^^^ + | +help: an associated type with a similar name exists + | +LL - let _: ::Z::N; +LL + let _: ::X::N; + | error[E0223]: ambiguous associated type --> $DIR/ufcs-partially-resolved.rs:36:12 diff --git a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr index 5f22c781345f..7e295c1d54f9 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr @@ -8,7 +8,13 @@ error[E0425]: cannot find value `y` in this scope --> $DIR/unboxed-closures-type-mismatch-closure-from-another-scope.rs:9:26 | LL | closure(&mut p, &y); - | ^ help: a local variable with a similar name exists: `p` + | ^ + | +help: a local variable with a similar name exists + | +LL - closure(&mut p, &y); +LL + closure(&mut p, &p); + | error[E0308]: mismatched types --> $DIR/unboxed-closures-type-mismatch-closure-from-another-scope.rs:9:17 From d0e4b5b159d2df4ba7c6c113171e3f6049d889f9 Mon Sep 17 00:00:00 2001 From: irelaxcn Date: Wed, 10 Dec 2025 01:34:25 +0800 Subject: [PATCH 437/585] Fix typo in deprecated lint `string_to_string` message --- clippy_lints/src/deprecated_lints.rs | 2 +- tests/ui/deprecated.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index f010d17917f9..6e62e983d2f3 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -34,7 +34,7 @@ macro_rules! declare_with_version { #[clippy::version = "pre 1.29.0"] ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"), #[clippy::version = "1.91.0"] - ("clippy::string_to_string", "`clippy:implicit_clone` covers those cases"), + ("clippy::string_to_string", "`clippy::implicit_clone` covers those cases"), #[clippy::version = "pre 1.29.0"] ("clippy::unsafe_vector_initialization", "the suggested alternative could be substantially slower"), #[clippy::version = "pre 1.29.0"] diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index cd225da611c4..fa70371b926f 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -61,7 +61,7 @@ error: lint `clippy::should_assert_eq` has been removed: `assert!(a == b)` can n LL | #![warn(clippy::should_assert_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::string_to_string` has been removed: `clippy:implicit_clone` covers those cases +error: lint `clippy::string_to_string` has been removed: `clippy::implicit_clone` covers those cases --> tests/ui/deprecated.rs:15:9 | LL | #![warn(clippy::string_to_string)] From 1232c81a3eb6403b04a1795fe5e4bdb678f236fe Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Tue, 9 Dec 2025 22:56:23 +0100 Subject: [PATCH 438/585] Add needless_type_cast lint --- CHANGELOG.md | 1 + README.md | 2 +- book/src/README.md | 2 +- clippy_lints/src/casts/mod.rs | 32 ++ clippy_lints/src/casts/needless_type_cast.rs | 289 +++++++++++++++++++ clippy_lints/src/declared_lints.rs | 1 + tests/ui/needless_type_cast.fixed | 182 ++++++++++++ tests/ui/needless_type_cast.rs | 182 ++++++++++++ tests/ui/needless_type_cast.stderr | 71 +++++ 9 files changed, 760 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/casts/needless_type_cast.rs create mode 100644 tests/ui/needless_type_cast.fixed create mode 100644 tests/ui/needless_type_cast.rs create mode 100644 tests/ui/needless_type_cast.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c81fa47eca9..dfbd07e69e53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6688,6 +6688,7 @@ Released 2018-09-13 [`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return [`needless_return_with_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return_with_question_mark [`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn +[`needless_type_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_type_cast [`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update [`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord [`neg_multiply`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_multiply diff --git a/README.md b/README.md index 20a5e997e629..78498c73ae78 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 750 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 800 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. diff --git a/book/src/README.md b/book/src/README.md index 5d2c3972b060..c5b264c9f703 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 750 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 800 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 47cc1da0a6e9..494d6180d3cb 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -19,6 +19,7 @@ mod fn_to_numeric_cast_any; mod fn_to_numeric_cast_with_truncation; mod manual_dangling_ptr; +mod needless_type_cast; mod ptr_as_ptr; mod ptr_cast_constness; mod ref_as_ptr; @@ -813,6 +814,32 @@ "casting a primitive method pointer to any integer type" } +declare_clippy_lint! { + /// ### What it does + /// Checks for bindings (constants, statics, or let bindings) that are defined + /// with one numeric type but are consistently cast to a different type in all usages. + /// + /// ### Why is this bad? + /// If a binding is always cast to a different type when used, it would be clearer + /// and more efficient to define it with the target type from the start. + /// + /// ### Example + /// ```no_run + /// const SIZE: u16 = 15; + /// let arr: [u8; SIZE as usize] = [0; SIZE as usize]; + /// ``` + /// + /// Use instead: + /// ```no_run + /// const SIZE: usize = 15; + /// let arr: [u8; SIZE] = [0; SIZE]; + /// ``` + #[clippy::version = "1.93.0"] + pub NEEDLESS_TYPE_CAST, + pedantic, + "binding defined with one type but always cast to another" +} + pub struct Casts { msrv: Msrv, } @@ -851,6 +878,7 @@ pub fn new(conf: &'static Conf) -> Self { AS_POINTER_UNDERSCORE, MANUAL_DANGLING_PTR, CONFUSING_METHOD_TO_NUMERIC_CAST, + NEEDLESS_TYPE_CAST, ]); impl<'tcx> LateLintPass<'tcx> for Casts { @@ -920,4 +948,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { cast_slice_different_sizes::check(cx, expr, self.msrv); ptr_cast_constness::check_null_ptr_cast_method(cx, expr); } + + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &rustc_hir::Body<'tcx>) { + needless_type_cast::check(cx, body); + } } diff --git a/clippy_lints/src/casts/needless_type_cast.rs b/clippy_lints/src/casts/needless_type_cast.rs new file mode 100644 index 000000000000..ca6aa0f87bbf --- /dev/null +++ b/clippy_lints/src/casts/needless_type_cast.rs @@ -0,0 +1,289 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::visitors::{Descend, for_each_expr, for_each_expr_without_closures}; +use core::ops::ControlFlow; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{BlockCheckMode, Body, Expr, ExprKind, HirId, LetStmt, PatKind, StmtKind, UnsafeSource}; +use rustc_lint::LateContext; +use rustc_middle::ty::{Ty, TypeVisitableExt}; +use rustc_span::Span; + +use super::NEEDLESS_TYPE_CAST; + +struct BindingInfo<'a> { + source_ty: Ty<'a>, + ty_span: Span, +} + +struct UsageInfo<'a> { + cast_to: Option>, + in_generic_context: bool, +} + +pub(super) fn check<'a>(cx: &LateContext<'a>, body: &Body<'a>) { + let mut bindings: FxHashMap> = FxHashMap::default(); + + for_each_expr_without_closures(body.value, |expr| { + match expr.kind { + ExprKind::Block(block, _) => { + for stmt in block.stmts { + if let StmtKind::Let(let_stmt) = stmt.kind { + collect_binding_from_local(cx, let_stmt, &mut bindings); + } + } + }, + ExprKind::Let(let_expr) => { + collect_binding_from_let(cx, let_expr, &mut bindings); + }, + _ => {}, + } + ControlFlow::<()>::Continue(()) + }); + + #[allow(rustc::potential_query_instability)] + let mut binding_vec: Vec<_> = bindings.into_iter().collect(); + binding_vec.sort_by_key(|(_, info)| info.ty_span.lo()); + + for (hir_id, binding_info) in binding_vec { + check_binding_usages(cx, body, hir_id, &binding_info); + } +} + +fn collect_binding_from_let<'a>( + cx: &LateContext<'a>, + let_expr: &rustc_hir::LetExpr<'a>, + bindings: &mut FxHashMap>, +) { + if let_expr.ty.is_none() + || let_expr.span.from_expansion() + || has_generic_return_type(cx, let_expr.init) + || contains_unsafe(let_expr.init) + { + return; + } + + if let PatKind::Binding(_, hir_id, _, _) = let_expr.pat.kind + && let Some(ty_hir) = let_expr.ty + { + let ty = cx.typeck_results().pat_ty(let_expr.pat); + if ty.is_numeric() { + bindings.insert( + hir_id, + BindingInfo { + source_ty: ty, + ty_span: ty_hir.span, + }, + ); + } + } +} + +fn collect_binding_from_local<'a>( + cx: &LateContext<'a>, + let_stmt: &LetStmt<'a>, + bindings: &mut FxHashMap>, +) { + if let_stmt.ty.is_none() + || let_stmt.span.from_expansion() + || let_stmt + .init + .is_some_and(|init| has_generic_return_type(cx, init) || contains_unsafe(init)) + { + return; + } + + if let PatKind::Binding(_, hir_id, _, _) = let_stmt.pat.kind + && let Some(ty_hir) = let_stmt.ty + { + let ty = cx.typeck_results().pat_ty(let_stmt.pat); + if ty.is_numeric() { + bindings.insert( + hir_id, + BindingInfo { + source_ty: ty, + ty_span: ty_hir.span, + }, + ); + } + } +} + +fn contains_unsafe(expr: &Expr<'_>) -> bool { + for_each_expr_without_closures(expr, |e| { + if let ExprKind::Block(block, _) = e.kind + && let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules + { + return ControlFlow::Break(()); + } + ControlFlow::Continue(()) + }) + .is_some() +} + +fn has_generic_return_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + match &expr.kind { + ExprKind::Block(block, _) => { + if let Some(tail_expr) = block.expr { + return has_generic_return_type(cx, tail_expr); + } + false + }, + ExprKind::If(_, then_block, else_expr) => { + has_generic_return_type(cx, then_block) || else_expr.is_some_and(|e| has_generic_return_type(cx, e)) + }, + ExprKind::Match(_, arms, _) => arms.iter().any(|arm| has_generic_return_type(cx, arm.body)), + ExprKind::Loop(block, label, ..) => for_each_expr_without_closures(*block, |e| { + match e.kind { + ExprKind::Loop(..) => { + // Unlabeled breaks inside nested loops target the inner loop, not ours + return ControlFlow::Continue(Descend::No); + }, + ExprKind::Break(dest, Some(break_expr)) => { + let targets_this_loop = + dest.label.is_none() || dest.label.map(|l| l.ident) == label.map(|l| l.ident); + if targets_this_loop && has_generic_return_type(cx, break_expr) { + return ControlFlow::Break(()); + } + }, + _ => {}, + } + ControlFlow::Continue(Descend::Yes) + }) + .is_some(), + ExprKind::MethodCall(..) => { + if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { + let sig = cx.tcx.fn_sig(def_id).instantiate_identity(); + let ret_ty = sig.output().skip_binder(); + return ret_ty.has_param(); + } + false + }, + ExprKind::Call(callee, _) => { + if let ExprKind::Path(qpath) = &callee.kind { + let res = cx.qpath_res(qpath, callee.hir_id); + if let Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) = res { + let sig = cx.tcx.fn_sig(def_id).instantiate_identity(); + let ret_ty = sig.output().skip_binder(); + return ret_ty.has_param(); + } + } + false + }, + _ => false, + } +} + +fn is_generic_res(cx: &LateContext<'_>, res: Res) -> bool { + let has_type_params = |def_id| { + cx.tcx + .generics_of(def_id) + .own_params + .iter() + .any(|p| p.kind.is_ty_or_const()) + }; + match res { + Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => has_type_params(def_id), + // Ctor → Variant → ADT: constructor's parent is variant, variant's parent is the ADT + Res::Def(DefKind::Ctor(..), def_id) => has_type_params(cx.tcx.parent(cx.tcx.parent(def_id))), + _ => false, + } +} + +fn is_cast_in_generic_context<'a>(cx: &LateContext<'a>, cast_expr: &Expr<'a>) -> bool { + let mut current_id = cast_expr.hir_id; + + loop { + let parent_id = cx.tcx.parent_hir_id(current_id); + if parent_id == current_id { + return false; + } + + let parent = cx.tcx.hir_node(parent_id); + + match parent { + rustc_hir::Node::Expr(parent_expr) => { + match &parent_expr.kind { + ExprKind::Closure(_) => return false, + ExprKind::Call(callee, _) => { + if let ExprKind::Path(qpath) = &callee.kind { + let res = cx.qpath_res(qpath, callee.hir_id); + if is_generic_res(cx, res) { + return true; + } + } + }, + ExprKind::MethodCall(..) => { + if let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent_expr.hir_id) + && cx + .tcx + .generics_of(def_id) + .own_params + .iter() + .any(|p| p.kind.is_ty_or_const()) + { + return true; + } + }, + _ => {}, + } + current_id = parent_id; + }, + _ => return false, + } + } +} + +fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId, binding_info: &BindingInfo<'a>) { + let mut usages = Vec::new(); + + for_each_expr(cx, body.value, |expr| { + if let ExprKind::Path(ref qpath) = expr.kind + && !expr.span.from_expansion() + && let Res::Local(id) = cx.qpath_res(qpath, expr.hir_id) + && id == hir_id + { + let parent_id = cx.tcx.parent_hir_id(expr.hir_id); + let parent = cx.tcx.hir_node(parent_id); + + let usage = if let rustc_hir::Node::Expr(parent_expr) = parent + && let ExprKind::Cast(..) = parent_expr.kind + && !parent_expr.span.from_expansion() + { + UsageInfo { + cast_to: Some(cx.typeck_results().expr_ty(parent_expr)), + in_generic_context: is_cast_in_generic_context(cx, parent_expr), + } + } else { + UsageInfo { + cast_to: None, + in_generic_context: false, + } + }; + usages.push(usage); + } + ControlFlow::<()>::Continue(()) + }); + + let Some(first_target) = usages + .first() + .and_then(|u| u.cast_to) + .filter(|&t| t != binding_info.source_ty) + .filter(|&t| usages.iter().all(|u| u.cast_to == Some(t) && !u.in_generic_context)) + else { + return; + }; + + span_lint_and_sugg( + cx, + NEEDLESS_TYPE_CAST, + binding_info.ty_span, + format!( + "this binding is defined as `{}` but is always cast to `{}`", + binding_info.source_ty, first_target + ), + "consider defining it as", + first_target.to_string(), + Applicability::MaybeIncorrect, + ); +} diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 1a02c2166454..87d75234ebc0 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -70,6 +70,7 @@ crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO, crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO, crate::casts::MANUAL_DANGLING_PTR_INFO, + crate::casts::NEEDLESS_TYPE_CAST_INFO, crate::casts::PTR_AS_PTR_INFO, crate::casts::PTR_CAST_CONSTNESS_INFO, crate::casts::REF_AS_PTR_INFO, diff --git a/tests/ui/needless_type_cast.fixed b/tests/ui/needless_type_cast.fixed new file mode 100644 index 000000000000..32c348d3ca3a --- /dev/null +++ b/tests/ui/needless_type_cast.fixed @@ -0,0 +1,182 @@ +#![warn(clippy::needless_type_cast)] +#![allow(clippy::no_effect, clippy::unnecessary_cast, unused)] + +fn takes_i32(x: i32) -> i32 { + x +} + +fn generic(x: T) -> T { + x +} + +fn main() { + let a: i32 = 10; + //~^ needless_type_cast + let _ = a as i32 + 5; + let _ = a as i32 * 2; + + let b: u16 = 20; + let _ = b; + let _ = b as u32; + + let c: u8 = 5; + let _ = c as u16; + let _ = c as u32; + + let d: i32 = 100; + let _ = d + 1; + + let e = 42u8; + let _ = e as i64; + let _ = e as i64 + 10; + + let f: usize = 1; + //~^ needless_type_cast + let _ = f as usize; +} + +fn test_function_call() { + let a: i32 = 10; + //~^ needless_type_cast + let _ = takes_i32(a as i32); + let _ = takes_i32(a as i32); +} + +fn test_generic_call() { + let a: u8 = 10; + let _ = generic(a as i32); + let _ = generic(a as i32); +} + +fn test_method_on_cast() { + let a: i32 = 10; + //~^ needless_type_cast + let _ = (a as i32).checked_add(5); + let _ = (a as i32).saturating_mul(2); +} + +fn test_iterator_sum() { + let a: i32 = 10; + //~^ needless_type_cast + let arr = [a as i32, a as i32]; + let _: i32 = arr.iter().copied().sum(); +} + +fn test_closure() { + let a: i32 = 10; + //~^ needless_type_cast + let _: i32 = [1i32, 2].iter().map(|x| x + a as i32).sum(); +} + +fn test_struct_field() { + struct S { + x: i32, + y: i32, + } + + let a: i32 = 10; + //~^ needless_type_cast + let _ = S { + x: a as i32, + y: a as i32, + }; +} + +fn test_option() { + let a: u8 = 10; + let _: Option = Some(a as i32); + let _: Option = Some(a as i32); +} + +fn test_mixed_context() { + let a: u8 = 10; + let _ = takes_i32(a as i32); + let _ = generic(a as i32); +} + +fn test_nested_block() { + if true { + let a: i32 = 10; + //~^ needless_type_cast + let _ = a as i32 + 1; + let _ = a as i32 * 2; + } +} + +fn test_match_expr() { + let a: i32 = 10; + //~^ needless_type_cast + let _ = match 1 { + 1 => a as i32, + _ => a as i32, + }; +} + +fn test_return_expr() -> i32 { + let a: i32 = 10; + //~^ needless_type_cast + a as i32 +} + +fn test_closure_always_cast() { + let a: i32 = 10; + //~^ needless_type_cast + let _ = [1, 2].iter().map(|_| a as i32).sum::(); + let _ = a as i32; +} + +fn test_closure_mixed_usage() { + let a: u8 = 10; + let _ = [1, 2].iter().map(|_| a as i32).sum::(); + let _ = a + 1; +} + +fn test_nested_generic_call() { + let a: u8 = 10; + let _ = generic(takes_i32(a as i32)); + let _ = generic(takes_i32(a as i32)); +} + +fn test_generic_initializer() { + // Should not lint: changing type would affect what generic() returns + let a: u8 = generic(10u8); + let _ = a as i32; + let _ = a as i32; +} + +fn test_unsafe_transmute() { + // Should not lint: initializer contains unsafe block + #[allow(clippy::useless_transmute)] + let x: u32 = unsafe { std::mem::transmute(0u32) }; + let _ = x as u64; +} + +fn test_if_with_generic() { + // Should not lint: one branch has generic return type + let x: u8 = if true { generic(1) } else { 2 }; + let _ = x as i32; +} + +fn test_match_with_generic() { + // Should not lint: one branch has generic return type + let x: u8 = match 1 { + 1 => generic(1), + _ => 2, + }; + let _ = x as i32; +} + +fn test_default() { + // Should not lint: Default::default() has generic return type + let x: u8 = Default::default(); + let _ = x as i32; +} + +fn test_loop_with_generic() { + // Should not lint: loop break has generic return type + #[allow(clippy::never_loop)] + let x: u8 = loop { + break generic(1); + }; + let _ = x as i32; +} diff --git a/tests/ui/needless_type_cast.rs b/tests/ui/needless_type_cast.rs new file mode 100644 index 000000000000..e28f620e035f --- /dev/null +++ b/tests/ui/needless_type_cast.rs @@ -0,0 +1,182 @@ +#![warn(clippy::needless_type_cast)] +#![allow(clippy::no_effect, clippy::unnecessary_cast, unused)] + +fn takes_i32(x: i32) -> i32 { + x +} + +fn generic(x: T) -> T { + x +} + +fn main() { + let a: u8 = 10; + //~^ needless_type_cast + let _ = a as i32 + 5; + let _ = a as i32 * 2; + + let b: u16 = 20; + let _ = b; + let _ = b as u32; + + let c: u8 = 5; + let _ = c as u16; + let _ = c as u32; + + let d: i32 = 100; + let _ = d + 1; + + let e = 42u8; + let _ = e as i64; + let _ = e as i64 + 10; + + let f: u8 = 1; + //~^ needless_type_cast + let _ = f as usize; +} + +fn test_function_call() { + let a: u8 = 10; + //~^ needless_type_cast + let _ = takes_i32(a as i32); + let _ = takes_i32(a as i32); +} + +fn test_generic_call() { + let a: u8 = 10; + let _ = generic(a as i32); + let _ = generic(a as i32); +} + +fn test_method_on_cast() { + let a: u8 = 10; + //~^ needless_type_cast + let _ = (a as i32).checked_add(5); + let _ = (a as i32).saturating_mul(2); +} + +fn test_iterator_sum() { + let a: u8 = 10; + //~^ needless_type_cast + let arr = [a as i32, a as i32]; + let _: i32 = arr.iter().copied().sum(); +} + +fn test_closure() { + let a: u8 = 10; + //~^ needless_type_cast + let _: i32 = [1i32, 2].iter().map(|x| x + a as i32).sum(); +} + +fn test_struct_field() { + struct S { + x: i32, + y: i32, + } + + let a: u8 = 10; + //~^ needless_type_cast + let _ = S { + x: a as i32, + y: a as i32, + }; +} + +fn test_option() { + let a: u8 = 10; + let _: Option = Some(a as i32); + let _: Option = Some(a as i32); +} + +fn test_mixed_context() { + let a: u8 = 10; + let _ = takes_i32(a as i32); + let _ = generic(a as i32); +} + +fn test_nested_block() { + if true { + let a: u8 = 10; + //~^ needless_type_cast + let _ = a as i32 + 1; + let _ = a as i32 * 2; + } +} + +fn test_match_expr() { + let a: u8 = 10; + //~^ needless_type_cast + let _ = match 1 { + 1 => a as i32, + _ => a as i32, + }; +} + +fn test_return_expr() -> i32 { + let a: u8 = 10; + //~^ needless_type_cast + a as i32 +} + +fn test_closure_always_cast() { + let a: u8 = 10; + //~^ needless_type_cast + let _ = [1, 2].iter().map(|_| a as i32).sum::(); + let _ = a as i32; +} + +fn test_closure_mixed_usage() { + let a: u8 = 10; + let _ = [1, 2].iter().map(|_| a as i32).sum::(); + let _ = a + 1; +} + +fn test_nested_generic_call() { + let a: u8 = 10; + let _ = generic(takes_i32(a as i32)); + let _ = generic(takes_i32(a as i32)); +} + +fn test_generic_initializer() { + // Should not lint: changing type would affect what generic() returns + let a: u8 = generic(10u8); + let _ = a as i32; + let _ = a as i32; +} + +fn test_unsafe_transmute() { + // Should not lint: initializer contains unsafe block + #[allow(clippy::useless_transmute)] + let x: u32 = unsafe { std::mem::transmute(0u32) }; + let _ = x as u64; +} + +fn test_if_with_generic() { + // Should not lint: one branch has generic return type + let x: u8 = if true { generic(1) } else { 2 }; + let _ = x as i32; +} + +fn test_match_with_generic() { + // Should not lint: one branch has generic return type + let x: u8 = match 1 { + 1 => generic(1), + _ => 2, + }; + let _ = x as i32; +} + +fn test_default() { + // Should not lint: Default::default() has generic return type + let x: u8 = Default::default(); + let _ = x as i32; +} + +fn test_loop_with_generic() { + // Should not lint: loop break has generic return type + #[allow(clippy::never_loop)] + let x: u8 = loop { + break generic(1); + }; + let _ = x as i32; +} diff --git a/tests/ui/needless_type_cast.stderr b/tests/ui/needless_type_cast.stderr new file mode 100644 index 000000000000..3ee9df1043e7 --- /dev/null +++ b/tests/ui/needless_type_cast.stderr @@ -0,0 +1,71 @@ +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:13:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + | + = note: `-D clippy::needless-type-cast` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_type_cast)]` + +error: this binding is defined as `u8` but is always cast to `usize` + --> tests/ui/needless_type_cast.rs:33:12 + | +LL | let f: u8 = 1; + | ^^ help: consider defining it as: `usize` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:39:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:52:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:59:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:66:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:77:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:99:16 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:107:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:116:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:122:12 + | +LL | let a: u8 = 10; + | ^^ help: consider defining it as: `i32` + +error: aborting due to 11 previous errors + From a3b78e0320f9bdabb294cbef573d4fe0ddec771f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 23 Sep 2025 21:16:00 +0200 Subject: [PATCH 439/585] add `core::hint::prefetch_{read, write}_{data, instruction}` well, we don't expose `prefetch_write_instruction`, that one doesn't really make sense in practice. --- library/core/src/hint.rs | 112 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 71acede7e3eb..7a2752219eb5 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -823,3 +823,115 @@ fn drop(&mut self) { crate::intrinsics::select_unpredictable(condition, true_val, false_val).assume_init() } } + +/// The expected temporal locality of a memory prefetch operation. +/// +/// Locality expresses how likely the prefetched data is to be reused soon, +/// and therefore which level of cache it should be brought into. +/// +/// The locality is just a hint, and may be ignored on some targets or by the hardware. +/// +/// Used with functions like [`prefetch_read_data`] and [`prefetch_write_data`]. +/// +/// [`prefetch_read_data`]: crate::hint::prefetch_read_data +/// [`prefetch_write_data`]: crate::hint::prefetch_write_data +#[unstable(feature = "hint_prefetch", issue = "146941")] +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Locality { + /// Data is unlikely to be reused soon. + /// + /// Typically bypasses the caches so they are not polluted. + NonTemporal = 0, + /// Data is expected to be reused eventually. + /// + /// Typically prefetches into L3 cache (if the CPU supports it). + L3 = 1, + /// Data is expected to be reused in the near future. + /// + /// Typically prefetches into L2 cache. + L2 = 2, + /// Data is expected to be reused very soon. + /// + /// Typically prefetches into L1 cache. + L1 = 3, +} + +/// Prefetch the cache line containing `ptr` for a future read. +/// +/// A strategically placed prefetch can reduce cache miss latency if the data is accessed +/// soon after, but may also increase bandwidth usage or evict other cache lines. +/// +/// A prefetch is a *hint*, and may be ignored on certain targets or by the hardware. +/// +/// Passing a dangling or invalid pointer is permitted: the memory will not +/// actually be dereferenced, and no faults are raised. +/// +/// # Examples +/// +/// ``` +/// use std::hint::{Locality, prefetch_read_data}; +/// use std::mem::size_of_val; +/// +/// // Prefetch all of `slice` into the L1 cache. +/// fn prefetch_slice(slice: &[T]) { +/// // On most systems the cache line size is 64 bytes. +/// for offset in (0..size_of_val(slice)).step_by(64) { +/// prefetch_read_data(slice.as_ptr().wrapping_add(offset), Locality::L1); +/// } +/// } +/// ``` +#[inline(always)] +#[unstable(feature = "hint_prefetch", issue = "146941")] +pub const fn prefetch_read_data(ptr: *const T, locality: Locality) { + match locality { + Locality::NonTemporal => { + intrinsics::prefetch_read_data::(ptr) + } + Locality::L3 => intrinsics::prefetch_read_data::(ptr), + Locality::L2 => intrinsics::prefetch_read_data::(ptr), + Locality::L1 => intrinsics::prefetch_read_data::(ptr), + } +} + +/// Prefetch the cache line containing `ptr` for a future write. +/// +/// A strategically placed prefetch can reduce cache miss latency if the data is accessed +/// soon after, but may also increase bandwidth usage or evict other cache lines. +/// +/// A prefetch is a *hint*, and may be ignored on certain targets or by the hardware. +/// +/// Passing a dangling or invalid pointer is permitted: the memory will not +/// actually be dereferenced, and no faults are raised. +#[unstable(feature = "hint_prefetch", issue = "146941")] +pub const fn prefetch_write_data(ptr: *mut T, locality: Locality) { + match locality { + Locality::NonTemporal => { + intrinsics::prefetch_write_data::(ptr) + } + Locality::L3 => intrinsics::prefetch_write_data::(ptr), + Locality::L2 => intrinsics::prefetch_write_data::(ptr), + Locality::L1 => intrinsics::prefetch_write_data::(ptr), + } +} + +/// Prefetch the cache line containing `ptr` for a future read. +/// +/// A strategically placed prefetch can reduce cache miss latency if the instructions are +/// accessed soon after, but may also increase bandwidth usage or evict other cache lines. +/// +/// A prefetch is a *hint*, and may be ignored on certain targets or by the hardware. +/// +/// Passing a dangling or invalid pointer is permitted: the memory will not +/// actually be dereferenced, and no faults are raised. +#[unstable(feature = "hint_prefetch", issue = "146941")] +pub const fn prefetch_read_instruction(ptr: *const T, locality: Locality) { + match locality { + Locality::NonTemporal => { + intrinsics::prefetch_read_instruction::(ptr) + } + Locality::L3 => intrinsics::prefetch_read_instruction::(ptr), + Locality::L2 => intrinsics::prefetch_read_instruction::(ptr), + Locality::L1 => intrinsics::prefetch_read_instruction::(ptr), + } +} From 6407023007a69d4afd31b2ceff98e375bc5af43f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 25 Sep 2025 20:40:23 +0200 Subject: [PATCH 440/585] Add a separate function for a non-temporal read prefetch --- library/core/src/hint.rs | 68 +++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 7a2752219eb5..57fdb245c6a2 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -831,18 +831,14 @@ fn drop(&mut self) { /// /// The locality is just a hint, and may be ignored on some targets or by the hardware. /// -/// Used with functions like [`prefetch_read_data`] and [`prefetch_write_data`]. +/// Used with functions like [`prefetch_read`] and [`prefetch_write`]. /// -/// [`prefetch_read_data`]: crate::hint::prefetch_read_data -/// [`prefetch_write_data`]: crate::hint::prefetch_write_data +/// [`prefetch_read`]: crate::hint::prefetch_read +/// [`prefetch_write`]: crate::hint::prefetch_write #[unstable(feature = "hint_prefetch", issue = "146941")] #[non_exhaustive] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Locality { - /// Data is unlikely to be reused soon. - /// - /// Typically bypasses the caches so they are not polluted. - NonTemporal = 0, /// Data is expected to be reused eventually. /// /// Typically prefetches into L3 cache (if the CPU supports it). @@ -870,30 +866,46 @@ pub enum Locality { /// # Examples /// /// ``` -/// use std::hint::{Locality, prefetch_read_data}; +/// #![feature(hint_prefetch)] +/// use std::hint::{Locality, prefetch_read}; /// use std::mem::size_of_val; /// /// // Prefetch all of `slice` into the L1 cache. /// fn prefetch_slice(slice: &[T]) { /// // On most systems the cache line size is 64 bytes. /// for offset in (0..size_of_val(slice)).step_by(64) { -/// prefetch_read_data(slice.as_ptr().wrapping_add(offset), Locality::L1); +/// prefetch_read(slice.as_ptr().wrapping_add(offset), Locality::L1); /// } /// } /// ``` #[inline(always)] #[unstable(feature = "hint_prefetch", issue = "146941")] -pub const fn prefetch_read_data(ptr: *const T, locality: Locality) { +pub const fn prefetch_read(ptr: *const T, locality: Locality) { match locality { - Locality::NonTemporal => { - intrinsics::prefetch_read_data::(ptr) - } Locality::L3 => intrinsics::prefetch_read_data::(ptr), Locality::L2 => intrinsics::prefetch_read_data::(ptr), Locality::L1 => intrinsics::prefetch_read_data::(ptr), } } +/// Prefetch the cache line containing `ptr` for a single future read, but attempt to avoid +/// polluting the cache. +/// +/// A strategically placed prefetch can reduce cache miss latency if the data is accessed +/// soon after, but may also increase bandwidth usage or evict other cache lines. +/// +/// A prefetch is a *hint*, and may be ignored on certain targets or by the hardware. +/// +/// Passing a dangling or invalid pointer is permitted: the memory will not +/// actually be dereferenced, and no faults are raised. +#[inline(always)] +#[unstable(feature = "hint_prefetch", issue = "146941")] +pub const fn prefetch_read_non_temporal(ptr: *const T, locality: Locality) { + // The LLVM intrinsic does not currently support specifying the locality. + let _ = locality; + intrinsics::prefetch_read_data::(ptr) +} + /// Prefetch the cache line containing `ptr` for a future write. /// /// A strategically placed prefetch can reduce cache miss latency if the data is accessed @@ -903,19 +915,35 @@ pub const fn prefetch_read_data(ptr: *const T, locality: Locality) { /// /// Passing a dangling or invalid pointer is permitted: the memory will not /// actually be dereferenced, and no faults are raised. +#[inline(always)] #[unstable(feature = "hint_prefetch", issue = "146941")] -pub const fn prefetch_write_data(ptr: *mut T, locality: Locality) { +pub const fn prefetch_write(ptr: *mut T, locality: Locality) { match locality { - Locality::NonTemporal => { - intrinsics::prefetch_write_data::(ptr) - } Locality::L3 => intrinsics::prefetch_write_data::(ptr), Locality::L2 => intrinsics::prefetch_write_data::(ptr), Locality::L1 => intrinsics::prefetch_write_data::(ptr), } } -/// Prefetch the cache line containing `ptr` for a future read. +/// Prefetch the cache line containing `ptr` for a single future write, but attempt to avoid +/// polluting the cache. +/// +/// A strategically placed prefetch can reduce cache miss latency if the data is accessed +/// soon after, but may also increase bandwidth usage or evict other cache lines. +/// +/// A prefetch is a *hint*, and may be ignored on certain targets or by the hardware. +/// +/// Passing a dangling or invalid pointer is permitted: the memory will not +/// actually be dereferenced, and no faults are raised. +#[inline(always)] +#[unstable(feature = "hint_prefetch", issue = "146941")] +pub const fn prefetch_write_non_temporal(ptr: *const T, locality: Locality) { + // The LLVM intrinsic does not currently support specifying the locality. + let _ = locality; + intrinsics::prefetch_write_data::(ptr) +} + +/// Prefetch the cache line containing `ptr` into the instruction cache for a future read. /// /// A strategically placed prefetch can reduce cache miss latency if the instructions are /// accessed soon after, but may also increase bandwidth usage or evict other cache lines. @@ -924,12 +952,10 @@ pub const fn prefetch_write_data(ptr: *mut T, locality: Locality) { /// /// Passing a dangling or invalid pointer is permitted: the memory will not /// actually be dereferenced, and no faults are raised. +#[inline(always)] #[unstable(feature = "hint_prefetch", issue = "146941")] pub const fn prefetch_read_instruction(ptr: *const T, locality: Locality) { match locality { - Locality::NonTemporal => { - intrinsics::prefetch_read_instruction::(ptr) - } Locality::L3 => intrinsics::prefetch_read_instruction::(ptr), Locality::L2 => intrinsics::prefetch_read_instruction::(ptr), Locality::L1 => intrinsics::prefetch_read_instruction::(ptr), From b9e3e4162a66c6b520fa8c3bba6b9d33663c91e7 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 10 Dec 2025 00:17:57 +0100 Subject: [PATCH 441/585] remove explicit discriminants --- library/core/src/hint.rs | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 57fdb245c6a2..e2ac746d3149 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -842,15 +842,26 @@ pub enum Locality { /// Data is expected to be reused eventually. /// /// Typically prefetches into L3 cache (if the CPU supports it). - L3 = 1, + L3, /// Data is expected to be reused in the near future. /// /// Typically prefetches into L2 cache. - L2 = 2, + L2, /// Data is expected to be reused very soon. /// /// Typically prefetches into L1 cache. - L1 = 3, + L1, +} + +impl Locality { + /// Convert to the constant that LLVM associates with a locality. + const fn to_llvm(self) -> i32 { + match self { + Self::L3 => 1, + Self::L2 => 2, + Self::L1 => 3, + } + } } /// Prefetch the cache line containing `ptr` for a future read. @@ -882,9 +893,9 @@ pub enum Locality { #[unstable(feature = "hint_prefetch", issue = "146941")] pub const fn prefetch_read(ptr: *const T, locality: Locality) { match locality { - Locality::L3 => intrinsics::prefetch_read_data::(ptr), - Locality::L2 => intrinsics::prefetch_read_data::(ptr), - Locality::L1 => intrinsics::prefetch_read_data::(ptr), + Locality::L3 => intrinsics::prefetch_read_data::(ptr), + Locality::L2 => intrinsics::prefetch_read_data::(ptr), + Locality::L1 => intrinsics::prefetch_read_data::(ptr), } } @@ -919,9 +930,9 @@ pub const fn prefetch_read_non_temporal(ptr: *const T, locality: Locality) { #[unstable(feature = "hint_prefetch", issue = "146941")] pub const fn prefetch_write(ptr: *mut T, locality: Locality) { match locality { - Locality::L3 => intrinsics::prefetch_write_data::(ptr), - Locality::L2 => intrinsics::prefetch_write_data::(ptr), - Locality::L1 => intrinsics::prefetch_write_data::(ptr), + Locality::L3 => intrinsics::prefetch_write_data::(ptr), + Locality::L2 => intrinsics::prefetch_write_data::(ptr), + Locality::L1 => intrinsics::prefetch_write_data::(ptr), } } @@ -956,8 +967,8 @@ pub const fn prefetch_write_non_temporal(ptr: *const T, locality: Locality) { #[unstable(feature = "hint_prefetch", issue = "146941")] pub const fn prefetch_read_instruction(ptr: *const T, locality: Locality) { match locality { - Locality::L3 => intrinsics::prefetch_read_instruction::(ptr), - Locality::L2 => intrinsics::prefetch_read_instruction::(ptr), - Locality::L1 => intrinsics::prefetch_read_instruction::(ptr), + Locality::L3 => intrinsics::prefetch_read_instruction::(ptr), + Locality::L2 => intrinsics::prefetch_read_instruction::(ptr), + Locality::L1 => intrinsics::prefetch_read_instruction::(ptr), } } From 0488690d3e248a72a98945fbd4ced83a5ba05d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Dec 2025 00:10:08 +0000 Subject: [PATCH 442/585] Use `let`...`else` instead of `match foo { ... _ => return };` and `if let ... else return` in std --- library/alloc/src/collections/linked_list.rs | 5 ++--- library/alloc/src/raw_vec/mod.rs | 4 +--- library/alloc/src/string.rs | 21 +++++++++----------- library/alloc/src/vec/splice.rs | 9 ++++----- library/core/src/num/dec2flt/mod.rs | 6 +----- library/core/src/time.rs | 7 +++---- library/std/src/sys/pal/windows/pipe.rs | 5 +---- 7 files changed, 21 insertions(+), 36 deletions(-) diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 8bc0e08a4b26..e738c29c237f 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1646,9 +1646,8 @@ impl<'a, T> CursorMut<'a, T> { #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn splice_after(&mut self, list: LinkedList) { unsafe { - let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() { - Some(parts) => parts, - _ => return, + let Some((splice_head, splice_tail, splice_len)) = list.detach_all_nodes() else { + return; }; let node_next = match self.current { None => self.list.head, diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 236e33e2f450..15b0823df9ec 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -788,9 +788,7 @@ unsafe fn shrink_unchecked( elem_layout: Layout, ) -> Result<(), TryReserveError> { // SAFETY: Precondition passed to caller - let (ptr, layout) = if let Some(mem) = unsafe { self.current_memory(elem_layout) } { - mem - } else { + let Some((ptr, layout)) = (unsafe { self.current_memory(elem_layout) }) else { return Ok(()); }; diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index f5ba71c28833..64abdca32d21 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -619,16 +619,14 @@ pub fn from_utf8(vec: Vec) -> Result { pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> { let mut iter = v.utf8_chunks(); - let first_valid = if let Some(chunk) = iter.next() { - let valid = chunk.valid(); - if chunk.invalid().is_empty() { - debug_assert_eq!(valid.len(), v.len()); - return Cow::Borrowed(valid); - } - valid - } else { + let Some(chunk) = iter.next() else { return Cow::Borrowed(""); }; + let first_valid = chunk.valid(); + if chunk.invalid().is_empty() { + debug_assert_eq!(first_valid.len(), v.len()); + return Cow::Borrowed(first_valid); + } const REPLACEMENT: &str = "\u{FFFD}"; @@ -720,11 +718,10 @@ pub fn from_utf16(v: &[u16]) -> Result { // FIXME: the function can be simplified again when #48994 is closed. let mut ret = String::with_capacity(v.len()); for c in char::decode_utf16(v.iter().cloned()) { - if let Ok(c) = c { - ret.push(c); - } else { + let Ok(c) = c else { return Err(FromUtf16Error(())); - } + }; + ret.push(c); } Ok(ret) } diff --git a/library/alloc/src/vec/splice.rs b/library/alloc/src/vec/splice.rs index d571e35828ae..b08bb9cb6d19 100644 --- a/library/alloc/src/vec/splice.rs +++ b/library/alloc/src/vec/splice.rs @@ -112,12 +112,11 @@ unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { }; for place in range_slice { - if let Some(new_item) = replace_with.next() { - unsafe { ptr::write(place, new_item) }; - vec.len += 1; - } else { + let Some(new_item) = replace_with.next() else { return false; - } + }; + unsafe { ptr::write(place, new_item) }; + vec.len += 1; } true } diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index dd4eccd24de0..eee8adf4f755 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -255,11 +255,7 @@ fn biased_fp_to_float(x: BiasedFp) -> F { #[inline(always)] // Will be inlined into a function with `#[inline(never)]`, see above pub fn dec2flt(s: &str) -> Result { let mut s = s.as_bytes(); - let c = if let Some(&c) = s.first() { - c - } else { - return Err(pfe_empty()); - }; + let Some(&c) = s.first() else { return Err(pfe_empty()) }; let negative = c == b'-'; if c == b'-' || c == b'+' { s = &s[1..]; diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 51a01545f5cf..b85179e925d1 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -672,11 +672,10 @@ pub const fn checked_add(self, rhs: Duration) -> Option { let mut nanos = self.nanos.as_inner() + rhs.nanos.as_inner(); if nanos >= NANOS_PER_SEC { nanos -= NANOS_PER_SEC; - if let Some(new_secs) = secs.checked_add(1) { - secs = new_secs; - } else { + let Some(new_secs) = secs.checked_add(1) else { return None; - } + }; + secs = new_secs; } debug_assert!(nanos < NANOS_PER_SEC); Some(Duration::new(secs, nanos)) diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index d8e306068d73..32cf4695d4a1 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -530,10 +530,7 @@ fn finish(&mut self) -> io::Result<()> { impl<'a> Drop for AsyncPipe<'a> { fn drop(&mut self) { - match self.state { - State::Reading => {} - _ => return, - } + let State::Reading = self.state else { return }; // If we have a pending read operation, then we have to make sure that // it's *done* before we actually drop this type. The kernel requires From d440210f9a47572842ae6781303336ad4fe0f268 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Wed, 10 Dec 2025 08:58:34 +0900 Subject: [PATCH 443/585] Add a regression test for issue 145748 --- .../normalize/normalize-const-in-async-body.rs | 2 ++ .../non-defining-use-borrowck-issue-145748.rs | 14 ++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/ui/traits/next-solver/opaques/non-defining-use-borrowck-issue-145748.rs diff --git a/tests/ui/traits/next-solver/normalize/normalize-const-in-async-body.rs b/tests/ui/traits/next-solver/normalize/normalize-const-in-async-body.rs index 2b9454db3fac..4da078dbb4f4 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-const-in-async-body.rs +++ b/tests/ui/traits/next-solver/normalize/normalize-const-in-async-body.rs @@ -2,6 +2,8 @@ //@ check-pass //@ edition:2021 +// Regression test for https://github.com/rust-lang/rust/issues/129865. + pub async fn cleanse_old_array_async(_: &[u8; BUCKET_LEN]) {} pub const BUCKET_LEN: usize = 0; diff --git a/tests/ui/traits/next-solver/opaques/non-defining-use-borrowck-issue-145748.rs b/tests/ui/traits/next-solver/opaques/non-defining-use-borrowck-issue-145748.rs new file mode 100644 index 000000000000..ae70ffdfdaee --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/non-defining-use-borrowck-issue-145748.rs @@ -0,0 +1,14 @@ +//@ ignore-compare-mode-next-solver +//@ compile-flags: -Znext-solver +//@ check-pass + +// Make sure that we support non-defining uses in borrowck. +// Regression test for https://github.com/rust-lang/rust/issues/145748. + +pub fn f(_: &()) -> impl Fn() + '_ { + || { + let _ = f(&()); + } +} + +fn main() {} From fc3d61ee7c221f38eec38166f9a9f5f0e0bd3a7e Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 10 Dec 2025 09:35:24 +0800 Subject: [PATCH 444/585] compiletest: tidy up `adb_path`/`adb_test_dir` handling Be more faithful that they aren't always available. --- src/tools/compiletest/src/common.rs | 4 ++-- src/tools/compiletest/src/lib.rs | 8 +++----- src/tools/compiletest/src/runtest/debuginfo.rs | 12 ++++++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 02b93593cbbd..34153d93d463 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -575,7 +575,7 @@ pub struct Config { /// /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for /// `arm-linux-androideabi` target. - pub adb_path: Utf8PathBuf, + pub adb_path: Option, /// Extra parameter to run test suite on `arm-linux-androideabi`. /// @@ -584,7 +584,7 @@ pub struct Config { /// /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for /// `arm-linux-androideabi` target. - pub adb_test_dir: Utf8PathBuf, + pub adb_test_dir: Option, /// Status whether android device available or not. When unavailable, this will cause tests to /// panic when the test binary is attempted to be run. diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index ff4cd81d33ff..324ce2eaabee 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -260,11 +260,9 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { let android_cross_path = matches.opt_str("android-cross-path").map(Utf8PathBuf::from); - // FIXME: `adb_path` should be an `Option`... - let adb_path = matches.opt_str("adb-path").map(Utf8PathBuf::from).unwrap_or_default(); - // FIXME: `adb_test_dir` should be an `Option`... - let adb_test_dir = matches.opt_str("adb-test-dir").map(Utf8PathBuf::from).unwrap_or_default(); - let adb_device_status = target.contains("android") && !adb_test_dir.as_str().is_empty(); + let adb_path = matches.opt_str("adb-path").map(Utf8PathBuf::from); + let adb_test_dir = matches.opt_str("adb-test-dir").map(Utf8PathBuf::from); + let adb_device_status = target.contains("android") && adb_test_dir.is_some(); // FIXME: `cdb_version` is *derived* from cdb, but it's *not* technically a config! let cdb = debuggers::discover_cdb(matches.opt_str("cdb"), &target); diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index ac935910205b..83b61b9be57d 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -150,12 +150,16 @@ fn run_debuginfo_gdb_test(&self) { debug!("script_str = {}", script_str); self.dump_output_file(&script_str, "debugger.script"); - let adb_path = &self.config.adb_path; + // Note: when `--android-cross-path` is specified, we expect both `adb_path` and + // `adb_test_dir` to be available. + let adb_path = self.config.adb_path.as_ref().expect("`adb_path` must be specified"); + let adb_test_dir = + self.config.adb_test_dir.as_ref().expect("`adb_test_dir` must be specified"); Command::new(adb_path) .arg("push") .arg(&exe_file) - .arg(&self.config.adb_test_dir) + .arg(adb_test_dir) .status() .unwrap_or_else(|e| panic!("failed to exec `{adb_path:?}`: {e:?}")); @@ -167,9 +171,9 @@ fn run_debuginfo_gdb_test(&self) { let adb_arg = format!( "export LD_LIBRARY_PATH={}; \ gdbserver{} :5039 {}/{}", - self.config.adb_test_dir.clone(), + adb_test_dir, if self.config.target.contains("aarch64") { "64" } else { "" }, - self.config.adb_test_dir.clone(), + adb_test_dir, exe_file.file_name().unwrap() ); From 4033d19b79244b347a87f3c58d0ad01962935360 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 30 Nov 2025 14:46:36 -0800 Subject: [PATCH 445/585] Experimentally add *heterogeneous* `try` blocks 148725 moved the default to being homogeneous; this adds heterogeneous ones back under an obvious-bikeshed syntax so people can experiment with that as well. Essentially resolves 149025 by letting them move to this syntax instead. --- compiler/rustc_ast/src/ast.rs | 10 ++- compiler/rustc_ast/src/visit.rs | 4 +- compiler/rustc_ast_lowering/src/expr.rs | 74 +++++++++++++------ compiler/rustc_ast_lowering/src/lib.rs | 21 +++++- compiler/rustc_ast_passes/src/feature_gate.rs | 10 ++- .../rustc_ast_pretty/src/pprust/state/expr.rs | 7 +- .../src/assert/context.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_parse/src/parser/expr.rs | 19 +++-- compiler/rustc_parse/src/parser/token_type.rs | 2 + compiler/rustc_span/src/symbol.rs | 2 + tests/pretty/try-blocks.rs | 6 ++ .../feature-gate-try_blocks_heterogeneous.rs | 9 +++ ...ature-gate-try_blocks_heterogeneous.stderr | 17 +++++ .../try-block-bad-type-heterogeneous.rs | 21 ++++++ .../try-block-bad-type-heterogeneous.stderr | 46 ++++++++++++ tests/ui/try-block/try-block-heterogeneous.rs | 19 +++++ tests/ui/unpretty/exhaustive.expanded.stdout | 8 +- tests/ui/unpretty/exhaustive.hir.stderr | 40 +++++----- tests/ui/unpretty/exhaustive.hir.stdout | 15 +++- tests/ui/unpretty/exhaustive.rs | 3 + 21 files changed, 278 insertions(+), 59 deletions(-) create mode 100644 tests/pretty/try-blocks.rs create mode 100644 tests/ui/feature-gates/feature-gate-try_blocks_heterogeneous.rs create mode 100644 tests/ui/feature-gates/feature-gate-try_blocks_heterogeneous.stderr create mode 100644 tests/ui/try-block/try-block-bad-type-heterogeneous.rs create mode 100644 tests/ui/try-block/try-block-bad-type-heterogeneous.stderr create mode 100644 tests/ui/try-block/try-block-heterogeneous.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index db7cace49ae8..09dd5c389632 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1806,8 +1806,14 @@ pub enum ExprKind { /// A use expression (`x.use`). Span is of use keyword. Use(Box, Span), - /// A try block (`try { ... }`). - TryBlock(Box), + /// A try block (`try { ... }`), if the type is `None`, or + /// A try block (`try bikeshed Ty { ... }`) if the type is `Some`. + /// + /// Note that `try bikeshed` is a *deliberately ridiculous* placeholder + /// syntax to avoid deciding what keyword or symbol should go there. + /// It's that way for experimentation only; an RFC to decide the final + /// semantics and syntax would be needed to put it on stabilization-track. + TryBlock(Box, Option>), /// An assignment (`a = foo()`). /// The `Span` argument is the span of the `=` token. diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index dde773fd147d..7a0424d39575 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1048,8 +1048,8 @@ pub fn walk_fn<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, kind: FnKind<$($lt)? visit_visitable!($($mut)? vis, kind), ExprKind::Try(subexpression) => visit_visitable!($($mut)? vis, subexpression), - ExprKind::TryBlock(body) => - visit_visitable!($($mut)? vis, body), + ExprKind::TryBlock(body, optional_type) => + visit_visitable!($($mut)? vis, body, optional_type), ExprKind::Lit(token) => visit_visitable!($($mut)? vis, token), ExprKind::IncludedBytes(bytes) => diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 524f8b054cb4..7230e1c42474 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,3 +1,4 @@ +use std::mem; use std::ops::ControlFlow; use std::sync::Arc; @@ -27,7 +28,9 @@ GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt, }; use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure}; -use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, fluent_generated}; +use crate::{ + AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, TryBlockScope, fluent_generated, +}; struct WillCreateDefIdsVisitor {} @@ -199,7 +202,9 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { ) }) } - ExprKind::TryBlock(body) => self.lower_expr_try_block(body), + ExprKind::TryBlock(body, opt_ty) => { + self.lower_expr_try_block(body, opt_ty.as_deref()) + } ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match( self.lower_expr(expr), self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))), @@ -562,9 +567,14 @@ fn lower_expr_while_in_loop_scope( /// Desugar `try { ; }` into `{ ; ::std::ops::Try::from_output() }`, /// `try { ; }` into `{ ; ::std::ops::Try::from_output(()) }` /// and save the block id to use it as a break target for desugaring of the `?` operator. - fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> { + fn lower_expr_try_block(&mut self, body: &Block, opt_ty: Option<&Ty>) -> hir::ExprKind<'hir> { let body_hir_id = self.lower_node_id(body.id); - self.with_catch_scope(body_hir_id, |this| { + let new_scope = if opt_ty.is_some() { + TryBlockScope::Heterogeneous(body_hir_id) + } else { + TryBlockScope::Homogeneous(body_hir_id) + }; + let whole_block = self.with_try_block_scope(new_scope, |this| { let mut block = this.lower_block_noalloc(body_hir_id, body, true); // Final expression of the block (if present) or `()` with span at the end of block @@ -598,8 +608,16 @@ fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> { ok_wrapped_span, )); - hir::ExprKind::Block(this.arena.alloc(block), None) - }) + this.arena.alloc(block) + }); + + if let Some(ty) = opt_ty { + let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)); + let block_expr = self.arena.alloc(self.expr_block(whole_block)); + hir::ExprKind::Type(block_expr, ty) + } else { + hir::ExprKind::Block(whole_block, None) + } } fn wrap_in_try_constructor( @@ -1617,10 +1635,14 @@ fn lower_jump_destination(&mut self, id: NodeId, opt_label: Option::with_capacity(if doc_only { 0 } else { size_hint }); for (attr, item_id) in attrs { - if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() { - let doc = beautify_doc_string(doc_str, comment_kind); - let (span, kind, from_expansion) = if let Some(span) = attr.is_doc_comment() { - (span, DocFragmentKind::SugaredDoc, span.from_expansion()) - } else { - let attr_span = attr.span(); - let (span, from_expansion) = match attr.value_span() { - Some(sp) => (sp.with_ctxt(attr_span.ctxt()), sp.from_expansion()), - None => (attr_span, attr_span.from_expansion()), - }; - (span, DocFragmentKind::RawDoc, from_expansion) + if let Some((doc_str, fragment_kind)) = attr.doc_str_and_fragment_kind() { + let doc = beautify_doc_string(doc_str, fragment_kind.comment_kind()); + let attr_span = attr.span(); + let (span, from_expansion) = match fragment_kind { + DocFragmentKind::Sugared(_) => (attr_span, attr_span.from_expansion()), + DocFragmentKind::Raw(value_span) => { + (value_span.with_ctxt(attr_span.ctxt()), value_span.from_expansion()) + } }; - let fragment = DocFragment { span, doc, kind, item_id, indent: 0, from_expansion }; + let fragment = + DocFragment { span, doc, kind: fragment_kind, item_id, indent: 0, from_expansion }; doc_fragments.push(fragment); } else if !doc_only { other_attrs.push(attr.clone()); @@ -571,7 +561,7 @@ pub fn source_span_for_markdown_range_inner( use rustc_span::BytePos; if let &[fragment] = &fragments - && fragment.kind == DocFragmentKind::RawDoc + && !fragment.kind.is_sugared() && let Ok(snippet) = map.span_to_snippet(fragment.span) && snippet.trim_end() == markdown.trim_end() && let Ok(md_range_lo) = u32::try_from(md_range.start) @@ -589,7 +579,7 @@ pub fn source_span_for_markdown_range_inner( )); } - let is_all_sugared_doc = fragments.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc); + let is_all_sugared_doc = fragments.iter().all(|frag| frag.kind.is_sugared()); if !is_all_sugared_doc { // This case ignores the markdown outside of the range so that it can diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 12dcb198bd21..40191d5c98e0 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2403,7 +2403,7 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(Crate, 16); // frequently moved by-value - static_assert_size!(DocFragment, 32); + static_assert_size!(DocFragment, 48); static_assert_size!(GenericArg, 32); static_assert_size!(GenericArgs, 24); static_assert_size!(GenericParamDef, 40); From 92edc499a69a24e69e6fcc2641dc9bca1098bd5b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 28 Nov 2025 16:50:16 +0100 Subject: [PATCH 459/585] Correctly handle doc items inlining --- src/librustdoc/clean/mod.rs | 21 +++++++++++++-------- src/librustdoc/clean/types.rs | 31 ------------------------------- src/librustdoc/visit_ast.rs | 18 +++++++----------- 3 files changed, 20 insertions(+), 50 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6fd578628388..bea4398ccf86 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -196,9 +196,12 @@ fn generate_item_with_correct_attrs( // For glob re-exports the item may or may not exist to be re-exported (potentially the // cfgs on the path up until the glob can be removed, and only cfgs on the globbed item // itself matter), for non-inlined re-exports see #85043. - let import_is_inline = find_attr!(inline::load_attrs(cx, import_id.to_def_id()), AttributeKind::Doc(d) if d.inline.is_some()) - || (is_glob_import(cx.tcx, import_id) - && (cx.document_hidden() || !cx.tcx.is_doc_hidden(def_id))); + let import_is_inline = find_attr!( + inline::load_attrs(cx, import_id.to_def_id()), + AttributeKind::Doc(d) + if d.inline.is_some_and(|(inline, _)| inline == DocInline::Inline) + ) || (is_glob_import(cx.tcx, import_id) + && (cx.document_hidden() || !cx.tcx.is_doc_hidden(def_id))); attrs.extend(get_all_import_attributes(cx, import_id, def_id, is_inline)); is_inline = is_inline || import_is_inline; } @@ -2666,10 +2669,10 @@ fn add_without_unwanted_attributes<'hir>( let DocAttribute { hidden, inline, cfg, .. } = d; let mut attr = DocAttribute::default(); if is_inline { + attr.cfg = cfg.clone(); + } else { attr.inline = inline.clone(); attr.hidden = hidden.clone(); - } else { - attr.cfg = cfg.clone(); } attrs.push(( Cow::Owned(hir::Attribute::Parsed(AttributeKind::Doc(Box::new(attr)))), @@ -2914,10 +2917,12 @@ fn clean_extern_crate<'tcx>( let attrs = cx.tcx.hir_attrs(krate.hir_id()); let ty_vis = cx.tcx.visibility(krate.owner_id); let please_inline = ty_vis.is_public() - && attrs.iter().any(|a| matches!( + && attrs.iter().any(|a| { + matches!( a, - hir::Attribute::Parsed(AttributeKind::Doc(d)) if d.inline.is_some_and(|(i, _)| i == DocInline::Inline)) - ) + hir::Attribute::Parsed(AttributeKind::Doc(d)) + if d.inline.is_some_and(|(i, _)| i == DocInline::Inline)) + }) && !cx.is_json_output(); let krate_owner_def_id = krate.owner_id.def_id; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 40191d5c98e0..cefaf1102fb9 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -929,37 +929,6 @@ pub(crate) struct Module { pub(crate) span: Span, } -pub(crate) fn hir_attr_lists<'a, I: IntoIterator>( - attrs: I, - name: Symbol, -) -> impl Iterator + use<'a, I> { - attrs - .into_iter() - .filter(move |attr| attr.has_name(name)) - .filter_map(ast::attr::AttributeExt::meta_item_list) - .flatten() -} - -pub(crate) trait NestedAttributesExt { - /// Returns `true` if the attribute list contains a specific `word` - fn has_word(self, word: Symbol) -> bool - where - Self: Sized, - { - ::get_word_attr(self, word).is_some() - } - - /// Returns `Some(attr)` if the attribute list contains 'attr' - /// corresponding to a specific `word` - fn get_word_attr(self, word: Symbol) -> Option; -} - -impl> NestedAttributesExt for I { - fn get_word_attr(mut self, word: Symbol) -> Option { - self.find(|attr| attr.is_word() && attr.has_name(word)) - } -} - /// A link that has not yet been rendered. /// /// This link will be turned into a rendered link by [`Item::links`]. diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 51b2821eb1e5..d6da8615d57e 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -3,9 +3,10 @@ use std::mem; +use rustc_ast::attr::AttributeExt; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir as hir; -use rustc_hir::attrs::AttributeKind; +use rustc_hir::attrs::{AttributeKind, DocInline}; use rustc_hir::def::{DefKind, MacroKinds, Res}; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet}; use rustc_hir::intravisit::{Visitor, walk_body, walk_item}; @@ -14,11 +15,11 @@ use rustc_middle::ty::TyCtxt; use rustc_span::Span; use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; -use rustc_span::symbol::{Symbol, kw, sym}; +use rustc_span::symbol::{Symbol, kw}; use tracing::debug; +use crate::clean::reexport_chain; use crate::clean::utils::{inherits_doc_hidden, should_ignore_res}; -use crate::clean::{NestedAttributesExt, hir_attr_lists, reexport_chain}; use crate::core; /// This module is used to store stuff from Rust's AST in a more convenient @@ -246,8 +247,8 @@ fn maybe_inline_local( let document_hidden = self.cx.document_hidden(); let use_attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); // Don't inline `doc(hidden)` imports so they can be stripped at a later stage. - let is_no_inline = hir_attr_lists(use_attrs, sym::doc).has_word(sym::no_inline) - || (document_hidden && hir_attr_lists(use_attrs, sym::doc).has_word(sym::hidden)); + let is_no_inline = find_attr!(use_attrs, AttributeKind::Doc(d) if d.inline.is_some_and(|(inline, _)| inline == DocInline::NoInline)) + || (document_hidden && use_attrs.iter().any(|attr| attr.is_doc_hidden())); if is_no_inline { return false; @@ -464,12 +465,7 @@ fn visit_item_inner( // If there was a private module in the current path then don't bother inlining // anything as it will probably be stripped anyway. if is_pub && self.inside_public_path { - let please_inline = attrs.iter().any(|item| match item.meta_item_list() { - Some(ref list) if item.has_name(sym::doc) => { - list.iter().any(|i| i.has_name(sym::inline)) - } - _ => false, - }); + let please_inline = find_attr!(attrs, AttributeKind::Doc(d) if d.inline.is_some_and(|(inline, _)| inline == DocInline::Inline)); let ident = match kind { hir::UseKind::Single(ident) => Some(ident.name), hir::UseKind::Glob => None, From 368a103902b00b4b0b93d30050ce2da7d5c2b0d9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 28 Nov 2025 18:49:19 +0100 Subject: [PATCH 460/585] Fix `Cfg` add/or operations --- .../rustc_hir/src/attrs/data_structures.rs | 36 +++++++++++++++---- src/librustdoc/clean/cfg.rs | 24 ++++++------- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 87a4cf7823f5..e35af0853651 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -197,14 +197,38 @@ pub enum CfgEntry { impl CfgEntry { pub fn span(&self) -> Span { - let (CfgEntry::All(_, span) - | CfgEntry::Any(_, span) - | CfgEntry::Not(_, span) - | CfgEntry::Bool(_, span) - | CfgEntry::NameValue { span, .. } - | CfgEntry::Version(_, span)) = self; + let (Self::All(_, span) + | Self::Any(_, span) + | Self::Not(_, span) + | Self::Bool(_, span) + | Self::NameValue { span, .. } + | Self::Version(_, span)) = self; *span } + + /// Same as `PartialEq` but doesn't check spans and ignore order of cfgs. + pub fn is_equivalent_to(&self, other: &Self) -> bool { + match (self, other) { + (Self::All(a, _), Self::All(b, _)) | (Self::Any(a, _), Self::Any(b, _)) => { + a.len() == b.len() && a.iter().all(|a| b.iter().any(|b| a.is_equivalent_to(b))) + } + (Self::Not(a, _), Self::Not(b, _)) => a.is_equivalent_to(b), + (Self::Bool(a, _), Self::Bool(b, _)) => a == b, + ( + Self::NameValue { name: name1, value: value1, .. }, + Self::NameValue { name: name2, value: value2, .. }, + ) => { + name1 == name2 + && match (value1, value2) { + (Some((a, _)), Some((b, _))) => a == b, + (None, None) => true, + _ => false, + } + } + (Self::Version(a, _), Self::Version(b, _)) => a == b, + _ => false, + } + } } /// Possible values for the `#[linkage]` attribute, allowing to specify the diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 38d3a47f8ca0..9b59e7ce6bef 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -280,13 +280,12 @@ pub(crate) fn render_long_plain(&self) -> String { fn should_append_only_to_description(&self) -> bool { match self.0 { - CfgEntry::Bool(..) => false, CfgEntry::Any(..) | CfgEntry::All(..) | CfgEntry::NameValue { .. } - | CfgEntry::Version(..) => true, - CfgEntry::Not(box CfgEntry::NameValue { .. }, _) => true, - CfgEntry::Not(..) => false, + | CfgEntry::Version(..) + | CfgEntry::Not(box CfgEntry::NameValue { .. }, _) => true, + CfgEntry::Not(..) | CfgEntry::Bool(..) => false, } } @@ -347,25 +346,25 @@ fn bitand_assign(&mut self, other: Cfg) { (s @ CfgEntry::Bool(true, _), b) => *s = b, (CfgEntry::All(a, _), CfgEntry::All(ref mut b, _)) => { for c in b.drain(..) { - if !a.contains(&c) { + if !a.iter().any(|a| a.is_equivalent_to(&c)) { a.push(c); } } } (CfgEntry::All(a, _), ref mut b) => { - if !a.contains(b) { + if !a.iter().any(|a| a.is_equivalent_to(b)) { a.push(mem::replace(b, CfgEntry::Bool(true, DUMMY_SP))); } } (s, CfgEntry::All(mut a, _)) => { let b = mem::replace(s, CfgEntry::Bool(true, DUMMY_SP)); - if !a.contains(&b) { + if !a.iter().any(|a| a.is_equivalent_to(&b)) { a.push(b); } *s = CfgEntry::All(a, DUMMY_SP); } (s, b) => { - if *s != b { + if !s.is_equivalent_to(&b) { let a = mem::replace(s, CfgEntry::Bool(true, DUMMY_SP)); *s = CfgEntry::All(thin_vec![a, b], DUMMY_SP); } @@ -391,25 +390,25 @@ fn bitor_assign(&mut self, other: Cfg) { (s @ CfgEntry::Bool(false, _), b) => *s = b, (CfgEntry::Any(a, _), CfgEntry::Any(ref mut b, _)) => { for c in b.drain(..) { - if !a.contains(&c) { + if !a.iter().any(|a| a.is_equivalent_to(&c)) { a.push(c); } } } (CfgEntry::Any(a, _), ref mut b) => { - if !a.contains(b) { + if !a.iter().any(|a| a.is_equivalent_to(b)) { a.push(mem::replace(b, CfgEntry::Bool(true, DUMMY_SP))); } } (s, CfgEntry::Any(mut a, _)) => { let b = mem::replace(s, CfgEntry::Bool(true, DUMMY_SP)); - if !a.contains(&b) { + if !a.iter().any(|a| a.is_equivalent_to(&b)) { a.push(b); } *s = CfgEntry::Any(a, DUMMY_SP); } (s, b) => { - if *s != b { + if !s.is_equivalent_to(&b) { let a = mem::replace(s, CfgEntry::Bool(true, DUMMY_SP)); *s = CfgEntry::Any(thin_vec![a, b], DUMMY_SP); } @@ -757,6 +756,7 @@ fn handle_auto_cfg_hide_show( { for item in items { // FIXME: Report in case `Cfg::parse` reports an error? + let Ok(cfg) = Cfg::parse(item) else { continue }; if let CfgEntry::NameValue { name, value, .. } = cfg.0 { let value = value.map(|(v, _)| v); From d35ec316c5496b2eda68ba05b9dd28ba94bfa87e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 1 Dec 2025 15:31:10 +0100 Subject: [PATCH 461/585] Keep a list of `CfgEntry` instead of just one --- compiler/rustc_attr_parsing/src/attributes/doc.rs | 5 ++++- compiler/rustc_hir/src/attrs/data_structures.rs | 4 ++-- src/librustdoc/clean/cfg.rs | 12 ++++++------ src/librustdoc/passes/collect_trait_impls.rs | 2 +- src/librustdoc/passes/propagate_doc_cfg.rs | 2 +- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 1a7d8ec93f70..5e48ade6b7cf 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -225,7 +225,7 @@ fn parse_cfg<'c, S: Stage>( args: &ArgParser<'_>, ) { if let Some(cfg_entry) = super::cfg::parse_cfg(cx, args) { - self.attribute.cfg = Some(cfg_entry); + self.attribute.cfg.push(cfg_entry); } } @@ -524,6 +524,9 @@ impl AttributeParser for DocParser { fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.nb_doc_attrs != 0 { + if std::env::var("LOL").is_ok() { + eprintln!("+++++> {:#?}", self.attribute); + } Some(AttributeKind::Doc(Box::new(self.attribute))) } else { None diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index e35af0853651..323a1290bb2a 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -479,7 +479,7 @@ pub struct DocAttribute { pub inline: Option<(DocInline, Span)>, // unstable - pub cfg: Option, + pub cfg: ThinVec, pub auto_cfg: ThinVec, /// This is for `#[doc(auto_cfg = false|true)]`. pub auto_cfg_change: Option<(bool, Span)>, @@ -512,7 +512,7 @@ fn default() -> Self { aliases: FxIndexMap::default(), hidden: None, inline: None, - cfg: None, + cfg: ThinVec::new(), auto_cfg: ThinVec::new(), auto_cfg_change: None, fake_variadic: None, diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 9b59e7ce6bef..727ad82eeca5 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -24,7 +24,7 @@ #[cfg(test)] mod tests; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, Hash)] pub(crate) struct Cfg(CfgEntry); #[derive(PartialEq, Debug)] @@ -299,13 +299,13 @@ fn should_use_with_in_description(&self) -> bool { /// /// See `tests::test_simplify_with` for examples. pub(crate) fn simplify_with(&self, assume: &Self) -> Option { - if self == assume { + if self.0.is_equivalent_to(&assume.0) { None } else if let CfgEntry::All(a, _) = &self.0 { let mut sub_cfgs: ThinVec = if let CfgEntry::All(b, _) = &assume.0 { - a.iter().filter(|a| !b.contains(a)).cloned().collect() + a.iter().filter(|a| !b.iter().any(|b| a.is_equivalent_to(b))).cloned().collect() } else { - a.iter().filter(|&a| *a != assume.0).cloned().collect() + a.iter().filter(|&a| !a.is_equivalent_to(&assume.0)).cloned().collect() }; let len = sub_cfgs.len(); match len { @@ -314,7 +314,7 @@ pub(crate) fn simplify_with(&self, assume: &Self) -> Option { _ => Some(Cfg(CfgEntry::All(sub_cfgs, DUMMY_SP))), } } else if let CfgEntry::All(b, _) = &assume.0 - && b.contains(&self.0) + && b.iter().any(|b| b.is_equivalent_to(&self.0)) { None } else { @@ -838,7 +838,7 @@ fn check_changed_auto_active_status( cfg_info.parent_is_doc_cfg = true; } for attr in doc_cfg { - if let Some(new_cfg) = attr.cfg.clone() { + for new_cfg in attr.cfg.clone() { cfg_info.current_cfg &= Cfg(new_cfg); } } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index d71c3eaa2dcb..357d00ef6521 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -67,7 +67,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> let mut parent = Some(tcx.parent(impl_def_id)); while let Some(did) = parent { attr_buf.extend(tcx.get_all_attrs(did).iter().filter_map(|attr| match attr { - Attribute::Parsed(AttributeKind::Doc(d)) if d.cfg.is_some() => { + Attribute::Parsed(AttributeKind::Doc(d)) if !d.cfg.is_empty() => { let mut new_attr = DocAttribute::default(); new_attr.cfg = d.cfg.clone(); Some(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr)))) diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 422393592c76..95f5537f394c 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -34,7 +34,7 @@ struct CfgPropagator<'a, 'tcx> { fn add_only_cfg_attributes(attrs: &mut Vec, new_attrs: &[Attribute]) { for attr in new_attrs { if let Attribute::Parsed(AttributeKind::Doc(d)) = attr - && d.cfg.is_some() + && !d.cfg.is_empty() { let mut new_attr = DocAttribute::default(); new_attr.cfg = d.cfg.clone(); From 57870b7242e3b3446abad0bc1672b52a46d92e1f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 1 Dec 2025 17:03:39 +0100 Subject: [PATCH 462/585] Fix `doc(auto_cfg)` attribute parsing --- .../rustc_attr_parsing/src/attributes/doc.rs | 24 ++- .../rustc_hir/src/attrs/data_structures.rs | 8 +- src/librustdoc/clean/cfg.rs | 151 +++++++----------- 3 files changed, 82 insertions(+), 101 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 5e48ade6b7cf..fb99f43fced8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -224,7 +224,21 @@ fn parse_cfg<'c, S: Stage>( cx: &'c mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>, ) { - if let Some(cfg_entry) = super::cfg::parse_cfg(cx, args) { + // This function replaces cases like `cfg(all())` with `true`. + fn simplify_cfg(cfg_entry: &mut CfgEntry) { + match cfg_entry { + CfgEntry::All(cfgs, span) if cfgs.is_empty() => { + *cfg_entry = CfgEntry::Bool(true, *span) + } + CfgEntry::Any(cfgs, span) if cfgs.is_empty() => { + *cfg_entry = CfgEntry::Bool(false, *span) + } + CfgEntry::Not(cfg, _) => simplify_cfg(cfg), + _ => {} + } + } + if let Some(mut cfg_entry) = super::cfg::parse_cfg(cx, args) { + simplify_cfg(&mut cfg_entry); self.attribute.cfg.push(cfg_entry); } } @@ -237,7 +251,7 @@ fn parse_auto_cfg<'c, S: Stage>( ) { match args { ArgParser::NoArgs => { - cx.expected_list(args.span().unwrap_or(path.span())); + self.attribute.auto_cfg_change.push((true, path.span())); } ArgParser::List(list) => { for meta in list.mixed() { @@ -303,6 +317,7 @@ fn parse_auto_cfg<'c, S: Stage>( } } } + self.attribute.auto_cfg.push((cfg_hide_show, path.span())); } } ArgParser::NameValue(nv) => { @@ -311,7 +326,7 @@ fn parse_auto_cfg<'c, S: Stage>( cx.emit_lint(AttributeLintKind::DocAutoCfgWrongLiteral, nv.value_span); return; }; - self.attribute.auto_cfg_change = Some((*bool_value, *span)); + self.attribute.auto_cfg_change.push((*bool_value, *span)); } } } @@ -524,9 +539,6 @@ impl AttributeParser for DocParser { fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.nb_doc_attrs != 0 { - if std::env::var("LOL").is_ok() { - eprintln!("+++++> {:#?}", self.attribute); - } Some(AttributeKind::Doc(Box::new(self.attribute))) } else { None diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 323a1290bb2a..4e1de8e5aeae 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -480,9 +480,9 @@ pub struct DocAttribute { // unstable pub cfg: ThinVec, - pub auto_cfg: ThinVec, - /// This is for `#[doc(auto_cfg = false|true)]`. - pub auto_cfg_change: Option<(bool, Span)>, + pub auto_cfg: ThinVec<(CfgHideShow, Span)>, + /// This is for `#[doc(auto_cfg = false|true)]`/`#[doc(auto_cfg)]`. + pub auto_cfg_change: ThinVec<(bool, Span)>, // builtin pub fake_variadic: Option, @@ -514,7 +514,7 @@ fn default() -> Self { inline: None, cfg: ThinVec::new(), auto_cfg: ThinVec::new(), - auto_cfg_change: None, + auto_cfg_change: ThinVec::new(), fake_variadic: None, keyword: None, attribute: None, diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 727ad82eeca5..292df1cf9550 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -10,13 +10,13 @@ use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::thin_vec::{ThinVec, thin_vec}; +use rustc_hir as hir; use rustc_hir::Attribute; -use rustc_hir::attrs::{AttributeKind, CfgEntry}; +use rustc_hir::attrs::{self, AttributeKind, CfgEntry, CfgHideShow, HideOrShow}; use rustc_middle::ty::TyCtxt; use rustc_session::parse::ParseSess; use rustc_span::symbol::{Symbol, sym}; use rustc_span::{DUMMY_SP, Span}; -use {rustc_ast as ast, rustc_hir as hir}; use crate::display::{Joined as _, MaybeDisplay, Wrapped}; use crate::html::escape::Escape; @@ -689,6 +689,12 @@ fn from(cfg: &'a CfgEntry) -> Self { } } +impl<'a> From<&'a attrs::CfgInfo> for SimpleCfg { + fn from(cfg: &'a attrs::CfgInfo) -> Self { + Self { name: cfg.name, value: cfg.value.map(|(value, _)| value) } + } +} + /// This type keeps track of (doc) cfg information as we go down the item tree. #[derive(Clone, Debug)] pub(crate) struct CfgInfo { @@ -746,37 +752,27 @@ fn show_hide_show_conflict_error( fn handle_auto_cfg_hide_show( tcx: TyCtxt<'_>, cfg_info: &mut CfgInfo, - sub_attr: &MetaItemInner, - is_show: bool, + attr: &CfgHideShow, + attr_span: Span, new_show_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, new_hide_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, ) { - if let MetaItemInner::MetaItem(item) = sub_attr - && let MetaItemKind::List(items) = &item.kind - { - for item in items { - // FIXME: Report in case `Cfg::parse` reports an error? - - let Ok(cfg) = Cfg::parse(item) else { continue }; - if let CfgEntry::NameValue { name, value, .. } = cfg.0 { - let value = value.map(|(v, _)| v); - let simple = SimpleCfg::from(&cfg.0); - if is_show { - if let Some(span) = new_hide_attrs.get(&(name, value)) { - show_hide_show_conflict_error(tcx, item.span(), *span); - } else { - new_show_attrs.insert((name, value), item.span()); - } - cfg_info.hidden_cfg.remove(&simple); - } else { - if let Some(span) = new_show_attrs.get(&(name, value)) { - show_hide_show_conflict_error(tcx, item.span(), *span); - } else { - new_hide_attrs.insert((name, value), item.span()); - } - cfg_info.hidden_cfg.insert(simple); - } + for value in &attr.values { + let simple = SimpleCfg::from(value); + if attr.kind == HideOrShow::Show { + if let Some(span) = new_hide_attrs.get(&(simple.name, simple.value)) { + show_hide_show_conflict_error(tcx, attr_span, *span); + } else { + new_show_attrs.insert((simple.name, simple.value), attr_span); } + cfg_info.hidden_cfg.remove(&simple); + } else { + if let Some(span) = new_show_attrs.get(&(simple.name, simple.value)) { + show_hide_show_conflict_error(tcx, attr_span, *span); + } else { + new_hide_attrs.insert((simple.name, simple.value), attr_span); + } + cfg_info.hidden_cfg.insert(simple); } } } @@ -797,7 +793,7 @@ fn single(it: T) -> Option { fn check_changed_auto_active_status( changed_auto_active_status: &mut Option, - attr: &ast::MetaItem, + attr_span: Span, cfg_info: &mut CfgInfo, tcx: TyCtxt<'_>, new_value: bool, @@ -807,14 +803,14 @@ fn check_changed_auto_active_status( tcx.sess .dcx() .struct_span_err( - vec![*first_change, attr.span], + vec![*first_change, attr_span], "`auto_cfg` was disabled and enabled more than once on the same item", ) .emit(); return true; } } else { - *changed_auto_active_status = Some(attr.span); + *changed_auto_active_status = Some(attr_span); } cfg_info.auto_cfg_active = new_value; false @@ -826,7 +822,7 @@ fn check_changed_auto_active_status( let mut doc_cfg = attrs .clone() .filter_map(|attr| match attr { - Attribute::Parsed(AttributeKind::Doc(d)) => Some(d), + Attribute::Parsed(AttributeKind::Doc(d)) if !d.cfg.is_empty() => Some(d), _ => None, }) .peekable(); @@ -850,64 +846,37 @@ fn check_changed_auto_active_status( // We get all `doc(auto_cfg)`, `cfg` and `target_feature` attributes. for attr in attrs { - if let Some(ident) = attr.ident() - && ident.name == sym::doc - && let Some(attrs) = attr.meta_item_list() - { - for attr in attrs.iter().filter(|attr| attr.has_name(sym::auto_cfg)) { - let MetaItemInner::MetaItem(attr) = attr else { - continue; - }; - match &attr.kind { - MetaItemKind::Word => { - if check_changed_auto_active_status( - &mut changed_auto_active_status, - attr, - cfg_info, - tcx, - true, - ) { - return None; - } - } - MetaItemKind::NameValue(lit) => { - if let LitKind::Bool(value) = lit.kind { - if check_changed_auto_active_status( - &mut changed_auto_active_status, - attr, - cfg_info, - tcx, - value, - ) { - return None; - } - } - } - MetaItemKind::List(sub_attrs) => { - if check_changed_auto_active_status( - &mut changed_auto_active_status, - attr, - cfg_info, - tcx, - true, - ) { - return None; - } - for sub_attr in sub_attrs.iter() { - if let Some(ident) = sub_attr.ident() - && (ident.name == sym::show || ident.name == sym::hide) - { - handle_auto_cfg_hide_show( - tcx, - cfg_info, - &sub_attr, - ident.name == sym::show, - &mut new_show_attrs, - &mut new_hide_attrs, - ); - } - } - } + if let Attribute::Parsed(AttributeKind::Doc(d)) = attr { + for (new_value, span) in &d.auto_cfg_change { + if check_changed_auto_active_status( + &mut changed_auto_active_status, + *span, + cfg_info, + tcx, + *new_value, + ) { + return None; + } + } + if let Some((_, span)) = d.auto_cfg.first() { + if check_changed_auto_active_status( + &mut changed_auto_active_status, + *span, + cfg_info, + tcx, + true, + ) { + return None; + } + for (value, span) in &d.auto_cfg { + handle_auto_cfg_hide_show( + tcx, + cfg_info, + value, + *span, + &mut new_show_attrs, + &mut new_hide_attrs, + ); } } } else if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr { From 5c47240ad16fc19d093176c606a7529b54401b9e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 2 Dec 2025 16:01:20 +0100 Subject: [PATCH 463/585] Correctly handle `doc(test(attr(...)))` --- Cargo.lock | 2 +- compiler/rustc_attr_parsing/src/attributes/doc.rs | 6 +++--- src/librustdoc/Cargo.toml | 2 +- src/librustdoc/doctest.rs | 2 +- src/librustdoc/doctest/rust.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 23708adcc499..d818d87e0804 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4868,9 +4868,9 @@ dependencies = [ "indexmap", "itertools", "minifier", + "proc-macro2", "pulldown-cmark-escape", "regex", - "rustc_proc_macro", "rustdoc-json-types", "serde", "serde_json", diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index fb99f43fced8..26fb53baf2e4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -115,9 +115,9 @@ fn parse_single_test_doc_attr_item<'c, S: Stage>( return; }; - // FIXME: convert list into a Vec of `AttributeKind`. - for _ in list.mixed() { - // self.attribute.test_attrs.push(AttributeKind::parse()); + // FIXME: convert list into a Vec of `AttributeKind` because current code is awful. + for attr in list.mixed() { + self.attribute.test_attrs.push(attr.span()); } } Some(name) => { diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 371da896b9fc..dcfc1ffc251e 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -15,10 +15,10 @@ base64 = "0.21.7" indexmap = { version = "2", features = ["serde"] } itertools = "0.12" minifier = { version = "0.3.5", default-features = false } +proc-macro2 = "1.0.103" pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } -rustc_proc_macro = { path = "../../compiler/rustc_proc_macro" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" smallvec = "1.8.1" diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 7541311be05d..19e8fe3e3ed2 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -17,6 +17,7 @@ pub(crate) use make::{BuildDocTestBuilder, DocTestBuilder}; pub(crate) use markdown::test as test_markdown; +use proc_macro2::{TokenStream, TokenTree}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxHasher, FxIndexMap, FxIndexSet}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagCtxtHandle}; @@ -25,7 +26,6 @@ use rustc_hir::{Attribute, CRATE_HIR_ID}; use rustc_interface::interface; use rustc_middle::ty::TyCtxt; -use rustc_proc_macro::{TokenStream, TokenTree}; use rustc_session::config::{self, CrateType, ErrorOutputType, Input}; use rustc_session::lint; use rustc_span::edition::Edition; diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index e119344a806a..6f294ad96267 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -5,12 +5,12 @@ use std::str::FromStr; use std::sync::Arc; +use proc_macro2::{TokenStream, TokenTree}; use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{self as hir, Attribute, CRATE_HIR_ID, intravisit}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; -use rustc_proc_macro::{TokenStream, TokenTree}; use rustc_resolve::rustdoc::span_of_fragments; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span}; From 976d45452a90780a3e0b850dfb635232fa2f3058 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 2 Dec 2025 17:25:43 +0100 Subject: [PATCH 464/585] Update rustdoc unit tests --- src/librustdoc/clean/cfg.rs | 3 + src/librustdoc/clean/cfg/tests.rs | 266 +++++++++++++++++----------- src/librustdoc/clean/types/tests.rs | 5 +- 3 files changed, 170 insertions(+), 104 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 292df1cf9550..99409cf838cd 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -25,6 +25,9 @@ mod tests; #[derive(Clone, Debug, Hash)] +// Because `CfgEntry` includes `Span`, we must NEVER use `==`/`!=` operators on `Cfg` and instead +// use `is_equivalent_to`. +#[cfg_attr(test, derive(PartialEq))] pub(crate) struct Cfg(CfgEntry); #[derive(PartialEq, Debug)] diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index f0591295da64..4eb6c060cbd2 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -1,23 +1,62 @@ use rustc_ast::ast::LitIntType; use rustc_ast::{MetaItemInner, MetaItemLit, Path, Safety, StrStyle}; use rustc_data_structures::thin_vec::thin_vec; +use rustc_hir::attrs::CfgEntry; use rustc_span::symbol::{Ident, kw}; use rustc_span::{DUMMY_SP, create_default_session_globals_then}; use super::*; -fn word_cfg(s: &str) -> Cfg { - Cfg::Cfg(Symbol::intern(s), None) +fn word_cfg(name: &str) -> Cfg { + Cfg(word_cfg_e(name)) +} + +fn word_cfg_e(name: &str) -> CfgEntry { + CfgEntry::NameValue { + name: Symbol::intern(name), + name_span: DUMMY_SP, + value: None, + span: DUMMY_SP, + } } fn name_value_cfg(name: &str, value: &str) -> Cfg { - Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value))) + Cfg(name_value_cfg_e(name, value)) +} + +fn name_value_cfg_e(name: &str, value: &str) -> CfgEntry { + CfgEntry::NameValue { + name: Symbol::intern(name), + name_span: DUMMY_SP, + value: Some((Symbol::intern(value), DUMMY_SP)), + span: DUMMY_SP, + } } fn dummy_lit(symbol: Symbol, kind: LitKind) -> MetaItemInner { MetaItemInner::Lit(MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }) } +fn cfg_all(v: ThinVec) -> Cfg { + Cfg(cfg_all_e(v)) +} + +fn cfg_all_e(v: ThinVec) -> CfgEntry { + CfgEntry::All(v, DUMMY_SP) +} + +fn cfg_any(v: ThinVec) -> Cfg { + Cfg(cfg_any_e(v)) +} + +fn cfg_any_e(v: ThinVec) -> CfgEntry { + CfgEntry::Any(v, DUMMY_SP) +} + +fn cfg_not(v: CfgEntry) -> Cfg { + Cfg(CfgEntry::Not(Box::new(v), DUMMY_SP)) +} + fn dummy_meta_item_word(name: &str) -> MetaItemInner { MetaItemInner::MetaItem(MetaItem { unsafety: Safety::Default, @@ -63,40 +102,48 @@ macro_rules! dummy_meta_item_list { }; } +fn cfg_true() -> Cfg { + Cfg(CfgEntry::Bool(true, DUMMY_SP)) +} + +fn cfg_false() -> Cfg { + Cfg(CfgEntry::Bool(false, DUMMY_SP)) +} + #[test] fn test_cfg_not() { create_default_session_globals_then(|| { - assert_eq!(!Cfg::False, Cfg::True); - assert_eq!(!Cfg::True, Cfg::False); - assert_eq!(!word_cfg("test"), Cfg::Not(Box::new(word_cfg("test")))); + assert_eq!(!cfg_false(), cfg_true()); + assert_eq!(!cfg_true(), cfg_false()); + assert_eq!(!word_cfg("test"), cfg_not(word_cfg_e("test"))); assert_eq!( - !Cfg::All(vec![word_cfg("a"), word_cfg("b")]), - Cfg::Not(Box::new(Cfg::All(vec![word_cfg("a"), word_cfg("b")]))) + !cfg_all(thin_vec![word_cfg_e("a"), word_cfg_e("b")]), + cfg_not(cfg_all_e(thin_vec![word_cfg_e("a"), word_cfg_e("b")])) ); assert_eq!( - !Cfg::Any(vec![word_cfg("a"), word_cfg("b")]), - Cfg::Not(Box::new(Cfg::Any(vec![word_cfg("a"), word_cfg("b")]))) + !cfg_any(thin_vec![word_cfg_e("a"), word_cfg_e("b")]), + cfg_not(cfg_any_e(thin_vec![word_cfg_e("a"), word_cfg_e("b")])) ); - assert_eq!(!Cfg::Not(Box::new(word_cfg("test"))), word_cfg("test")); + assert_eq!(!cfg_not(word_cfg_e("test")), word_cfg("test")); }) } #[test] fn test_cfg_and() { create_default_session_globals_then(|| { - let mut x = Cfg::False; - x &= Cfg::True; - assert_eq!(x, Cfg::False); + let mut x = cfg_false(); + x &= cfg_true(); + assert_eq!(x, cfg_false()); x = word_cfg("test"); - x &= Cfg::False; - assert_eq!(x, Cfg::False); + x &= cfg_false(); + assert_eq!(x, cfg_false()); x = word_cfg("test2"); - x &= Cfg::True; + x &= cfg_true(); assert_eq!(x, word_cfg("test2")); - x = Cfg::True; + x = cfg_true(); x &= word_cfg("test3"); assert_eq!(x, word_cfg("test3")); @@ -104,63 +151,69 @@ fn test_cfg_and() { assert_eq!(x, word_cfg("test3")); x &= word_cfg("test4"); - assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")])); + assert_eq!(x, cfg_all(thin_vec![word_cfg_e("test3"), word_cfg_e("test4")])); x &= word_cfg("test4"); - assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")])); + assert_eq!(x, cfg_all(thin_vec![word_cfg_e("test3"), word_cfg_e("test4")])); x &= word_cfg("test5"); - assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")])); - - x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]); assert_eq!( x, - Cfg::All(vec![ - word_cfg("test3"), - word_cfg("test4"), - word_cfg("test5"), - word_cfg("test6"), - word_cfg("test7"), + cfg_all(thin_vec![word_cfg_e("test3"), word_cfg_e("test4"), word_cfg_e("test5")]) + ); + + x &= cfg_all(thin_vec![word_cfg_e("test6"), word_cfg_e("test7")]); + assert_eq!( + x, + cfg_all(thin_vec![ + word_cfg_e("test3"), + word_cfg_e("test4"), + word_cfg_e("test5"), + word_cfg_e("test6"), + word_cfg_e("test7"), ]) ); - x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]); + x &= cfg_all(thin_vec![word_cfg_e("test6"), word_cfg_e("test7")]); assert_eq!( x, - Cfg::All(vec![ - word_cfg("test3"), - word_cfg("test4"), - word_cfg("test5"), - word_cfg("test6"), - word_cfg("test7"), + cfg_all(thin_vec![ + word_cfg_e("test3"), + word_cfg_e("test4"), + word_cfg_e("test5"), + word_cfg_e("test6"), + word_cfg_e("test7"), ]) ); - let mut y = Cfg::Any(vec![word_cfg("a"), word_cfg("b")]); + let mut y = cfg_any(thin_vec![word_cfg_e("a"), word_cfg_e("b")]); y &= x; assert_eq!( y, - Cfg::All(vec![ - word_cfg("test3"), - word_cfg("test4"), - word_cfg("test5"), - word_cfg("test6"), - word_cfg("test7"), - Cfg::Any(vec![word_cfg("a"), word_cfg("b")]), + cfg_all(thin_vec![ + word_cfg_e("test3"), + word_cfg_e("test4"), + word_cfg_e("test5"), + word_cfg_e("test6"), + word_cfg_e("test7"), + cfg_any_e(thin_vec![word_cfg_e("a"), word_cfg_e("b")]), ]) ); let mut z = word_cfg("test8"); - z &= Cfg::All(vec![word_cfg("test9"), word_cfg("test10")]); - assert_eq!(z, Cfg::All(vec![word_cfg("test9"), word_cfg("test10"), word_cfg("test8")])); + z &= cfg_all(thin_vec![word_cfg_e("test9"), word_cfg_e("test10")]); + assert_eq!( + z, + cfg_all(thin_vec![word_cfg_e("test9"), word_cfg_e("test10"), word_cfg_e("test8"),]), + ); let mut z = word_cfg("test11"); - z &= Cfg::All(vec![word_cfg("test11"), word_cfg("test12")]); - assert_eq!(z, Cfg::All(vec![word_cfg("test11"), word_cfg("test12")])); + z &= cfg_all(thin_vec![word_cfg_e("test11"), word_cfg_e("test12")]); + assert_eq!(z, cfg_all(thin_vec![word_cfg_e("test11"), word_cfg_e("test12")])); assert_eq!( word_cfg("a") & word_cfg("b") & word_cfg("c"), - Cfg::All(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")]) + cfg_all(thin_vec![word_cfg_e("a"), word_cfg_e("b"), word_cfg_e("c")]) ); }) } @@ -168,19 +221,19 @@ fn test_cfg_and() { #[test] fn test_cfg_or() { create_default_session_globals_then(|| { - let mut x = Cfg::True; - x |= Cfg::False; - assert_eq!(x, Cfg::True); + let mut x = cfg_true(); + x |= cfg_false(); + assert_eq!(x, cfg_true()); x = word_cfg("test"); - x |= Cfg::True; + x |= cfg_true(); assert_eq!(x, word_cfg("test")); x = word_cfg("test2"); - x |= Cfg::False; + x |= cfg_false(); assert_eq!(x, word_cfg("test2")); - x = Cfg::False; + x = cfg_false(); x |= word_cfg("test3"); assert_eq!(x, word_cfg("test3")); @@ -188,63 +241,69 @@ fn test_cfg_or() { assert_eq!(x, word_cfg("test3")); x |= word_cfg("test4"); - assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")])); + assert_eq!(x, cfg_any(thin_vec![word_cfg_e("test3"), word_cfg_e("test4")])); x |= word_cfg("test4"); - assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")])); + assert_eq!(x, cfg_any(thin_vec![word_cfg_e("test3"), word_cfg_e("test4")])); x |= word_cfg("test5"); - assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")])); - - x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]); assert_eq!( x, - Cfg::Any(vec![ - word_cfg("test3"), - word_cfg("test4"), - word_cfg("test5"), - word_cfg("test6"), - word_cfg("test7"), + cfg_any(thin_vec![word_cfg_e("test3"), word_cfg_e("test4"), word_cfg_e("test5")]) + ); + + x |= cfg_any(thin_vec![word_cfg_e("test6"), word_cfg_e("test7")]); + assert_eq!( + x, + cfg_any(thin_vec![ + word_cfg_e("test3"), + word_cfg_e("test4"), + word_cfg_e("test5"), + word_cfg_e("test6"), + word_cfg_e("test7"), ]) ); - x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]); + x |= cfg_any(thin_vec![word_cfg_e("test6"), word_cfg_e("test7")]); assert_eq!( x, - Cfg::Any(vec![ - word_cfg("test3"), - word_cfg("test4"), - word_cfg("test5"), - word_cfg("test6"), - word_cfg("test7"), + cfg_any(thin_vec![ + word_cfg_e("test3"), + word_cfg_e("test4"), + word_cfg_e("test5"), + word_cfg_e("test6"), + word_cfg_e("test7"), ]) ); - let mut y = Cfg::All(vec![word_cfg("a"), word_cfg("b")]); + let mut y = cfg_all(thin_vec![word_cfg_e("a"), word_cfg_e("b")]); y |= x; assert_eq!( y, - Cfg::Any(vec![ - word_cfg("test3"), - word_cfg("test4"), - word_cfg("test5"), - word_cfg("test6"), - word_cfg("test7"), - Cfg::All(vec![word_cfg("a"), word_cfg("b")]), + cfg_any(thin_vec![ + word_cfg_e("test3"), + word_cfg_e("test4"), + word_cfg_e("test5"), + word_cfg_e("test6"), + word_cfg_e("test7"), + cfg_all_e(thin_vec![word_cfg_e("a"), word_cfg_e("b")]), ]) ); let mut z = word_cfg("test8"); - z |= Cfg::Any(vec![word_cfg("test9"), word_cfg("test10")]); - assert_eq!(z, Cfg::Any(vec![word_cfg("test9"), word_cfg("test10"), word_cfg("test8")])); + z |= cfg_any(thin_vec![word_cfg_e("test9"), word_cfg_e("test10")]); + assert_eq!( + z, + cfg_any(thin_vec![word_cfg_e("test9"), word_cfg_e("test10"), word_cfg_e("test8")]) + ); let mut z = word_cfg("test11"); - z |= Cfg::Any(vec![word_cfg("test11"), word_cfg("test12")]); - assert_eq!(z, Cfg::Any(vec![word_cfg("test11"), word_cfg("test12")])); + z |= cfg_any(thin_vec![word_cfg_e("test11"), word_cfg_e("test12")]); + assert_eq!(z, cfg_any(thin_vec![word_cfg_e("test11"), word_cfg_e("test12")])); assert_eq!( word_cfg("a") | word_cfg("b") | word_cfg("c"), - Cfg::Any(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")]) + cfg_any(thin_vec![word_cfg_e("a"), word_cfg_e("b"), word_cfg_e("c")]) ); }) } @@ -254,11 +313,11 @@ fn test_parse_ok() { create_default_session_globals_then(|| { let r#true = Symbol::intern("true"); let mi = dummy_lit(r#true, LitKind::Bool(true)); - assert_eq!(Cfg::parse(&mi), Ok(Cfg::True)); + assert_eq!(Cfg::parse(&mi), Ok(cfg_true())); let r#false = Symbol::intern("false"); let mi = dummy_lit(r#false, LitKind::Bool(false)); - assert_eq!(Cfg::parse(&mi), Ok(Cfg::False)); + assert_eq!(Cfg::parse(&mi), Ok(cfg_false())); let mi = dummy_meta_item_word("all"); assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all"))); @@ -464,33 +523,36 @@ fn test_simplify_with() { // This is a tiny subset of things that could be simplified, but it likely covers 90% of // real world usecases well. create_default_session_globals_then(|| { - let foo = word_cfg("foo"); - let bar = word_cfg("bar"); - let baz = word_cfg("baz"); - let quux = word_cfg("quux"); + let foo = word_cfg_e("foo"); + let bar = word_cfg_e("bar"); + let baz = word_cfg_e("baz"); + let quux = word_cfg_e("quux"); - let foobar = Cfg::All(vec![foo.clone(), bar.clone()]); - let barbaz = Cfg::All(vec![bar.clone(), baz.clone()]); - let foobarbaz = Cfg::All(vec![foo.clone(), bar.clone(), baz.clone()]); - let bazquux = Cfg::All(vec![baz.clone(), quux.clone()]); + let foobar = cfg_all(thin_vec![foo.clone(), bar.clone()]); + let barbaz = cfg_all(thin_vec![bar.clone(), baz.clone()]); + let foobarbaz = cfg_all(thin_vec![foo.clone(), bar.clone(), baz.clone()]); + let bazquux = cfg_all(thin_vec![baz.clone(), quux.clone()]); // Unrelated cfgs don't affect each other - assert_eq!(foo.simplify_with(&bar).as_ref(), Some(&foo)); + assert_eq!( + Cfg(foo.clone()).simplify_with(&Cfg(bar.clone())).as_ref(), + Some(&Cfg(foo.clone())) + ); assert_eq!(foobar.simplify_with(&bazquux).as_ref(), Some(&foobar)); // Identical cfgs are eliminated - assert_eq!(foo.simplify_with(&foo), None); + assert_eq!(Cfg(foo.clone()).simplify_with(&Cfg(foo.clone())), None); assert_eq!(foobar.simplify_with(&foobar), None); // Multiple cfgs eliminate a single assumed cfg - assert_eq!(foobar.simplify_with(&foo).as_ref(), Some(&bar)); - assert_eq!(foobar.simplify_with(&bar).as_ref(), Some(&foo)); + assert_eq!(foobar.simplify_with(&Cfg(foo.clone())).as_ref(), Some(&Cfg(bar.clone()))); + assert_eq!(foobar.simplify_with(&Cfg(bar)).as_ref(), Some(&Cfg(foo.clone()))); // A single cfg is eliminated by multiple assumed cfg containing it - assert_eq!(foo.simplify_with(&foobar), None); + assert_eq!(Cfg(foo.clone()).simplify_with(&foobar), None); // Multiple cfgs eliminate the matching subset of multiple assumed cfg - assert_eq!(foobar.simplify_with(&barbaz).as_ref(), Some(&foo)); + assert_eq!(foobar.simplify_with(&barbaz).as_ref(), Some(&Cfg(foo))); assert_eq!(foobar.simplify_with(&foobarbaz), None); }); } diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs index 9499507b2c0f..915b7d851a3e 100644 --- a/src/librustdoc/clean/types/tests.rs +++ b/src/librustdoc/clean/types/tests.rs @@ -1,4 +1,5 @@ -use rustc_resolve::rustdoc::{DocFragmentKind, unindent_doc_fragments}; +use rustc_ast::token::{CommentKind, DocFragmentKind}; +use rustc_resolve::rustdoc::unindent_doc_fragments; use rustc_span::create_default_session_globals_then; use super::*; @@ -8,7 +9,7 @@ fn create_doc_fragment(s: &str) -> Vec { span: DUMMY_SP, item_id: None, doc: Symbol::intern(s), - kind: DocFragmentKind::SugaredDoc, + kind: DocFragmentKind::Sugared(CommentKind::Line), indent: 0, from_expansion: false, }] From 9c8c67bfdd864f6ba6eb1bf23b57cd81499c4e2d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 3 Dec 2025 15:55:57 +0100 Subject: [PATCH 465/585] Fix warning messages --- .../rustc_attr_parsing/src/attributes/doc.rs | 17 +- .../src/session_diagnostics.rs | 9 - .../rustc_hir/src/attrs/data_structures.rs | 6 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_passes/messages.ftl | 12 +- compiler/rustc_passes/src/check_attr.rs | 28 ++- compiler/rustc_passes/src/errors.rs | 8 + src/librustdoc/clean/mod.rs | 14 +- src/librustdoc/lib.rs | 14 ++ src/librustdoc/visit_ast.rs | 14 +- tests/rustdoc-ui/bad-render-options.rs | 36 ++- tests/rustdoc-ui/bad-render-options.stderr | 209 +++++++++++++++--- .../rustdoc-ui/cfg-hide-show-conflict.stderr | 8 +- .../check-doc-alias-attr-location.stderr | 16 +- tests/rustdoc-ui/check-doc-alias-attr.stderr | 61 +++-- tests/rustdoc-ui/doc-alias-assoc-const.stderr | 4 +- tests/rustdoc-ui/doc-alias-same-name.stderr | 6 +- .../rustdoc-ui/doc-include-suggestion.stderr | 2 +- tests/rustdoc-ui/lints/doc_cfg_hide.stderr | 8 +- tests/rustdoc-ui/lints/invalid-doc-attr.rs | 2 - .../rustdoc-ui/lints/invalid-doc-attr.stderr | 36 +-- 21 files changed, 377 insertions(+), 135 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 26fb53baf2e4..1fd7b702e92f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -2,7 +2,6 @@ #![allow(unused_imports)] use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit}; -use rustc_errors::MultiSpan; use rustc_feature::template; use rustc_hir::attrs::{ AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow, @@ -18,7 +17,7 @@ use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, PathParser}; use crate::session_diagnostics::{ DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttributeNotAttribute, - DocKeywordConflict, DocKeywordNotKeyword, + DocKeywordNotKeyword, }; fn check_keyword(cx: &mut AcceptContext<'_, '_, S>, keyword: Symbol, span: Span) -> bool { @@ -204,19 +203,7 @@ fn parse_inline<'c, S: Stage>( return; } - let span = path.span(); - - if let Some((prev_inline, prev_span)) = self.attribute.inline { - if prev_inline == inline { - let mut spans = MultiSpan::from_spans(vec![prev_span, span]); - spans.push_span_label(prev_span, fluent::attr_parsing_doc_inline_conflict_first); - spans.push_span_label(span, fluent::attr_parsing_doc_inline_conflict_second); - cx.emit_err(DocKeywordConflict { spans }); - return; - } - } - - self.attribute.inline = Some((inline, span)); + self.attribute.inline.push((inline, path.span())); } fn parse_cfg<'c, S: Stage>( diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 26b615448e3b..38ae597000d2 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -4,7 +4,6 @@ use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, - MultiSpan, }; use rustc_feature::AttributeTemplate; use rustc_hir::AttrPath; @@ -589,14 +588,6 @@ pub(crate) struct DocAliasDuplicated { pub first_defn: Span, } -#[derive(Diagnostic)] -#[diag(attr_parsing_doc_inline_conflict)] -#[help] -pub(crate) struct DocKeywordConflict { - #[primary_span] - pub spans: MultiSpan, -} - #[derive(Diagnostic)] #[diag(attr_parsing_link_ordinal_out_of_range)] #[note] diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 4e1de8e5aeae..0419e219afe4 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -476,7 +476,9 @@ pub struct CfgHideShow { pub struct DocAttribute { pub aliases: FxIndexMap, pub hidden: Option, - pub inline: Option<(DocInline, Span)>, + // Because we need to emit the error if there is more than one `inline` attribute on an item + // at the same time as the other doc attributes, we store a list instead of using `Option`. + pub inline: ThinVec<(DocInline, Span)>, // unstable pub cfg: ThinVec, @@ -511,7 +513,7 @@ fn default() -> Self { Self { aliases: FxIndexMap::default(), hidden: None, - inline: None, + inline: ThinVec::new(), cfg: ThinVec::new(), auto_cfg: ThinVec::new(), auto_cfg_change: ThinVec::new(), diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 9a1cf7f349fd..2069c06c3f77 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -880,7 +880,7 @@ fn analyze_attr(attr: &hir::Attribute, state: &mut AnalyzeAttrState<'_>) -> bool } else if let hir::Attribute::Parsed(AttributeKind::Doc(d)) = attr { // If this is a `doc` attribute that doesn't have anything except maybe `inline` (as in // `#[doc(inline)]`), then we can remove it. It won't be inlinable in downstream crates. - if d.inline.is_none() { + if d.inline.is_empty() { should_encode = true; if d.hidden.is_some() { state.is_doc_hidden = true; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 007ce22c01e6..4e8973e4928b 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -107,10 +107,10 @@ passes_diagnostic_item_first_defined = the diagnostic item is first defined here passes_doc_alias_bad_location = - doc alias attribute isn't allowed on {$location} + `#[doc(alias = "...")]` isn't allowed on {$location} passes_doc_alias_not_an_alias = - {$attr_str} is the same as the item's name + `#[doc(alias = "{$attr_str}"]` is the same as the item's name passes_doc_attr_not_crate_level = `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute @@ -118,7 +118,15 @@ passes_doc_attr_not_crate_level = passes_doc_fake_variadic_not_valid = `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity +passes_doc_inline_conflict = + conflicting doc inlining attributes + .help = remove one of the conflicting attributes +passes_doc_inline_conflict_first = + this attribute... + +passes_doc_inline_conflict_second = + {"."}..conflicts with this attribute passes_doc_inline_only_use = this attribute can only be applied to a `use` item diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index bae15de4bf88..3f29d943e7d3 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -13,13 +13,14 @@ use rustc_ast::{AttrStyle, LitKind, MetaItemKind, ast}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{DiagCtxtHandle, IntoDiagArg, StashKey}; +use rustc_errors::{DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_feature::{ ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, }; use rustc_hir::attrs::{ - AttributeKind, DocAttribute, InlineAttr, MirDialect, MirPhase, ReprAttr, SanitizerSet, + AttributeKind, DocAttribute, DocInline, InlineAttr, MirDialect, MirPhase, ReprAttr, + SanitizerSet, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModDefId; @@ -881,7 +882,24 @@ fn check_doc_search_unbox(&self, span: Span, hir_id: HirId) { /// already seen an inlining attribute for this item. /// If so, `specified_inline` holds the value and the span of /// the first `inline`/`no_inline` attribute. - fn check_doc_inline(&self, span: Span, hir_id: HirId, target: Target) { + fn check_doc_inline(&self, hir_id: HirId, target: Target, inline: &[(DocInline, Span)]) { + let span = match inline { + [] => return, + [(_, span)] => *span, + [(inline, span), rest @ ..] => { + for (inline2, span2) in rest { + if inline2 != inline { + let mut spans = MultiSpan::from_spans(vec![*span, *span2]); + spans.push_span_label(*span, fluent::passes_doc_inline_conflict_first); + spans.push_span_label(*span2, fluent::passes_doc_inline_conflict_second); + self.dcx().emit_err(errors::DocInlineConflict { spans }); + return; + } + } + *span + } + }; + match target { Target::Use | Target::ExternCrate => {} _ => { @@ -1050,9 +1068,7 @@ fn check_doc_attrs(&self, attr: &DocAttribute, hir_id: HirId, target: Target) { } } - if let Some((_, span)) = inline { - self.check_doc_inline(*span, hir_id, target) - } + self.check_doc_inline(hir_id, target, inline); if let Some(span) = rust_logo { if self.check_attr_crate_level(*span, hir_id) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index b693aaf76923..3a2908d14184 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -176,6 +176,14 @@ pub(crate) struct DocSearchUnboxInvalid { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes_doc_inline_conflict)] +#[help] +pub(crate) struct DocInlineConflict { + #[primary_span] + pub spans: MultiSpan, +} + #[derive(LintDiagnostic)] #[diag(passes_doc_inline_only_use)] #[note] diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bea4398ccf86..dd5c50d2ba37 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -199,7 +199,7 @@ fn generate_item_with_correct_attrs( let import_is_inline = find_attr!( inline::load_attrs(cx, import_id.to_def_id()), AttributeKind::Doc(d) - if d.inline.is_some_and(|(inline, _)| inline == DocInline::Inline) + if d.inline.first().is_some_and(|(inline, _)| *inline == DocInline::Inline) ) || (is_glob_import(cx.tcx, import_id) && (cx.document_hidden() || !cx.tcx.is_doc_hidden(def_id))); attrs.extend(get_all_import_attributes(cx, import_id, def_id, is_inline)); @@ -2921,7 +2921,7 @@ fn clean_extern_crate<'tcx>( matches!( a, hir::Attribute::Parsed(AttributeKind::Doc(d)) - if d.inline.is_some_and(|(i, _)| i == DocInline::Inline)) + if d.inline.first().is_some_and(|(i, _)| *i == DocInline::Inline)) }) && !cx.is_json_output(); @@ -2986,9 +2986,9 @@ fn clean_use_statement_inner<'tcx>( let attrs = cx.tcx.hir_attrs(import.hir_id()); let inline_attr = find_attr!( attrs, - AttributeKind::Doc(d) if d.inline.is_some_and(|(i, _)| i == DocInline::Inline) => d + AttributeKind::Doc(d) if d.inline.first().is_some_and(|(i, _)| *i == DocInline::Inline) => d ) - .and_then(|d| d.inline); + .and_then(|d| d.inline.first()); let pub_underscore = visibility.is_public() && name == Some(kw::Underscore); let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id); let import_def_id = import.owner_id.def_id; @@ -3009,7 +3009,7 @@ fn clean_use_statement_inner<'tcx>( if pub_underscore && let Some((_, inline_span)) = inline_attr { struct_span_code_err!( cx.tcx.dcx(), - inline_span, + *inline_span, E0780, "anonymous imports cannot be inlined" ) @@ -3026,7 +3026,9 @@ fn clean_use_statement_inner<'tcx>( || pub_underscore || attrs.iter().any(|a| matches!( a, - hir::Attribute::Parsed(AttributeKind::Doc(d)) if d.hidden.is_some() || d.inline.is_some_and(|(i, _)| i == DocInline::NoInline))); + hir::Attribute::Parsed(AttributeKind::Doc(d)) + if d.hidden.is_some() || d.inline.first().is_some_and(|(i, _)| *i == DocInline::NoInline) + )); // Also check whether imports were asked to be inlined, in case we're trying to re-export a // crate in Rust 2018+ diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index a0e359032f9b..13be1a04dbc5 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -32,6 +32,7 @@ extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_ast_pretty; +extern crate rustc_attr_parsing; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; @@ -75,6 +76,7 @@ use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::lints::DelayedLint; use rustc_interface::interface; use rustc_middle::ty::TyCtxt; use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option}; @@ -900,6 +902,18 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { return; } + for owner_id in tcx.hir_crate_items(()).delayed_lint_items() { + if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) { + for lint in &delayed_lints.lints { + match lint { + DelayedLint::AttributeParsing(attribute_lint) => { + rustc_attr_parsing::emit_attribute_lint(attribute_lint, tcx) + } + } + } + } + } + if render_opts.dep_info().is_some() { rustc_interface::passes::write_dep_info(tcx); } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index d6da8615d57e..0f4460bed35a 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -247,8 +247,12 @@ fn maybe_inline_local( let document_hidden = self.cx.document_hidden(); let use_attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); // Don't inline `doc(hidden)` imports so they can be stripped at a later stage. - let is_no_inline = find_attr!(use_attrs, AttributeKind::Doc(d) if d.inline.is_some_and(|(inline, _)| inline == DocInline::NoInline)) - || (document_hidden && use_attrs.iter().any(|attr| attr.is_doc_hidden())); + let is_no_inline = find_attr!( + use_attrs, + AttributeKind::Doc(d) + if d.inline.first().is_some_and(|(inline, _)| *inline == DocInline::NoInline) + ) || (document_hidden + && use_attrs.iter().any(|attr| attr.is_doc_hidden())); if is_no_inline { return false; @@ -465,7 +469,11 @@ fn visit_item_inner( // If there was a private module in the current path then don't bother inlining // anything as it will probably be stripped anyway. if is_pub && self.inside_public_path { - let please_inline = find_attr!(attrs, AttributeKind::Doc(d) if d.inline.is_some_and(|(inline, _)| inline == DocInline::Inline)); + let please_inline = find_attr!( + attrs, + AttributeKind::Doc(d) + if d.inline.first().is_some_and(|(inline, _)| *inline == DocInline::Inline) + ); let ident = match kind { hir::UseKind::Single(ident) => Some(ident.name), hir::UseKind::Glob => None, diff --git a/tests/rustdoc-ui/bad-render-options.rs b/tests/rustdoc-ui/bad-render-options.rs index f2cfd4b76fa8..0522f68cb6c2 100644 --- a/tests/rustdoc-ui/bad-render-options.rs +++ b/tests/rustdoc-ui/bad-render-options.rs @@ -1,11 +1,29 @@ // regression test for https://github.com/rust-lang/rust/issues/149187 -#![doc(html_favicon_url)] //~ ERROR: `doc(html_favicon_url)` expects a string value [invalid_doc_attributes] -#![doc(html_logo_url)] //~ ERROR: `doc(html_logo_url)` expects a string value [invalid_doc_attributes] -#![doc(html_playground_url)] //~ ERROR: `doc(html_playground_url)` expects a string value [invalid_doc_attributes] -#![doc(issue_tracker_base_url)] //~ ERROR expects a string value -#![doc(html_favicon_url = 1)] //~ ERROR expects a string value -#![doc(html_logo_url = 2)] //~ ERROR expects a string value -#![doc(html_playground_url = 3)] //~ ERROR expects a string value -#![doc(issue_tracker_base_url = 4)] //~ ERROR expects a string value -#![doc(html_no_source = "asdf")] //~ ERROR `doc(html_no_source)` does not accept a value [invalid_doc_attributes] +#![doc(html_favicon_url)] +//~^ ERROR: malformed `doc` attribute +//~| NOTE expected this to be of the form `html_favicon_url = "..."` +#![doc(html_logo_url)] +//~^ ERROR: malformed `doc` attribute +//~| NOTE expected this to be of the form `html_logo_url = "..."` +#![doc(html_playground_url)] +//~^ ERROR: malformed `doc` attribute +//~| NOTE expected this to be of the form `html_playground_url = "..."` +#![doc(issue_tracker_base_url)] +//~^ ERROR: malformed `doc` attribute +//~| NOTE expected this to be of the form `issue_tracker_base_url = "..."` +#![doc(html_favicon_url = 1)] +//~^ ERROR malformed `doc` attribute +//~| NOTE expected a string literal +#![doc(html_logo_url = 2)] +//~^ ERROR malformed `doc` attribute +//~| NOTE expected a string literal +#![doc(html_playground_url = 3)] +//~^ ERROR malformed `doc` attribute +//~| NOTE expected a string literal +#![doc(issue_tracker_base_url = 4)] +//~^ ERROR malformed `doc` attribute +//~| NOTE expected a string literal +#![doc(html_no_source = "asdf")] +//~^ ERROR malformed `doc` attribute +//~| NOTE didn't expect any arguments here diff --git a/tests/rustdoc-ui/bad-render-options.stderr b/tests/rustdoc-ui/bad-render-options.stderr index 9d503363c0bd..e7f33f4dff1d 100644 --- a/tests/rustdoc-ui/bad-render-options.stderr +++ b/tests/rustdoc-ui/bad-render-options.stderr @@ -1,58 +1,211 @@ -error: `doc(html_favicon_url)` expects a string value - --> $DIR/bad-render-options.rs:3:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:3:1 | LL | #![doc(html_favicon_url)] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^----------------^^ + | | + | expected this to be of the form `html_favicon_url = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_favicon_url)] +LL + #![doc = "string"] + | +LL - #![doc(html_favicon_url)] +LL + #![doc(hidden)] + | +LL - #![doc(html_favicon_url)] +LL + #![doc(inline)] + | +LL - #![doc(html_favicon_url)] +LL + #![doc(test)] | - = note: `#[deny(invalid_doc_attributes)]` on by default -error: `doc(html_logo_url)` expects a string value - --> $DIR/bad-render-options.rs:4:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:6:1 | LL | #![doc(html_logo_url)] - | ^^^^^^^^^^^^^ + | ^^^^^^^-------------^^ + | | + | expected this to be of the form `html_logo_url = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_logo_url)] +LL + #![doc = "string"] + | +LL - #![doc(html_logo_url)] +LL + #![doc(hidden)] + | +LL - #![doc(html_logo_url)] +LL + #![doc(inline)] + | +LL - #![doc(html_logo_url)] +LL + #![doc(test)] + | -error: `doc(html_playground_url)` expects a string value - --> $DIR/bad-render-options.rs:5:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:9:1 | LL | #![doc(html_playground_url)] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^-------------------^^ + | | + | expected this to be of the form `html_playground_url = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_playground_url)] +LL + #![doc = "string"] + | +LL - #![doc(html_playground_url)] +LL + #![doc(hidden)] + | +LL - #![doc(html_playground_url)] +LL + #![doc(inline)] + | +LL - #![doc(html_playground_url)] +LL + #![doc(test)] + | -error: `doc(issue_tracker_base_url)` expects a string value - --> $DIR/bad-render-options.rs:6:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:12:1 | LL | #![doc(issue_tracker_base_url)] - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^----------------------^^ + | | + | expected this to be of the form `issue_tracker_base_url = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(issue_tracker_base_url)] +LL + #![doc = "string"] + | +LL - #![doc(issue_tracker_base_url)] +LL + #![doc(hidden)] + | +LL - #![doc(issue_tracker_base_url)] +LL + #![doc(inline)] + | +LL - #![doc(issue_tracker_base_url)] +LL + #![doc(test)] + | -error: `doc(html_favicon_url)` expects a string value - --> $DIR/bad-render-options.rs:7:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:15:1 | LL | #![doc(html_favicon_url = 1)] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_favicon_url = 1)] +LL + #![doc = "string"] + | +LL - #![doc(html_favicon_url = 1)] +LL + #![doc(hidden)] + | +LL - #![doc(html_favicon_url = 1)] +LL + #![doc(inline)] + | +LL - #![doc(html_favicon_url = 1)] +LL + #![doc(test)] + | -error: `doc(html_logo_url)` expects a string value - --> $DIR/bad-render-options.rs:8:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:18:1 | LL | #![doc(html_logo_url = 2)] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_logo_url = 2)] +LL + #![doc = "string"] + | +LL - #![doc(html_logo_url = 2)] +LL + #![doc(hidden)] + | +LL - #![doc(html_logo_url = 2)] +LL + #![doc(inline)] + | +LL - #![doc(html_logo_url = 2)] +LL + #![doc(test)] + | -error: `doc(html_playground_url)` expects a string value - --> $DIR/bad-render-options.rs:9:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:21:1 | LL | #![doc(html_playground_url = 3)] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_playground_url = 3)] +LL + #![doc = "string"] + | +LL - #![doc(html_playground_url = 3)] +LL + #![doc(hidden)] + | +LL - #![doc(html_playground_url = 3)] +LL + #![doc(inline)] + | +LL - #![doc(html_playground_url = 3)] +LL + #![doc(test)] + | -error: `doc(issue_tracker_base_url)` expects a string value - --> $DIR/bad-render-options.rs:10:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:24:1 | LL | #![doc(issue_tracker_base_url = 4)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(issue_tracker_base_url = 4)] +LL + #![doc = "string"] + | +LL - #![doc(issue_tracker_base_url = 4)] +LL + #![doc(hidden)] + | +LL - #![doc(issue_tracker_base_url = 4)] +LL + #![doc(inline)] + | +LL - #![doc(issue_tracker_base_url = 4)] +LL + #![doc(test)] + | -error: `doc(html_no_source)` does not accept a value - --> $DIR/bad-render-options.rs:11:8 +error[E0565]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:27:1 | LL | #![doc(html_no_source = "asdf")] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^--------^^ + | | + | didn't expect any arguments here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_no_source = "asdf")] +LL + #![doc = "string"] + | +LL - #![doc(html_no_source = "asdf")] +LL + #![doc(hidden)] + | +LL - #![doc(html_no_source = "asdf")] +LL + #![doc(inline)] + | +LL - #![doc(html_no_source = "asdf")] +LL + #![doc(test)] + | error: aborting due to 9 previous errors +Some errors have detailed explanations: E0539, E0565. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/rustdoc-ui/cfg-hide-show-conflict.stderr b/tests/rustdoc-ui/cfg-hide-show-conflict.stderr index 22231e82cd7b..384a9f1a0b1f 100644 --- a/tests/rustdoc-ui/cfg-hide-show-conflict.stderr +++ b/tests/rustdoc-ui/cfg-hide-show-conflict.stderr @@ -1,14 +1,14 @@ error: same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item - --> $DIR/cfg-hide-show-conflict.rs:3:31 + --> $DIR/cfg-hide-show-conflict.rs:3:8 | LL | #![doc(auto_cfg(show(windows, target_os = "linux")))] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | note: first change was here - --> $DIR/cfg-hide-show-conflict.rs:2:22 + --> $DIR/cfg-hide-show-conflict.rs:2:8 | LL | #![doc(auto_cfg(hide(target_os = "linux")))] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/check-doc-alias-attr-location.stderr b/tests/rustdoc-ui/check-doc-alias-attr-location.stderr index 85c9516236c9..b8e1863ce560 100644 --- a/tests/rustdoc-ui/check-doc-alias-attr-location.stderr +++ b/tests/rustdoc-ui/check-doc-alias-attr-location.stderr @@ -1,26 +1,26 @@ error: `#[doc(alias = "...")]` isn't allowed on foreign module - --> $DIR/check-doc-alias-attr-location.rs:7:7 + --> $DIR/check-doc-alias-attr-location.rs:7:15 | LL | #[doc(alias = "foo")] - | ^^^^^^^^^^^^^ + | ^^^^^ error: `#[doc(alias = "...")]` isn't allowed on implementation block - --> $DIR/check-doc-alias-attr-location.rs:10:7 + --> $DIR/check-doc-alias-attr-location.rs:10:15 | LL | #[doc(alias = "bar")] - | ^^^^^^^^^^^^^ + | ^^^^^ error: `#[doc(alias = "...")]` isn't allowed on implementation block - --> $DIR/check-doc-alias-attr-location.rs:16:7 + --> $DIR/check-doc-alias-attr-location.rs:16:15 | LL | #[doc(alias = "foobar")] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on type alias in implementation block - --> $DIR/check-doc-alias-attr-location.rs:18:11 + --> $DIR/check-doc-alias-attr-location.rs:18:19 | LL | #[doc(alias = "assoc")] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/rustdoc-ui/check-doc-alias-attr.stderr b/tests/rustdoc-ui/check-doc-alias-attr.stderr index 250568be3333..06d5c6535191 100644 --- a/tests/rustdoc-ui/check-doc-alias-attr.stderr +++ b/tests/rustdoc-ui/check-doc-alias-attr.stderr @@ -4,11 +4,28 @@ error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of s LL | #[doc(alias)] | ^^^^^ -error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` - --> $DIR/check-doc-alias-attr.rs:8:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/check-doc-alias-attr.rs:8:1 | LL | #[doc(alias = 0)] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(alias = 0)] +LL + #[doc = "string"] + | +LL - #[doc(alias = 0)] +LL + #[doc(hidden)] + | +LL - #[doc(alias = 0)] +LL + #[doc(inline)] + | +LL - #[doc(alias = 0)] +LL + #[doc(test)] + | error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:9:15 @@ -54,25 +71,42 @@ error: `#[doc(alias = "...")]` attribute cannot have empty value LL | #[doc(alias = "")] | ^^ -error: `#[doc(alias("a"))]` expects string literals - --> $DIR/check-doc-alias-attr.rs:19:13 +error[E0539]: malformed `doc` attribute input + --> $DIR/check-doc-alias-attr.rs:19:1 | LL | #[doc(alias(0))] - | ^ + | ^^^^^^^^^^^^-^^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(alias(0))] +LL + #[doc = "string"] + | +LL - #[doc(alias(0))] +LL + #[doc(hidden)] + | +LL - #[doc(alias(0))] +LL + #[doc(inline)] + | +LL - #[doc(alias(0))] +LL + #[doc(test)] + | -error: '"' character isn't allowed in `#[doc(alias("..."))]` +error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:20:13 | LL | #[doc(alias("\""))] | ^^^^ -error: '\n' character isn't allowed in `#[doc(alias("..."))]` +error: '\n' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:21:13 | LL | #[doc(alias("\n"))] | ^^^^ -error: '\n' character isn't allowed in `#[doc(alias("..."))]` +error: '\n' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:22:13 | LL | #[doc(alias(" @@ -80,25 +114,25 @@ LL | #[doc(alias(" LL | | "))] | |_^ -error: '\t' character isn't allowed in `#[doc(alias("..."))]` +error: '\t' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:24:13 | LL | #[doc(alias("\t"))] | ^^^^ -error: `#[doc(alias("..."))]` cannot start or end with ' ' +error: `#[doc(alias = "...")]` cannot start or end with ' ' --> $DIR/check-doc-alias-attr.rs:25:13 | LL | #[doc(alias(" hello"))] | ^^^^^^^^ -error: `#[doc(alias("..."))]` cannot start or end with ' ' +error: `#[doc(alias = "...")]` cannot start or end with ' ' --> $DIR/check-doc-alias-attr.rs:26:13 | LL | #[doc(alias("hello "))] | ^^^^^^^^ -error: `#[doc(alias("..."))]` attribute cannot have empty value +error: `#[doc(alias = "...")]` attribute cannot have empty value --> $DIR/check-doc-alias-attr.rs:27:13 | LL | #[doc(alias(""))] @@ -106,3 +140,4 @@ LL | #[doc(alias(""))] error: aborting due to 17 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/rustdoc-ui/doc-alias-assoc-const.stderr b/tests/rustdoc-ui/doc-alias-assoc-const.stderr index cc628c39400b..7566ec840da7 100644 --- a/tests/rustdoc-ui/doc-alias-assoc-const.stderr +++ b/tests/rustdoc-ui/doc-alias-assoc-const.stderr @@ -1,8 +1,8 @@ error: `#[doc(alias = "...")]` isn't allowed on associated constant in trait implementation block - --> $DIR/doc-alias-assoc-const.rs:8:11 + --> $DIR/doc-alias-assoc-const.rs:8:19 | LL | #[doc(alias = "CONST_BAZ")] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/doc-alias-same-name.stderr b/tests/rustdoc-ui/doc-alias-same-name.stderr index a9da75c0171c..a76ff5ee0b67 100644 --- a/tests/rustdoc-ui/doc-alias-same-name.stderr +++ b/tests/rustdoc-ui/doc-alias-same-name.stderr @@ -1,8 +1,8 @@ -error: `#[doc(alias = "...")]` is the same as the item's name - --> $DIR/doc-alias-same-name.rs:3:7 +error: `#[doc(alias = "Foo"]` is the same as the item's name + --> $DIR/doc-alias-same-name.rs:3:15 | LL | #[doc(alias = "Foo")] - | ^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/doc-include-suggestion.stderr b/tests/rustdoc-ui/doc-include-suggestion.stderr index 1b4b78a8f263..ea5261e5bbd4 100644 --- a/tests/rustdoc-ui/doc-include-suggestion.stderr +++ b/tests/rustdoc-ui/doc-include-suggestion.stderr @@ -2,7 +2,7 @@ error: unknown `doc` attribute `include` --> $DIR/doc-include-suggestion.rs:1:7 | LL | #[doc(include = "external-cross-doc.md")] - | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]` + | ^^^^^^^ help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]` | = note: `#[deny(invalid_doc_attributes)]` on by default diff --git a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr index c63c8d607fa0..acbe6ef69dd5 100644 --- a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr +++ b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr @@ -1,16 +1,16 @@ error: `#![doc(auto_cfg(hide(...)))]` expects a list of items - --> $DIR/doc_cfg_hide.rs:2:8 + --> $DIR/doc_cfg_hide.rs:2:17 | LL | #![doc(auto_cfg(hide = "test"))] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = note: `#[deny(invalid_doc_attributes)]` on by default error: `#![doc(auto_cfg(hide(...)))]` expects a list of items - --> $DIR/doc_cfg_hide.rs:3:8 + --> $DIR/doc_cfg_hide.rs:3:17 | LL | #![doc(auto_cfg(hide))] - | ^^^^^^^^^^^^^^ + | ^^^^ error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items --> $DIR/doc_cfg_hide.rs:4:22 diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.rs b/tests/rustdoc-ui/lints/invalid-doc-attr.rs index e1cc08ca2427..a8c42b8fd79c 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.rs +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.rs @@ -6,8 +6,6 @@ #[doc(test(no_crate_inject))] //~^ ERROR can only be applied at the crate level -//~| HELP to apply to the crate, use an inner attribute -//~| SUGGESTION ! #[doc(inline)] //~^ ERROR can only be applied to a `use` item pub fn foo() {} diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr index 7621999a8ca5..82e1b62b57a6 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr @@ -1,18 +1,14 @@ error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:7:7 + --> $DIR/invalid-doc-attr.rs:7:12 | LL | #[doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: read for more information = note: `#[deny(invalid_doc_attributes)]` on by default -help: to apply to the crate, use an inner attribute - | -LL | #![doc(test(no_crate_inject))] - | + error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:11:7 + --> $DIR/invalid-doc-attr.rs:9:7 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -23,15 +19,15 @@ LL | pub fn foo() {} = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:16:12 + --> $DIR/invalid-doc-attr.rs:14:17 | LL | #![doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: read for more information error: conflicting doc inlining attributes - --> $DIR/invalid-doc-attr.rs:26:7 + --> $DIR/invalid-doc-attr.rs:24:7 | LL | #[doc(inline)] | ^^^^^^ this attribute... @@ -41,7 +37,7 @@ LL | #[doc(no_inline)] = help: remove one of the conflicting attributes error: this attribute can only be applied to an `extern crate` item - --> $DIR/invalid-doc-attr.rs:32:7 + --> $DIR/invalid-doc-attr.rs:30:7 | LL | #[doc(masked)] | ^^^^^^ only applicable on `extern crate` items @@ -52,7 +48,7 @@ LL | pub struct Masked; = note: read for more information error: this attribute cannot be applied to an `extern crate self` item - --> $DIR/invalid-doc-attr.rs:36:7 + --> $DIR/invalid-doc-attr.rs:34:7 | LL | #[doc(masked)] | ^^^^^^ not applicable on `extern crate self` items @@ -63,21 +59,27 @@ LL | pub extern crate self as reexport; error: this attribute can only be applied to an `extern crate` item --> $DIR/invalid-doc-attr.rs:4:8 | -LL | #![doc(masked)] - | ^^^^^^ only applicable on `extern crate` items +LL | / #![crate_type = "lib"] +LL | | #![feature(doc_masked)] +LL | | +LL | | #![doc(masked)] + | | ^^^^^^ only applicable on `extern crate` items +... | +LL | | pub extern crate self as reexport; + | |__________________________________- not an `extern crate` item | = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:19:11 + --> $DIR/invalid-doc-attr.rs:17:16 | LL | #[doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: read for more information error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:21:11 + --> $DIR/invalid-doc-attr.rs:19:11 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items From d1277ccffaff214fb6127930c70f29744e40a877 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Dec 2025 12:58:31 +0100 Subject: [PATCH 466/585] Update `check_doc_cfg` pass in rustdoc, remove old `rustc_attr_parsing::cfg_matches` API --- .../src/attributes/cfg_old.rs | 40 ------- src/librustdoc/passes/check_doc_cfg.rs | 100 +++++++++--------- 2 files changed, 49 insertions(+), 91 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs index adae3fa635f4..29be000d476d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs @@ -4,8 +4,6 @@ use rustc_hir::RustcVersion; use rustc_hir::lints::AttributeLintKind; 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}; @@ -37,44 +35,6 @@ pub struct Condition { 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::AttributeLint(AttributeLintKind::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::AttributeLint(AttributeLintKind::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) { diff --git a/src/librustdoc/passes/check_doc_cfg.rs b/src/librustdoc/passes/check_doc_cfg.rs index 63dc375a13c6..9e7fae5e14e4 100644 --- a/src/librustdoc/passes/check_doc_cfg.rs +++ b/src/librustdoc/passes/check_doc_cfg.rs @@ -1,9 +1,8 @@ -#![allow(dead_code, unused_imports)] - -use rustc_hir::HirId; +use rustc_attr_parsing::{ShouldEmit, eval_config_entry}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::LocalDefId; +use rustc_hir::{Attribute, HirId}; use rustc_middle::ty::TyCtxt; -use rustc_span::sym; use super::Pass; use crate::clean::{Attributes, Crate, Item}; @@ -16,59 +15,58 @@ description: "checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs", }; -pub(crate) fn check_doc_cfg(krate: Crate, _cx: &mut DocContext<'_>) -> Crate { - // let mut checker = DocCfgChecker { cx }; - // checker.visit_crate(&krate); +pub(crate) fn check_doc_cfg(krate: Crate, cx: &mut DocContext<'_>) -> Crate { + let mut checker = DocCfgChecker { cx }; + checker.visit_crate(&krate); krate } -// struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, HirId); +struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, HirId); -// impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> { -// fn emit_span_lint( -// &self, -// sess: &rustc_session::Session, -// lint: &'static rustc_lint::Lint, -// sp: rustc_span::Span, -// builtin_diag: rustc_lint_defs::BuiltinLintDiag, -// ) { -// self.0.node_span_lint(lint, self.1, sp, |diag| { -// rustc_lint::decorate_builtin_lint(sess, Some(self.0), builtin_diag, diag) -// }); -// } -// } +impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> { + fn emit_span_lint( + &self, + sess: &rustc_session::Session, + lint: &'static rustc_lint::Lint, + sp: rustc_span::Span, + builtin_diag: rustc_lint_defs::BuiltinLintDiag, + ) { + self.0.node_span_lint(lint, self.1, sp, |diag| { + rustc_lint::decorate_builtin_lint(sess, Some(self.0), builtin_diag, diag) + }); + } +} -// struct DocCfgChecker<'a, 'tcx> { -// cx: &'a mut DocContext<'tcx>, -// } +struct DocCfgChecker<'a, 'tcx> { + cx: &'a mut DocContext<'tcx>, +} -// impl DocCfgChecker<'_, '_> { -// fn check_attrs(&mut self, attrs: &Attributes, did: LocalDefId) { -// for attr in &attrs.other_attrs { -// let Attribute::Parsed(AttributeKind::Doc(d)) = attr else { continue }; -// let Some(doc_cfg) = d.cfg else { continue }; +impl DocCfgChecker<'_, '_> { + fn check_attrs(&mut self, attrs: &Attributes, did: LocalDefId) { + for attr in &attrs.other_attrs { + let Attribute::Parsed(AttributeKind::Doc(d)) = attr else { continue }; -// if let Some([cfg_mi]) = doc_cfg.meta_item_list() { -// let _ = rustc_attr_parsing::cfg_matches( -// cfg_mi, -// &self.cx.tcx.sess, -// RustdocCfgMatchesLintEmitter( -// self.cx.tcx, -// self.cx.tcx.local_def_id_to_hir_id(did), -// ), -// Some(self.cx.tcx.features()), -// ); -// } -// } -// } -// } + for doc_cfg in &d.cfg { + let _ = eval_config_entry( + &self.cx.tcx.sess, + doc_cfg, + &RustdocCfgMatchesLintEmitter( + self.cx.tcx, + self.cx.tcx.local_def_id_to_hir_id(did), + ), + ShouldEmit::ErrorsAndLints, + ); + } + } + } +} -// impl DocVisitor<'_> for DocCfgChecker<'_, '_> { -// fn visit_item(&mut self, item: &'_ Item) { -// if let Some(Some(local_did)) = item.def_id().map(|did| did.as_local()) { -// self.check_attrs(&item.attrs, local_did); -// } +impl DocVisitor<'_> for DocCfgChecker<'_, '_> { + fn visit_item(&mut self, item: &'_ Item) { + if let Some(Some(local_did)) = item.def_id().map(|did| did.as_local()) { + self.check_attrs(&item.attrs, local_did); + } -// self.visit_item_recur(item); -// } -// } + self.visit_item_recur(item); + } +} From e4f57dd4b3f3f4dc0bd6c4b2484526375ef3c5cf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Dec 2025 15:48:56 +0100 Subject: [PATCH 467/585] Finish fixing ui tests --- .../rustc_attr_parsing/src/attributes/doc.rs | 7 +- compiler/rustc_attr_parsing/src/lib.rs | 1 + tests/rustdoc-ui/deprecated-attrs.stderr | 4 +- tests/rustdoc-ui/doc-alias-crate-level.rs | 3 - tests/rustdoc-ui/doc-alias-crate-level.stderr | 12 +- tests/rustdoc-ui/doc-alias.rs | 2 + tests/rustdoc-ui/doc-alias.stderr | 8 + tests/rustdoc-ui/doc-cfg-2.rs | 16 ++ tests/rustdoc-ui/doc-cfg-2.stderr | 60 ++++++ tests/rustdoc-ui/doc-cfg.rs | 17 +- tests/rustdoc-ui/doc-cfg.stderr | 183 ++++++++++-------- tests/rustdoc-ui/doctest/doc-test-attr.stderr | 4 +- tests/rustdoc-ui/invalid-cfg.rs | 16 +- tests/rustdoc-ui/invalid-cfg.stderr | 178 ++++++++++++++--- tests/rustdoc-ui/lints/doc-attr-2.rs | 11 ++ tests/rustdoc-ui/lints/doc-attr-2.stderr | 28 +++ tests/rustdoc-ui/lints/doc-attr.rs | 15 +- tests/rustdoc-ui/lints/doc-attr.stderr | 92 +++++---- 18 files changed, 471 insertions(+), 186 deletions(-) create mode 100644 tests/rustdoc-ui/doc-alias.rs create mode 100644 tests/rustdoc-ui/doc-alias.stderr create mode 100644 tests/rustdoc-ui/doc-cfg-2.rs create mode 100644 tests/rustdoc-ui/doc-cfg-2.stderr create mode 100644 tests/rustdoc-ui/lints/doc-attr-2.rs create mode 100644 tests/rustdoc-ui/lints/doc-attr-2.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 1fd7b702e92f..2e8249fb35be 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -442,7 +442,12 @@ macro_rules! string_arg { cx.emit_lint(AttributeLintKind::DocUnknownAny { name }, path.span()); } None => { - // FIXME: is there anything to do in this case? + let full_name = + path.segments().map(|s| s.as_str()).intersperse("::").collect::(); + cx.emit_lint( + AttributeLintKind::DocUnknownAny { name: Symbol::intern(&full_name) }, + path.span(), + ); } } } diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 37a3189f892e..3e9d8087a192 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -81,6 +81,7 @@ #![recursion_limit = "256"] // tidy-alphabetical-end #![feature(if_let_guard)] +#![feature(iter_intersperse)] #[macro_use] /// All the individual attribute parsers for each of rustc's built-in attributes. diff --git a/tests/rustdoc-ui/deprecated-attrs.stderr b/tests/rustdoc-ui/deprecated-attrs.stderr index 323257f944ce..6135b1496925 100644 --- a/tests/rustdoc-ui/deprecated-attrs.stderr +++ b/tests/rustdoc-ui/deprecated-attrs.stderr @@ -17,7 +17,7 @@ error: unknown `doc` attribute `passes` --> $DIR/deprecated-attrs.rs:9:8 | LL | #![doc(passes = "collapse-docs unindent-comments")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no longer functions + | ^^^^^^ no longer functions | = note: `doc` attribute `passes` no longer functions; see issue #44136 = note: `doc(passes)` is now a no-op @@ -26,7 +26,7 @@ error: unknown `doc` attribute `plugins` --> $DIR/deprecated-attrs.rs:14:8 | LL | #![doc(plugins = "xxx")] - | ^^^^^^^^^^^^^^^ no longer functions + | ^^^^^^^ no longer functions | = note: `doc` attribute `plugins` no longer functions; see issue #44136 and CVE-2018-1000622 = note: `doc(plugins)` is now a no-op diff --git a/tests/rustdoc-ui/doc-alias-crate-level.rs b/tests/rustdoc-ui/doc-alias-crate-level.rs index 70618ac01dfb..9ba7a63d7f10 100644 --- a/tests/rustdoc-ui/doc-alias-crate-level.rs +++ b/tests/rustdoc-ui/doc-alias-crate-level.rs @@ -1,4 +1 @@ #![doc(alias = "crate-level-not-working")] //~ ERROR - -#[doc(alias = "shouldn't work!")] //~ ERROR -pub fn foo() {} diff --git a/tests/rustdoc-ui/doc-alias-crate-level.stderr b/tests/rustdoc-ui/doc-alias-crate-level.stderr index fc8095e03ca9..1742118a67c1 100644 --- a/tests/rustdoc-ui/doc-alias-crate-level.stderr +++ b/tests/rustdoc-ui/doc-alias-crate-level.stderr @@ -1,14 +1,8 @@ -error: '\'' character isn't allowed in `#[doc(alias = "...")]` - --> $DIR/doc-alias-crate-level.rs:3:15 - | -LL | #[doc(alias = "shouldn't work!")] - | ^^^^^^^^^^^^^^^^^ - error: `#![doc(alias = "...")]` isn't allowed as a crate-level attribute - --> $DIR/doc-alias-crate-level.rs:1:8 + --> $DIR/doc-alias-crate-level.rs:1:16 | LL | #![doc(alias = "crate-level-not-working")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/doc-alias.rs b/tests/rustdoc-ui/doc-alias.rs new file mode 100644 index 000000000000..ae2a5b387191 --- /dev/null +++ b/tests/rustdoc-ui/doc-alias.rs @@ -0,0 +1,2 @@ +#[doc(alias = "shouldn't work!")] //~ ERROR +pub fn foo() {} diff --git a/tests/rustdoc-ui/doc-alias.stderr b/tests/rustdoc-ui/doc-alias.stderr new file mode 100644 index 000000000000..1b3cc9426947 --- /dev/null +++ b/tests/rustdoc-ui/doc-alias.stderr @@ -0,0 +1,8 @@ +error: '\'' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/doc-alias.rs:1:15 + | +LL | #[doc(alias = "shouldn't work!")] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/rustdoc-ui/doc-cfg-2.rs b/tests/rustdoc-ui/doc-cfg-2.rs new file mode 100644 index 000000000000..bd6a2dc18be9 --- /dev/null +++ b/tests/rustdoc-ui/doc-cfg-2.rs @@ -0,0 +1,16 @@ +#![feature(doc_cfg)] + +#[doc(cfg(foo), cfg(bar))] +//~^ WARN unexpected `cfg` condition name: `foo` +//~| WARN unexpected `cfg` condition name: `bar` +#[doc(auto_cfg(42))] //~ ERROR +#[doc(auto_cfg(hide(true)))] //~ ERROR +#[doc(auto_cfg(hide(42)))] //~ ERROR +#[doc(auto_cfg(hide("a")))] //~ ERROR +#[doc(auto_cfg = 42)] //~ ERROR +#[doc(auto_cfg = "a")] //~ ERROR +// Shouldn't lint +#[doc(auto_cfg(hide(windows)))] +#[doc(auto_cfg(hide(feature = "windows")))] +#[doc(auto_cfg(hide(foo)))] +pub fn foo() {} diff --git a/tests/rustdoc-ui/doc-cfg-2.stderr b/tests/rustdoc-ui/doc-cfg-2.stderr new file mode 100644 index 000000000000..f3d67abfb8dd --- /dev/null +++ b/tests/rustdoc-ui/doc-cfg-2.stderr @@ -0,0 +1,60 @@ +warning: unexpected `cfg` condition name: `foo` + --> $DIR/doc-cfg-2.rs:3:11 + | +LL | #[doc(cfg(foo), cfg(bar))] + | ^^^ + | + = help: expected names are: `FALSE` and `test` and 31 more + = help: to expect this configuration use `--check-cfg=cfg(foo)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name: `bar` + --> $DIR/doc-cfg-2.rs:3:21 + | +LL | #[doc(cfg(foo), cfg(bar))] + | ^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(bar)` + = note: see for more information about checking conditional configuration + +error: only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` + --> $DIR/doc-cfg-2.rs:6:16 + | +LL | #[doc(auto_cfg(42))] + | ^^ + | + = note: `#[deny(invalid_doc_attributes)]` on by default + +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg-2.rs:7:21 + | +LL | #[doc(auto_cfg(hide(true)))] + | ^^^^ + +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg-2.rs:8:21 + | +LL | #[doc(auto_cfg(hide(42)))] + | ^^ + +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg-2.rs:9:21 + | +LL | #[doc(auto_cfg(hide("a")))] + | ^^^ + +error: expected boolean for `#[doc(auto_cfg = ...)]` + --> $DIR/doc-cfg-2.rs:10:18 + | +LL | #[doc(auto_cfg = 42)] + | ^^ + +error: expected boolean for `#[doc(auto_cfg = ...)]` + --> $DIR/doc-cfg-2.rs:11:18 + | +LL | #[doc(auto_cfg = "a")] + | ^^^ + +error: aborting due to 6 previous errors; 2 warnings emitted + diff --git a/tests/rustdoc-ui/doc-cfg.rs b/tests/rustdoc-ui/doc-cfg.rs index d72643e23556..f30d80aa9cda 100644 --- a/tests/rustdoc-ui/doc-cfg.rs +++ b/tests/rustdoc-ui/doc-cfg.rs @@ -1,22 +1,9 @@ #![feature(doc_cfg)] #[doc(cfg(), cfg(foo, bar))] -//~^ ERROR -//~^^ ERROR -#[doc(cfg(foo), cfg(bar))] -//~^ WARN unexpected `cfg` condition name: `foo` -//~^^ WARN unexpected `cfg` condition name: `bar` +//~^ ERROR malformed `doc` attribute input +//~| ERROR malformed `doc` attribute input #[doc(cfg())] //~ ERROR #[doc(cfg(foo, bar))] //~ ERROR -#[doc(auto_cfg(42))] //~ ERROR -#[doc(auto_cfg(hide(true)))] //~ ERROR -#[doc(auto_cfg(hide(42)))] //~ ERROR -#[doc(auto_cfg(hide("a")))] //~ ERROR #[doc(auto_cfg(hide(foo::bar)))] //~ ERROR -#[doc(auto_cfg = 42)] //~ ERROR -#[doc(auto_cfg = "a")] //~ ERROR -// Shouldn't lint -#[doc(auto_cfg(hide(windows)))] -#[doc(auto_cfg(hide(feature = "windows")))] -#[doc(auto_cfg(hide(foo)))] pub fn foo() {} diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr index 49e8c324facf..a4c6584d3294 100644 --- a/tests/rustdoc-ui/doc-cfg.stderr +++ b/tests/rustdoc-ui/doc-cfg.stderr @@ -1,90 +1,119 @@ -error: only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` - --> $DIR/doc-cfg.rs:11:7 - | -LL | #[doc(auto_cfg(42))] - | ^^^^^^^^^^^^ - | - = note: `#[deny(invalid_doc_attributes)]` on by default - -error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items - --> $DIR/doc-cfg.rs:12:21 - | -LL | #[doc(auto_cfg(hide(true)))] - | ^^^^ - -error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items - --> $DIR/doc-cfg.rs:13:21 - | -LL | #[doc(auto_cfg(hide(42)))] - | ^^ - -error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items - --> $DIR/doc-cfg.rs:14:21 - | -LL | #[doc(auto_cfg(hide("a")))] - | ^^^ - -error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items - --> $DIR/doc-cfg.rs:15:21 - | -LL | #[doc(auto_cfg(hide(foo::bar)))] - | ^^^^^^^^ - -error: expected boolean for `#[doc(auto_cfg = ...)]` - --> $DIR/doc-cfg.rs:16:7 - | -LL | #[doc(auto_cfg = 42)] - | ^^^^^^^^^^^^^ - -error: expected boolean for `#[doc(auto_cfg = ...)]` - --> $DIR/doc-cfg.rs:17:7 - | -LL | #[doc(auto_cfg = "a")] - | ^^^^^^^^^^^^^^ - -warning: unexpected `cfg` condition name: `foo` - --> $DIR/doc-cfg.rs:6:11 - | -LL | #[doc(cfg(foo), cfg(bar))] - | ^^^ - | - = help: expected names are: `FALSE` and `test` and 31 more - = help: to expect this configuration use `--check-cfg=cfg(foo)` - = note: see for more information about checking conditional configuration - = note: `#[warn(unexpected_cfgs)]` on by default - -warning: unexpected `cfg` condition name: `bar` - --> $DIR/doc-cfg.rs:6:21 - | -LL | #[doc(cfg(foo), cfg(bar))] - | ^^^ - | - = help: to expect this configuration use `--check-cfg=cfg(bar)` - = note: see for more information about checking conditional configuration - -error: `cfg` predicate is not specified - --> $DIR/doc-cfg.rs:3:7 +error[E0805]: malformed `doc` attribute input + --> $DIR/doc-cfg.rs:3:1 | LL | #[doc(cfg(), cfg(foo, bar))] - | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^--^^^^^^^^^^^^^^^^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc(test)] + | -error: multiple `cfg` predicates are specified - --> $DIR/doc-cfg.rs:3:23 +error[E0805]: malformed `doc` attribute input + --> $DIR/doc-cfg.rs:3:1 | LL | #[doc(cfg(), cfg(foo, bar))] - | ^^^ + | ^^^^^^^^^^^^^^^^----------^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc(test)] + | -error: `cfg` predicate is not specified - --> $DIR/doc-cfg.rs:9:7 +error[E0805]: malformed `doc` attribute input + --> $DIR/doc-cfg.rs:6:1 | LL | #[doc(cfg())] - | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^--^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg())] +LL + #[doc = "string"] + | +LL - #[doc(cfg())] +LL + #[doc(hidden)] + | +LL - #[doc(cfg())] +LL + #[doc(inline)] + | +LL - #[doc(cfg())] +LL + #[doc(test)] + | -error: multiple `cfg` predicates are specified - --> $DIR/doc-cfg.rs:10:16 +error[E0805]: malformed `doc` attribute input + --> $DIR/doc-cfg.rs:7:1 | LL | #[doc(cfg(foo, bar))] - | ^^^ + | ^^^^^^^^^----------^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(foo, bar))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(foo, bar))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(foo, bar))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(foo, bar))] +LL + #[doc(test)] + | -error: aborting due to 11 previous errors; 2 warnings emitted +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-cfg.rs:8:1 + | +LL | #[doc(auto_cfg(hide(foo::bar)))] + | ^^^^^^^^^^^^^^^^^^^^--------^^^^ + | | + | expected a valid identifier here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(auto_cfg(hide(foo::bar)))] +LL + #[doc = "string"] + | +LL - #[doc(auto_cfg(hide(foo::bar)))] +LL + #[doc(hidden)] + | +LL - #[doc(auto_cfg(hide(foo::bar)))] +LL + #[doc(inline)] + | +LL - #[doc(auto_cfg(hide(foo::bar)))] +LL + #[doc(test)] + | +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0539, E0805. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/rustdoc-ui/doctest/doc-test-attr.stderr b/tests/rustdoc-ui/doctest/doc-test-attr.stderr index 415251cc5e9d..cf7bce66ef40 100644 --- a/tests/rustdoc-ui/doctest/doc-test-attr.stderr +++ b/tests/rustdoc-ui/doctest/doc-test-attr.stderr @@ -7,10 +7,10 @@ LL | #![doc(test)] = note: `#[deny(invalid_doc_attributes)]` on by default error: `#[doc(test(...)]` takes a list of attributes - --> $DIR/doc-test-attr.rs:5:8 + --> $DIR/doc-test-attr.rs:5:13 | LL | #![doc(test = "hello")] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^ error: unknown `doc(test)` attribute `a` --> $DIR/doc-test-attr.rs:7:13 diff --git a/tests/rustdoc-ui/invalid-cfg.rs b/tests/rustdoc-ui/invalid-cfg.rs index 7e54aeea1def..4d00edc0c7c2 100644 --- a/tests/rustdoc-ui/invalid-cfg.rs +++ b/tests/rustdoc-ui/invalid-cfg.rs @@ -1,21 +1,21 @@ #![feature(doc_cfg)] -#[doc(cfg = "x")] //~ ERROR not followed by parentheses -#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates +#[doc(cfg = "x")] //~ ERROR malformed `doc` attribute input +#[doc(cfg(x, y))] //~ ERROR malformed `doc` attribute input pub struct S {} // We check it also fails on private items. -#[doc(cfg = "x")] //~ ERROR not followed by parentheses -#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates +#[doc(cfg = "x")] //~ ERROR malformed `doc` attribute input +#[doc(cfg(x, y))] //~ ERROR malformed `doc` attribute input struct X {} // We check it also fails on hidden items. -#[doc(cfg = "x")] //~ ERROR not followed by parentheses -#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates +#[doc(cfg = "x")] //~ ERROR malformed `doc` attribute input +#[doc(cfg(x, y))] //~ ERROR malformed `doc` attribute input #[doc(hidden)] pub struct Y {} // We check it also fails on hidden AND private items. -#[doc(cfg = "x")] //~ ERROR not followed by parentheses -#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates +#[doc(cfg = "x")] //~ ERROR malformed `doc` attribute input +#[doc(cfg(x, y))] //~ ERROR malformed `doc` attribute input #[doc(hidden)] struct Z {} diff --git a/tests/rustdoc-ui/invalid-cfg.stderr b/tests/rustdoc-ui/invalid-cfg.stderr index 455626e07bd5..a23784509c8b 100644 --- a/tests/rustdoc-ui/invalid-cfg.stderr +++ b/tests/rustdoc-ui/invalid-cfg.stderr @@ -1,50 +1,180 @@ -error: `cfg` is not followed by parentheses - --> $DIR/invalid-cfg.rs:2:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:2:1 | LL | #[doc(cfg = "x")] - | ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^^^^^^^^^ expected this to be a list + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg = "x")] +LL + #[doc = "string"] + | +LL - #[doc(cfg = "x")] +LL + #[doc(hidden)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(inline)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(test)] + | -error: multiple `cfg` predicates are specified - --> $DIR/invalid-cfg.rs:3:14 +error[E0805]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:3:1 | LL | #[doc(cfg(x, y))] - | ^ + | ^^^^^^^^^------^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(x, y))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(test)] + | -error: `cfg` is not followed by parentheses - --> $DIR/invalid-cfg.rs:7:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:7:1 | LL | #[doc(cfg = "x")] - | ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^^^^^^^^^ expected this to be a list + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg = "x")] +LL + #[doc = "string"] + | +LL - #[doc(cfg = "x")] +LL + #[doc(hidden)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(inline)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(test)] + | -error: multiple `cfg` predicates are specified - --> $DIR/invalid-cfg.rs:8:14 +error[E0805]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:8:1 | LL | #[doc(cfg(x, y))] - | ^ + | ^^^^^^^^^------^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(x, y))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(test)] + | -error: `cfg` is not followed by parentheses - --> $DIR/invalid-cfg.rs:12:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:12:1 | LL | #[doc(cfg = "x")] - | ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^^^^^^^^^ expected this to be a list + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg = "x")] +LL + #[doc = "string"] + | +LL - #[doc(cfg = "x")] +LL + #[doc(hidden)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(inline)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(test)] + | -error: multiple `cfg` predicates are specified - --> $DIR/invalid-cfg.rs:13:14 +error[E0805]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:13:1 | LL | #[doc(cfg(x, y))] - | ^ + | ^^^^^^^^^------^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(x, y))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(test)] + | -error: `cfg` is not followed by parentheses - --> $DIR/invalid-cfg.rs:18:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:18:1 | LL | #[doc(cfg = "x")] - | ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^^^^^^^^^ expected this to be a list + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg = "x")] +LL + #[doc = "string"] + | +LL - #[doc(cfg = "x")] +LL + #[doc(hidden)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(inline)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(test)] + | -error: multiple `cfg` predicates are specified - --> $DIR/invalid-cfg.rs:19:14 +error[E0805]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:19:1 | LL | #[doc(cfg(x, y))] - | ^ + | ^^^^^^^^^------^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(x, y))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(test)] + | error: aborting due to 8 previous errors +Some errors have detailed explanations: E0539, E0805. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/rustdoc-ui/lints/doc-attr-2.rs b/tests/rustdoc-ui/lints/doc-attr-2.rs new file mode 100644 index 000000000000..e5198e347523 --- /dev/null +++ b/tests/rustdoc-ui/lints/doc-attr-2.rs @@ -0,0 +1,11 @@ +#![doc(as_ptr)] +//~^ ERROR unknown `doc` attribute `as_ptr` + +#[doc(as_ptr)] +//~^ ERROR unknown `doc` attribute `as_ptr` +pub fn foo() {} + +#[doc(foo::bar, crate::bar::baz = "bye")] +//~^ ERROR unknown `doc` attribute `foo::bar` +//~| ERROR unknown `doc` attribute `crate::bar::baz` +fn bar() {} diff --git a/tests/rustdoc-ui/lints/doc-attr-2.stderr b/tests/rustdoc-ui/lints/doc-attr-2.stderr new file mode 100644 index 000000000000..c2bb45c5785e --- /dev/null +++ b/tests/rustdoc-ui/lints/doc-attr-2.stderr @@ -0,0 +1,28 @@ +error: unknown `doc` attribute `as_ptr` + --> $DIR/doc-attr-2.rs:4:7 + | +LL | #[doc(as_ptr)] + | ^^^^^^ + | + = note: `#[deny(invalid_doc_attributes)]` on by default + +error: unknown `doc` attribute `foo::bar` + --> $DIR/doc-attr-2.rs:8:7 + | +LL | #[doc(foo::bar, crate::bar::baz = "bye")] + | ^^^^^^^^ + +error: unknown `doc` attribute `crate::bar::baz` + --> $DIR/doc-attr-2.rs:8:17 + | +LL | #[doc(foo::bar, crate::bar::baz = "bye")] + | ^^^^^^^^^^^^^^^ + +error: unknown `doc` attribute `as_ptr` + --> $DIR/doc-attr-2.rs:1:8 + | +LL | #![doc(as_ptr)] + | ^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/rustdoc-ui/lints/doc-attr.rs b/tests/rustdoc-ui/lints/doc-attr.rs index 666aeb55cbec..b27faa81cb92 100644 --- a/tests/rustdoc-ui/lints/doc-attr.rs +++ b/tests/rustdoc-ui/lints/doc-attr.rs @@ -1,17 +1,8 @@ #![crate_type = "lib"] -#![doc(as_ptr)] -//~^ ERROR unknown `doc` attribute - -#[doc(as_ptr)] -//~^ ERROR unknown `doc` attribute -pub fn foo() {} #[doc(123)] -//~^ ERROR invalid `doc` attribute +//~^ ERROR malformed `doc` attribute #[doc("hello", "bar")] -//~^ ERROR invalid `doc` attribute -//~| ERROR invalid `doc` attribute -#[doc(foo::bar, crate::bar::baz = "bye")] -//~^ ERROR unknown `doc` attribute -//~| ERROR unknown `doc` attribute +//~^ ERROR malformed `doc` attribute +//~| ERROR malformed `doc` attribute fn bar() {} diff --git a/tests/rustdoc-ui/lints/doc-attr.stderr b/tests/rustdoc-ui/lints/doc-attr.stderr index 091ffc20d465..794b585a9de7 100644 --- a/tests/rustdoc-ui/lints/doc-attr.stderr +++ b/tests/rustdoc-ui/lints/doc-attr.stderr @@ -1,46 +1,72 @@ -error: unknown `doc` attribute `as_ptr` - --> $DIR/doc-attr.rs:5:7 - | -LL | #[doc(as_ptr)] - | ^^^^^^ - | - = note: `#[deny(invalid_doc_attributes)]` on by default - -error: invalid `doc` attribute - --> $DIR/doc-attr.rs:9:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-attr.rs:3:1 | LL | #[doc(123)] - | ^^^ + | ^^^^^^---^^ + | | + | expected this to be of the form `... = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(123)] +LL + #[doc = "string"] + | +LL - #[doc(123)] +LL + #[doc(hidden)] + | +LL - #[doc(123)] +LL + #[doc(inline)] + | +LL - #[doc(123)] +LL + #[doc(test)] + | -error: invalid `doc` attribute - --> $DIR/doc-attr.rs:11:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-attr.rs:5:1 | LL | #[doc("hello", "bar")] - | ^^^^^^^ + | ^^^^^^-------^^^^^^^^^ + | | + | expected this to be of the form `... = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc("hello", "bar")] +LL + #[doc = "string"] + | +LL - #[doc("hello", "bar")] +LL + #[doc(hidden)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(inline)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(test)] + | -error: invalid `doc` attribute - --> $DIR/doc-attr.rs:11:16 +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-attr.rs:5:1 | LL | #[doc("hello", "bar")] - | ^^^^^ - -error: unknown `doc` attribute `foo::bar` - --> $DIR/doc-attr.rs:14:7 + | ^^^^^^^^^^^^^^^-----^^ + | | + | expected this to be of the form `... = "..."` | -LL | #[doc(foo::bar, crate::bar::baz = "bye")] - | ^^^^^^^^ - -error: unknown `doc` attribute `crate::bar::baz` - --> $DIR/doc-attr.rs:14:17 +help: try changing it to one of the following valid forms of the attribute | -LL | #[doc(foo::bar, crate::bar::baz = "bye")] - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: unknown `doc` attribute `as_ptr` - --> $DIR/doc-attr.rs:2:8 +LL - #[doc("hello", "bar")] +LL + #[doc = "string"] + | +LL - #[doc("hello", "bar")] +LL + #[doc(hidden)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(inline)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(test)] | -LL | #![doc(as_ptr)] - | ^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0539`. From 3fa499bab0313ad3893b7b765c71c1654924af32 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Dec 2025 16:50:14 +0100 Subject: [PATCH 468/585] Sort fluent messages --- compiler/rustc_attr_parsing/messages.ftl | 164 ++++++++++++----------- 1 file changed, 83 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 4d7716560fb2..2a98b87e7a7e 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -14,8 +14,91 @@ attr_parsing_deprecated_item_suggestion = .help = add `#![feature(deprecated_suggestion)]` to the crate root .note = see #94785 for more details +attr_parsing_doc_alias_bad_char = + {$char_} character isn't allowed in {$attr_str} + +attr_parsing_doc_alias_duplicated = doc alias is duplicated + .label = first defined here + +attr_parsing_doc_alias_empty = + {$attr_str} attribute cannot have empty value + +attr_parsing_doc_alias_malformed = + doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` + +attr_parsing_doc_alias_start_end = + {$attr_str} cannot start or end with ' ' + +attr_parsing_doc_attribute_not_attribute = + nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` + .help = only existing builtin attributes are allowed in core/std + +attr_parsing_doc_auto_cfg_expects_hide_or_show = + only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` + +attr_parsing_doc_auto_cfg_hide_show_expects_list = + `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items + +attr_parsing_doc_auto_cfg_hide_show_unexpected_item = + `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items + +attr_parsing_doc_auto_cfg_wrong_literal = + expected boolean for `#[doc(auto_cfg = ...)]` + +attr_parsing_doc_invalid = + invalid `doc` attribute + +attr_parsing_doc_keyword_not_keyword = + nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]` + .help = only existing keywords are allowed in core/std + +attr_parsing_doc_test_literal = `#![doc(test(...)]` does not take a literal + +attr_parsing_doc_test_takes_list = + `#[doc(test(...)]` takes a list of attributes + +attr_parsing_doc_test_unknown = + unknown `doc(test)` attribute `{$name}` + +attr_parsing_doc_unknown_any = + unknown `doc` attribute `{$name}` + +attr_parsing_doc_unknown_include = + unknown `doc` attribute `include` + .suggestion = use `doc = include_str!` instead + +attr_parsing_doc_unknown_passes = + unknown `doc` attribute `{$name}` + .note = `doc` attribute `{$name}` no longer functions; see issue #44136 + .label = no longer functions + .no_op_note = `doc({$name})` is now a no-op + +attr_parsing_doc_unknown_plugins = + unknown `doc` attribute `plugins` + .note = `doc` attribute `plugins` no longer functions; see issue #44136 and CVE-2018-1000622 + .label = no longer functions + .no_op_note = `doc(plugins)` is now a no-op + +attr_parsing_doc_unknown_spotlight = + unknown `doc` attribute `spotlight` + .note = `doc(spotlight)` was renamed to `doc(notable_trait)` + .suggestion = use `notable_trait` instead + .no_op_note = `doc(spotlight)` is now a no-op + +attr_parsing_empty_attribute = + unused attribute + .suggestion = {$valid_without_list -> + [true] remove these parentheses + *[other] remove this attribute + } + .note = {$valid_without_list -> + [true] using `{$attr_path}` with an empty list is equivalent to not using a list at all + *[other] using `{$attr_path}` with an empty list has no effect + } + attr_parsing_empty_confusables = expected at least one confusable name + attr_parsing_empty_link_name = link name must not be empty .label = empty link name @@ -239,84 +322,3 @@ attr_parsing_doc_alias_duplicated = doc alias is duplicated attr_parsing_whole_archive_needs_static = linking modifier `whole-archive` is only compatible with `static` linking kind - -attr_parsing_unused_no_lints_note = - attribute `{$name}` without any lints has no effect - -attr_parsing_doc_alias_empty = - {$attr_str} attribute cannot have empty value - -attr_parsing_doc_alias_bad_char = - {$char_} character isn't allowed in {$attr_str} - -attr_parsing_doc_alias_start_end = - {$attr_str} cannot start or end with ' ' - -attr_parsing_doc_keyword_not_keyword = - nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]` - .help = only existing keywords are allowed in core/std - -attr_parsing_doc_attribute_not_attribute = - nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` - .help = only existing builtin attributes are allowed in core/std - -attr_parsing_doc_inline_conflict = - conflicting doc inlining attributes - .help = remove one of the conflicting attributes - -attr_parsing_doc_inline_conflict_first = - this attribute... - -attr_parsing_doc_inline_conflict_second = - {"."}..conflicts with this attribute - -attr_parsing_doc_auto_cfg_expects_hide_or_show = - only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` - -attr_parsing_doc_auto_cfg_hide_show_unexpected_item = - `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items - -attr_parsing_doc_auto_cfg_hide_show_expects_list = - `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items - -attr_parsing_doc_invalid = - invalid `doc` attribute - -attr_parsing_doc_unknown_include = - unknown `doc` attribute `include` - .suggestion = use `doc = include_str!` instead - -attr_parsing_doc_unknown_spotlight = - unknown `doc` attribute `spotlight` - .note = `doc(spotlight)` was renamed to `doc(notable_trait)` - .suggestion = use `notable_trait` instead - .no_op_note = `doc(spotlight)` is now a no-op - -attr_parsing_doc_unknown_passes = - unknown `doc` attribute `{$name}` - .note = `doc` attribute `{$name}` no longer functions; see issue #44136 - .label = no longer functions - .no_op_note = `doc({$name})` is now a no-op - -attr_parsing_doc_unknown_plugins = - unknown `doc` attribute `plugins` - .note = `doc` attribute `plugins` no longer functions; see issue #44136 and CVE-2018-1000622 - .label = no longer functions - .no_op_note = `doc(plugins)` is now a no-op - -attr_parsing_doc_unknown_any = - unknown `doc` attribute `{$name}` - -attr_parsing_doc_auto_cfg_wrong_literal = - expected boolean for `#[doc(auto_cfg = ...)]` - -attr_parsing_doc_test_takes_list = - `#[doc(test(...)]` takes a list of attributes - -attr_parsing_doc_test_unknown = - unknown `doc(test)` attribute `{$name}` - -attr_parsing_doc_test_literal = `#![doc(test(...)]` does not take a literal - -attr_parsing_doc_alias_malformed = - doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` From a36c462fb86cce3ca7abcdc9c577f68d76f0a4bf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Dec 2025 17:43:19 +0100 Subject: [PATCH 469/585] Update clippy code to new doc attribute API --- .../src/doc/doc_suspicious_footnotes.rs | 14 +++++++++----- src/tools/clippy/clippy_lints/src/doc/mod.rs | 2 +- .../src/doc/suspicious_doc_comments.rs | 6 +++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs index 3330cc5defd3..1944cd7c91d3 100644 --- a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs +++ b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::attr::AttributeExt as _; -use rustc_ast::token::CommentKind; +use rustc_ast::token::{CommentKind, DocFragmentKind}; use rustc_errors::Applicability; use rustc_hir::{AttrStyle, Attribute}; use rustc_lint::{LateContext, LintContext}; -use rustc_resolve::rustdoc::DocFragmentKind; use std::ops::Range; @@ -43,13 +42,18 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range, fragments: &F span, "looks like a footnote ref, but has no matching footnote", |diag| { - if this_fragment.kind == DocFragmentKind::SugaredDoc { - let (doc_attr, (_, doc_attr_comment_kind), attr_style) = attrs + if let DocFragmentKind::Sugared(_) = this_fragment.kind { + let (doc_attr, doc_attr_comment_kind, attr_style) = attrs .iter() .filter(|attr| attr.span().overlaps(this_fragment.span)) .rev() .find_map(|attr| { - Some((attr, attr.doc_str_and_comment_kind()?, attr.doc_resolution_scope()?)) + let (_, fragment) = attr.doc_str_and_fragment_kind()?; + let fragment = match fragment { + DocFragmentKind::Sugared(kind) => kind, + DocFragmentKind::Raw(_) => CommentKind::Line, + }; + Some((attr, fragment, attr.doc_resolution_scope()?)) }) .unwrap(); let (to_add, terminator) = match (doc_attr_comment_kind, attr_style) { diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 120da92da944..b11b2f8392c1 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -861,7 +861,7 @@ fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowSt let (fragments, _) = attrs_to_doc_fragments( attrs.iter().filter_map(|attr| { - if attr.doc_str_and_comment_kind().is_none() || attr.span().in_external_macro(cx.sess().source_map()) { + if attr.doc_str_and_fragment_kind().is_none() || attr.span().in_external_macro(cx.sess().source_map()) { None } else { Some((attr, None)) diff --git a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs index 47d91b80e7ee..e751600f00a6 100644 --- a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::AttrStyle; -use rustc_ast::token::CommentKind; +use rustc_ast::token::{CommentKind, DocFragmentKind}; use rustc_errors::Applicability; use rustc_hir::Attribute; use rustc_hir::attrs::AttributeKind; @@ -46,8 +46,8 @@ fn collect_doc_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> { && let Some(com) = comment.as_str().strip_prefix('!') { let sugg = match kind { - CommentKind::Line => format!("//!{com}"), - CommentKind::Block => format!("/*!{com}*/"), + DocFragmentKind::Sugared(CommentKind::Block) => format!("/*!{com}*/"), + DocFragmentKind::Sugared(CommentKind::Line) | DocFragmentKind::Raw(_) => format!("//!{com}"), }; Some((attr.span(), sugg)) } else { From aa3bf6fde949990eb75ae4f8d083109cfacba029 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Dec 2025 18:44:59 +0100 Subject: [PATCH 470/585] Update rustc_resolve unit tests --- compiler/rustc_resolve/src/rustdoc/tests.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc/tests.rs b/compiler/rustc_resolve/src/rustdoc/tests.rs index 6a98ae066304..9fea6f6807e4 100644 --- a/compiler/rustc_resolve/src/rustdoc/tests.rs +++ b/compiler/rustc_resolve/src/rustdoc/tests.rs @@ -2,7 +2,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::symbol::sym; -use rustc_span::{BytePos, Span}; +use rustc_span::{BytePos, DUMMY_SP, Span}; use super::{DocFragment, DocFragmentKind, source_span_for_markdown_range_inner}; @@ -17,7 +17,7 @@ fn single_backtick() { &[DocFragment { span: Span::with_root_ctxt(BytePos(8), BytePos(11)), item_id: None, - kind: DocFragmentKind::RawDoc, + kind: DocFragmentKind::Raw(DUMMY_SP), doc: sym::empty, // unused placeholder indent: 0, from_expansion: false, @@ -40,7 +40,7 @@ fn utf8() { &[DocFragment { span: Span::with_root_ctxt(BytePos(8), BytePos(14)), item_id: None, - kind: DocFragmentKind::RawDoc, + kind: DocFragmentKind::Raw(DUMMY_SP), doc: sym::empty, // unused placeholder indent: 0, from_expansion: false, From 4936973d49d653d01a114a00a14d427e37296775 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 5 Dec 2025 01:23:38 +0100 Subject: [PATCH 471/585] Fix ui tests --- .../rustc_attr_parsing/src/attributes/doc.rs | 40 ++++- compiler/rustc_attr_parsing/src/interface.rs | 3 +- compiler/rustc_expand/src/expand.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 10 +- compiler/rustc_passes/src/check_attr.rs | 58 ++++--- tests/rustdoc-ui/bad-render-options.stderr | 63 ++++---- tests/rustdoc-ui/check-doc-alias-attr.stderr | 14 +- tests/rustdoc-ui/doc-cfg.stderr | 35 +++-- tests/rustdoc-ui/invalid-cfg.stderr | 56 ++++--- tests/rustdoc-ui/lints/doc-attr.stderr | 21 +-- tests/ui/attributes/doc-attr.rs | 6 +- tests/ui/attributes/doc-attr.stderr | 93 ++++++++--- tests/ui/attributes/doc-test-literal.rs | 2 +- tests/ui/attributes/doc-test-literal.stderr | 25 ++- .../extented-attribute-macro-error.rs | 1 + .../extented-attribute-macro-error.stderr | 8 +- .../ui/attributes/issue-115264-expr-field.rs | 2 + .../attributes/issue-115264-expr-field.stderr | 12 ++ tests/ui/attributes/issue-115264-pat-field.rs | 2 + .../attributes/issue-115264-pat-field.stderr | 12 ++ .../attributes/key-value-expansion-scope.rs | 16 ++ .../key-value-expansion-scope.stderr | 148 +++++++++++++++--- .../ui/attributes/key-value-expansion.stderr | 12 +- tests/ui/attributes/malformed-attrs.stderr | 66 ++++---- ...es-note-version-and-pr-issue-141619.stderr | 2 +- .../invalid-utf8-binary-file.rs | 4 +- .../invalid-utf8-binary-file.stderr | 8 +- tests/ui/lint/unused/useless-comment.rs | 16 +- tests/ui/lint/unused/useless-comment.stderr | 70 +++++++-- .../ui/malformed/malformed-regressions.stderr | 24 ++- .../attribute/attr-unquoted-ident.stderr | 13 -- .../rustdoc/check-doc-alias-attr-location.rs | 17 +- .../check-doc-alias-attr-location.stderr | 67 ++++++-- tests/ui/rustdoc/check-doc-alias-attr.stderr | 63 ++++++-- tests/ui/rustdoc/doc-alias-crate-level.stderr | 4 +- tests/ui/rustdoc/doc-alias-same-name.stderr | 6 +- tests/ui/rustdoc/doc-primitive.stderr | 2 +- tests/ui/rustdoc/doc-test-attr.stderr | 4 +- tests/ui/rustdoc/doc_keyword.rs | 6 +- tests/ui/rustdoc/doc_keyword.stderr | 30 ++-- tests/ui/rustdoc/duplicate_doc_alias.stderr | 8 +- 41 files changed, 730 insertions(+), 321 deletions(-) create mode 100644 tests/ui/attributes/issue-115264-expr-field.stderr create mode 100644 tests/ui/attributes/issue-115264-pat-field.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 2e8249fb35be..83a6c4fc44d9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -10,7 +10,7 @@ use rustc_span::{Span, Symbol, edition, sym}; use thin_vec::ThinVec; -use super::prelude::{Allow, AllowedTargets, MethodKind, Target}; +use super::prelude::{Allow, AllowedTargets, Error, MethodKind, Target}; use super::{AcceptMapping, AttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::fluent_generated as fluent; @@ -459,7 +459,9 @@ fn accept_single_doc_attr<'c, S: Stage>( ) { match args { ArgParser::NoArgs => { - todo!() + let suggestions = cx.suggestions(); + let span = cx.attr_span; + cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); } ArgParser::List(items) => { for i in items.mixed() { @@ -493,12 +495,41 @@ fn accept_single_doc_attr<'c, S: Stage>( impl AttributeParser for DocParser { const ATTRIBUTES: AcceptMapping = &[( &[sym::doc], - template!(List: &["hidden", "inline", "test"], NameValueStr: "string"), + template!( + List: &[ + "alias", + "attribute", + "hidden", + "html_favicon_url", + "html_logo_url", + "html_no_source", + "html_playground_url", + "html_root_url", + "issue_tracker_base_url", + "inline", + "no_inline", + "masked", + "cfg", + "notable_trait", + "keyword", + "fake_variadic", + "search_unbox", + "rust_logo", + "auto_cfg", + "test", + "spotlight", + "include", + "no_default_passes", + "passes", + "plugins", + ], + NameValueStr: "string" + ), |this, cx, args| { this.accept_single_doc_attr(cx, args); }, )]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ Allow(Target::ExternCrate), Allow(Target::Use), Allow(Target::Static), @@ -527,6 +558,7 @@ impl AttributeParser for DocParser { Allow(Target::ForeignTy), Allow(Target::MacroDef), Allow(Target::Crate), + Error(Target::WherePredicate), ]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index b1538b447da0..5eefce75ace2 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; use rustc_ast as ast; -use rustc_ast::{AttrStyle, NodeId, Safety}; use rustc_ast::token::DocFragmentKind; +use rustc_ast::{AttrStyle, NodeId, Safety}; use rustc_errors::DiagCtxtHandle; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; @@ -357,7 +357,6 @@ pub fn parse_attribute_list( continue; } - let path = parser.path(); for accept in accepts { let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { shared: SharedContext { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 90563b21d2e8..33431556c76c 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -2177,7 +2177,7 @@ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) { continue; } - if attr.is_doc_comment() { + if attr.doc_str_and_fragment_kind().is_some() { self.cx.sess.psess.buffer_lint( UNUSED_DOC_COMMENTS, current_span, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ae973a3c49c2..bf66c7f85508 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -813,19 +813,23 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & let mut sugared_span: Option = None; while let Some(attr) = attrs.next() { - let is_doc_comment = attr.is_doc_comment(); + let (is_doc_comment, is_doc_attribute) = match &attr.kind { + AttrKind::DocComment(..) => (true, false), + AttrKind::Normal(normal) if normal.item.path == sym::doc => (true, true), + _ => (false, false), + }; if is_doc_comment { sugared_span = Some(sugared_span.map_or(attr.span, |span| span.with_hi(attr.span.hi()))); } - if attrs.peek().is_some_and(|next_attr| next_attr.is_doc_comment()) { + if !is_doc_attribute && attrs.peek().is_some_and(|next_attr| next_attr.is_doc_comment()) { continue; } let span = sugared_span.take().unwrap_or(attr.span); - if is_doc_comment { + if is_doc_comment || is_doc_attribute { let sub = match attr.kind { AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => { BuiltinUnusedDocCommentSub::PlainHelp diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3f29d943e7d3..030839baad9b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1029,25 +1029,27 @@ fn check_doc_attrs(&self, attr: &DocAttribute, hir_id: HirId, target: Target) { } } - if let Some((_, span)) = keyword { - self.check_attr_not_crate_level(*span, hir_id, "keyword"); + if let Some((_, span)) = keyword + && self.check_attr_not_crate_level(*span, hir_id, "keyword") + { self.check_doc_keyword_and_attribute(*span, hir_id, "keyword"); } - if let Some((_, span)) = attribute { - self.check_attr_not_crate_level(*span, hir_id, "attribute"); + if let Some((_, span)) = attribute + && self.check_attr_not_crate_level(*span, hir_id, "attribute") + { self.check_doc_keyword_and_attribute(*span, hir_id, "attribute"); } - if let Some(span) = fake_variadic { - if self.check_attr_not_crate_level(*span, hir_id, "fake_variadic") { - self.check_doc_fake_variadic(*span, hir_id); - } + if let Some(span) = fake_variadic + && self.check_attr_not_crate_level(*span, hir_id, "fake_variadic") + { + self.check_doc_fake_variadic(*span, hir_id); } - if let Some(span) = search_unbox { - if self.check_attr_not_crate_level(*span, hir_id, "search_unbox") { - self.check_doc_search_unbox(*span, hir_id); - } + if let Some(span) = search_unbox + && self.check_attr_not_crate_level(*span, hir_id, "search_unbox") + { + self.check_doc_search_unbox(*span, hir_id); } for i in [ @@ -1070,18 +1072,17 @@ fn check_doc_attrs(&self, attr: &DocAttribute, hir_id: HirId, target: Target) { self.check_doc_inline(hir_id, target, inline); - if let Some(span) = rust_logo { - if self.check_attr_crate_level(*span, hir_id) - && !self.tcx.features().rustdoc_internals() - { - feature_err( - &self.tcx.sess, - sym::rustdoc_internals, - *span, - fluent::passes_doc_rust_logo, - ) - .emit(); - } + if let Some(span) = rust_logo + && self.check_attr_crate_level(*span, hir_id) + && !self.tcx.features().rustdoc_internals() + { + feature_err( + &self.tcx.sess, + sym::rustdoc_internals, + *span, + fluent::passes_doc_rust_logo, + ) + .emit(); } if let Some(span) = masked { @@ -1984,7 +1985,14 @@ fn visit_where_predicate(&mut self, where_predicate: &'tcx hir::WherePredicate<' .hir_attrs(where_predicate.hir_id) .iter() .filter(|attr| !ATTRS_ALLOWED.iter().any(|&sym| attr.has_name(sym))) - .filter(|attr| !attr.is_parsed_attr()) + // FIXME: We shouldn't need to special-case `doc`! + .filter(|attr| { + matches!( + attr, + Attribute::Parsed(AttributeKind::DocComment { .. } | AttributeKind::Doc(_)) + | Attribute::Unparsed(_) + ) + }) .map(|attr| attr.span()) .collect::>(); if !spans.is_empty() { diff --git a/tests/rustdoc-ui/bad-render-options.stderr b/tests/rustdoc-ui/bad-render-options.stderr index e7f33f4dff1d..296a41337f33 100644 --- a/tests/rustdoc-ui/bad-render-options.stderr +++ b/tests/rustdoc-ui/bad-render-options.stderr @@ -12,14 +12,15 @@ LL - #![doc(html_favicon_url)] LL + #![doc = "string"] | LL - #![doc(html_favicon_url)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_favicon_url)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_favicon_url)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:6:1 @@ -35,14 +36,15 @@ LL - #![doc(html_logo_url)] LL + #![doc = "string"] | LL - #![doc(html_logo_url)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_logo_url)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_logo_url)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:9:1 @@ -58,14 +60,15 @@ LL - #![doc(html_playground_url)] LL + #![doc = "string"] | LL - #![doc(html_playground_url)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_playground_url)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_playground_url)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:12:1 @@ -81,14 +84,15 @@ LL - #![doc(issue_tracker_base_url)] LL + #![doc = "string"] | LL - #![doc(issue_tracker_base_url)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(issue_tracker_base_url)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(issue_tracker_base_url)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:15:1 @@ -104,14 +108,15 @@ LL - #![doc(html_favicon_url = 1)] LL + #![doc = "string"] | LL - #![doc(html_favicon_url = 1)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_favicon_url = 1)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_favicon_url = 1)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:18:1 @@ -127,14 +132,15 @@ LL - #![doc(html_logo_url = 2)] LL + #![doc = "string"] | LL - #![doc(html_logo_url = 2)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_logo_url = 2)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_logo_url = 2)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:21:1 @@ -150,14 +156,15 @@ LL - #![doc(html_playground_url = 3)] LL + #![doc = "string"] | LL - #![doc(html_playground_url = 3)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_playground_url = 3)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_playground_url = 3)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:24:1 @@ -173,14 +180,15 @@ LL - #![doc(issue_tracker_base_url = 4)] LL + #![doc = "string"] | LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 22 other candidates error[E0565]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:27:1 @@ -196,14 +204,15 @@ LL - #![doc(html_no_source = "asdf")] LL + #![doc = "string"] | LL - #![doc(html_no_source = "asdf")] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_no_source = "asdf")] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_no_source = "asdf")] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 22 other candidates error: aborting due to 9 previous errors diff --git a/tests/rustdoc-ui/check-doc-alias-attr.stderr b/tests/rustdoc-ui/check-doc-alias-attr.stderr index 06d5c6535191..6c33f10e8785 100644 --- a/tests/rustdoc-ui/check-doc-alias-attr.stderr +++ b/tests/rustdoc-ui/check-doc-alias-attr.stderr @@ -18,14 +18,15 @@ LL - #[doc(alias = 0)] LL + #[doc = "string"] | LL - #[doc(alias = 0)] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(alias = 0)] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(alias = 0)] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:9:15 @@ -85,14 +86,15 @@ LL - #[doc(alias(0))] LL + #[doc = "string"] | LL - #[doc(alias(0))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(alias(0))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(alias(0))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:20:13 diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr index a4c6584d3294..0efeac66554c 100644 --- a/tests/rustdoc-ui/doc-cfg.stderr +++ b/tests/rustdoc-ui/doc-cfg.stderr @@ -12,14 +12,15 @@ LL - #[doc(cfg(), cfg(foo, bar))] LL + #[doc = "string"] | LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:3:1 @@ -35,14 +36,15 @@ LL - #[doc(cfg(), cfg(foo, bar))] LL + #[doc = "string"] | LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:6:1 @@ -58,14 +60,15 @@ LL - #[doc(cfg())] LL + #[doc = "string"] | LL - #[doc(cfg())] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg())] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg())] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:7:1 @@ -81,14 +84,15 @@ LL - #[doc(cfg(foo, bar))] LL + #[doc = "string"] | LL - #[doc(cfg(foo, bar))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(foo, bar))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(foo, bar))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:8:1 @@ -104,14 +108,15 @@ LL - #[doc(auto_cfg(hide(foo::bar)))] LL + #[doc = "string"] | LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error: aborting due to 5 previous errors diff --git a/tests/rustdoc-ui/invalid-cfg.stderr b/tests/rustdoc-ui/invalid-cfg.stderr index a23784509c8b..3363dbb56fb4 100644 --- a/tests/rustdoc-ui/invalid-cfg.stderr +++ b/tests/rustdoc-ui/invalid-cfg.stderr @@ -10,14 +10,15 @@ LL - #[doc(cfg = "x")] LL + #[doc = "string"] | LL - #[doc(cfg = "x")] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg = "x")] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg = "x")] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:3:1 @@ -33,14 +34,15 @@ LL - #[doc(cfg(x, y))] LL + #[doc = "string"] | LL - #[doc(cfg(x, y))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(x, y))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(x, y))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:7:1 @@ -54,14 +56,15 @@ LL - #[doc(cfg = "x")] LL + #[doc = "string"] | LL - #[doc(cfg = "x")] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg = "x")] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg = "x")] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:8:1 @@ -77,14 +80,15 @@ LL - #[doc(cfg(x, y))] LL + #[doc = "string"] | LL - #[doc(cfg(x, y))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(x, y))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(x, y))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:12:1 @@ -98,14 +102,15 @@ LL - #[doc(cfg = "x")] LL + #[doc = "string"] | LL - #[doc(cfg = "x")] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg = "x")] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg = "x")] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:13:1 @@ -121,14 +126,15 @@ LL - #[doc(cfg(x, y))] LL + #[doc = "string"] | LL - #[doc(cfg(x, y))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(x, y))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(x, y))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:18:1 @@ -142,14 +148,15 @@ LL - #[doc(cfg = "x")] LL + #[doc = "string"] | LL - #[doc(cfg = "x")] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg = "x")] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg = "x")] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:19:1 @@ -165,14 +172,15 @@ LL - #[doc(cfg(x, y))] LL + #[doc = "string"] | LL - #[doc(cfg(x, y))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(x, y))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(x, y))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error: aborting due to 8 previous errors diff --git a/tests/rustdoc-ui/lints/doc-attr.stderr b/tests/rustdoc-ui/lints/doc-attr.stderr index 794b585a9de7..1201bd5c71f1 100644 --- a/tests/rustdoc-ui/lints/doc-attr.stderr +++ b/tests/rustdoc-ui/lints/doc-attr.stderr @@ -12,14 +12,15 @@ LL - #[doc(123)] LL + #[doc = "string"] | LL - #[doc(123)] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(123)] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(123)] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-attr.rs:5:1 @@ -35,14 +36,15 @@ LL - #[doc("hello", "bar")] LL + #[doc = "string"] | LL - #[doc("hello", "bar")] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc("hello", "bar")] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc("hello", "bar")] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-attr.rs:5:1 @@ -58,14 +60,15 @@ LL - #[doc("hello", "bar")] LL + #[doc = "string"] | LL - #[doc("hello", "bar")] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc("hello", "bar")] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc("hello", "bar")] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error: aborting due to 3 previous errors diff --git a/tests/ui/attributes/doc-attr.rs b/tests/ui/attributes/doc-attr.rs index 666aeb55cbec..8d733be93567 100644 --- a/tests/ui/attributes/doc-attr.rs +++ b/tests/ui/attributes/doc-attr.rs @@ -7,10 +7,10 @@ pub fn foo() {} #[doc(123)] -//~^ ERROR invalid `doc` attribute +//~^ ERROR malformed `doc` attribute #[doc("hello", "bar")] -//~^ ERROR invalid `doc` attribute -//~| ERROR invalid `doc` attribute +//~^ ERROR malformed `doc` attribute +//~| ERROR malformed `doc` attribute #[doc(foo::bar, crate::bar::baz = "bye")] //~^ ERROR unknown `doc` attribute //~| ERROR unknown `doc` attribute diff --git a/tests/ui/attributes/doc-attr.stderr b/tests/ui/attributes/doc-attr.stderr index 091ffc20d465..9234c1a0719b 100644 --- a/tests/ui/attributes/doc-attr.stderr +++ b/tests/ui/attributes/doc-attr.stderr @@ -1,3 +1,75 @@ +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-attr.rs:9:1 + | +LL | #[doc(123)] + | ^^^^^^---^^ + | | + | expected this to be of the form `... = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(123)] +LL + #[doc = "string"] + | +LL - #[doc(123)] +LL + #[doc(alias)] + | +LL - #[doc(123)] +LL + #[doc(attribute)] + | +LL - #[doc(123)] +LL + #[doc(auto_cfg)] + | + = and 22 other candidates + +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-attr.rs:11:1 + | +LL | #[doc("hello", "bar")] + | ^^^^^^-------^^^^^^^^^ + | | + | expected this to be of the form `... = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc("hello", "bar")] +LL + #[doc = "string"] + | +LL - #[doc("hello", "bar")] +LL + #[doc(alias)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(attribute)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(auto_cfg)] + | + = and 22 other candidates + +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-attr.rs:11:1 + | +LL | #[doc("hello", "bar")] + | ^^^^^^^^^^^^^^^-----^^ + | | + | expected this to be of the form `... = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc("hello", "bar")] +LL + #[doc = "string"] + | +LL - #[doc("hello", "bar")] +LL + #[doc(alias)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(attribute)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(auto_cfg)] + | + = and 22 other candidates + error: unknown `doc` attribute `as_ptr` --> $DIR/doc-attr.rs:5:7 | @@ -6,24 +78,6 @@ LL | #[doc(as_ptr)] | = note: `#[deny(invalid_doc_attributes)]` on by default -error: invalid `doc` attribute - --> $DIR/doc-attr.rs:9:7 - | -LL | #[doc(123)] - | ^^^ - -error: invalid `doc` attribute - --> $DIR/doc-attr.rs:11:7 - | -LL | #[doc("hello", "bar")] - | ^^^^^^^ - -error: invalid `doc` attribute - --> $DIR/doc-attr.rs:11:16 - | -LL | #[doc("hello", "bar")] - | ^^^^^ - error: unknown `doc` attribute `foo::bar` --> $DIR/doc-attr.rs:14:7 | @@ -34,7 +88,7 @@ error: unknown `doc` attribute `crate::bar::baz` --> $DIR/doc-attr.rs:14:17 | LL | #[doc(foo::bar, crate::bar::baz = "bye")] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ error: unknown `doc` attribute `as_ptr` --> $DIR/doc-attr.rs:2:8 @@ -44,3 +98,4 @@ LL | #![doc(as_ptr)] error: aborting due to 7 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/attributes/doc-test-literal.rs b/tests/ui/attributes/doc-test-literal.rs index 92fe7846f14c..f9776e9924bd 100644 --- a/tests/ui/attributes/doc-test-literal.rs +++ b/tests/ui/attributes/doc-test-literal.rs @@ -1,4 +1,4 @@ #![doc(test(""))] -//~^ ERROR `#![doc(test(...)]` does not take a literal +//~^ ERROR malformed `doc` attribute input fn main() {} diff --git a/tests/ui/attributes/doc-test-literal.stderr b/tests/ui/attributes/doc-test-literal.stderr index 39e109a76ce5..3ffbdcbb9fee 100644 --- a/tests/ui/attributes/doc-test-literal.stderr +++ b/tests/ui/attributes/doc-test-literal.stderr @@ -1,10 +1,27 @@ -error: `#![doc(test(...)]` does not take a literal - --> $DIR/doc-test-literal.rs:1:13 +error[E0565]: malformed `doc` attribute input + --> $DIR/doc-test-literal.rs:1:1 | LL | #![doc(test(""))] - | ^^ + | ^^^^^^^^^^^^--^^^ + | | + | didn't expect a literal here | - = note: `#[deny(invalid_doc_attributes)]` on by default +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(test(""))] +LL + #![doc = "string"] + | +LL - #![doc(test(""))] +LL + #![doc(alias)] + | +LL - #![doc(test(""))] +LL + #![doc(attribute)] + | +LL - #![doc(test(""))] +LL + #![doc(auto_cfg)] + | + = and 22 other candidates error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0565`. diff --git a/tests/ui/attributes/extented-attribute-macro-error.rs b/tests/ui/attributes/extented-attribute-macro-error.rs index 83060024dac9..f85a28ad706e 100644 --- a/tests/ui/attributes/extented-attribute-macro-error.rs +++ b/tests/ui/attributes/extented-attribute-macro-error.rs @@ -3,5 +3,6 @@ #![doc = include_str!("../not_existing_file.md")] struct Documented {} //~^^ ERROR couldn't read +//~| ERROR attribute value must be a literal fn main() {} diff --git a/tests/ui/attributes/extented-attribute-macro-error.stderr b/tests/ui/attributes/extented-attribute-macro-error.stderr index 7b93b98f64cd..ed46cba3d040 100644 --- a/tests/ui/attributes/extented-attribute-macro-error.stderr +++ b/tests/ui/attributes/extented-attribute-macro-error.stderr @@ -4,5 +4,11 @@ error: couldn't read the file LL | #![doc = include_str!("../not_existing_file.md")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: attribute value must be a literal + --> $DIR/extented-attribute-macro-error.rs:3:10 + | +LL | #![doc = include_str!("../not_existing_file.md")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/tests/ui/attributes/issue-115264-expr-field.rs b/tests/ui/attributes/issue-115264-expr-field.rs index 8adb68deb5b4..d8189626fb0f 100644 --- a/tests/ui/attributes/issue-115264-expr-field.rs +++ b/tests/ui/attributes/issue-115264-expr-field.rs @@ -12,6 +12,8 @@ struct X { fn main() { let _ = X { #[doc(alias = "StructItem")] + //~^ WARN: attribute cannot be used on struct fields + //~| WARN: this was previously accepted by the compiler but is being phased out foo: 123, }; } diff --git a/tests/ui/attributes/issue-115264-expr-field.stderr b/tests/ui/attributes/issue-115264-expr-field.stderr new file mode 100644 index 000000000000..6bb9dfc90c93 --- /dev/null +++ b/tests/ui/attributes/issue-115264-expr-field.stderr @@ -0,0 +1,12 @@ +warning: `#[doc]` attribute cannot be used on struct fields + --> $DIR/issue-115264-expr-field.rs:14:9 + | +LL | #[doc(alias = "StructItem")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + = note: requested on the command line with `-W unused-attributes` + +warning: 1 warning emitted + diff --git a/tests/ui/attributes/issue-115264-pat-field.rs b/tests/ui/attributes/issue-115264-pat-field.rs index 53e3b4524d60..0c8966b5893f 100644 --- a/tests/ui/attributes/issue-115264-pat-field.rs +++ b/tests/ui/attributes/issue-115264-pat-field.rs @@ -12,6 +12,8 @@ struct X { fn main() { let X { #[doc(alias = "StructItem")] + //~^ WARN: attribute cannot be used on pattern fields + //~| WARN: this was previously accepted by the compiler but is being phased out foo } = X { foo: 123 diff --git a/tests/ui/attributes/issue-115264-pat-field.stderr b/tests/ui/attributes/issue-115264-pat-field.stderr new file mode 100644 index 000000000000..a5b221110789 --- /dev/null +++ b/tests/ui/attributes/issue-115264-pat-field.stderr @@ -0,0 +1,12 @@ +warning: `#[doc]` attribute cannot be used on pattern fields + --> $DIR/issue-115264-pat-field.rs:14:9 + | +LL | #[doc(alias = "StructItem")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + = note: requested on the command line with `-W unused-attributes` + +warning: 1 warning emitted + diff --git a/tests/ui/attributes/key-value-expansion-scope.rs b/tests/ui/attributes/key-value-expansion-scope.rs index 6688d698f9ea..b30da2eda24a 100644 --- a/tests/ui/attributes/key-value-expansion-scope.rs +++ b/tests/ui/attributes/key-value-expansion-scope.rs @@ -1,19 +1,29 @@ #![doc = in_root!()] //~ ERROR cannot find macro `in_root` //~| WARN this was previously accepted by the compiler #![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope + //~| ERROR attribute value must be a literal #![doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` //~| WARN this was previously accepted by the compiler #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal #[doc = in_root!()] //~ ERROR cannot find macro `in_root` in this scope + //~| ERROR attribute value must be a literal #[doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope + //~| ERROR attribute value must be a literal #[doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope + //~| ERROR attribute value must be a literal #[doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal fn before() { #![doc = in_root!()] //~ ERROR cannot find macro `in_root` in this scope + //~| ERROR attribute value must be a literal #![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope + //~| ERROR attribute value must be a literal #![doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope + //~| ERROR attribute value must be a literal #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal } macro_rules! in_root { () => { "" } } @@ -48,8 +58,10 @@ fn f() { } #[doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal fn block() { #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal macro_rules! in_block { () => { "" } } @@ -61,13 +73,17 @@ fn f() { #[doc = in_root!()] // OK #[doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope + //~| ERROR attribute value must be a literal #[doc = in_mod_escape!()] // OK #[doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal fn after() { #![doc = in_root!()] // OK #![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope + //~| ERROR attribute value must be a literal #![doc = in_mod_escape!()] // OK #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal } fn main() {} diff --git a/tests/ui/attributes/key-value-expansion-scope.stderr b/tests/ui/attributes/key-value-expansion-scope.stderr index 71a83d80617a..1ebed6b8b6fc 100644 --- a/tests/ui/attributes/key-value-expansion-scope.stderr +++ b/tests/ui/attributes/key-value-expansion-scope.stderr @@ -7,7 +7,7 @@ LL | #![doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:6:10 + --> $DIR/key-value-expansion-scope.rs:7:10 | LL | #![doc = in_block!()] | ^^^^^^^^ @@ -15,7 +15,7 @@ LL | #![doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_root` in this scope - --> $DIR/key-value-expansion-scope.rs:8:9 + --> $DIR/key-value-expansion-scope.rs:10:9 | LL | #[doc = in_root!()] | ^^^^^^^ @@ -23,7 +23,7 @@ LL | #[doc = in_root!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod` in this scope - --> $DIR/key-value-expansion-scope.rs:9:9 + --> $DIR/key-value-expansion-scope.rs:12:9 | LL | #[doc = in_mod!()] | ^^^^^^ @@ -31,7 +31,7 @@ LL | #[doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod_escape` in this scope - --> $DIR/key-value-expansion-scope.rs:10:9 + --> $DIR/key-value-expansion-scope.rs:14:9 | LL | #[doc = in_mod_escape!()] | ^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | #[doc = in_mod_escape!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:11:9 + --> $DIR/key-value-expansion-scope.rs:16:9 | LL | #[doc = in_block!()] | ^^^^^^^^ @@ -47,7 +47,7 @@ LL | #[doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_root` in this scope - --> $DIR/key-value-expansion-scope.rs:13:14 + --> $DIR/key-value-expansion-scope.rs:19:14 | LL | #![doc = in_root!()] | ^^^^^^^ @@ -55,7 +55,7 @@ LL | #![doc = in_root!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod` in this scope - --> $DIR/key-value-expansion-scope.rs:14:14 + --> $DIR/key-value-expansion-scope.rs:21:14 | LL | #![doc = in_mod!()] | ^^^^^^ @@ -63,7 +63,7 @@ LL | #![doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod_escape` in this scope - --> $DIR/key-value-expansion-scope.rs:15:14 + --> $DIR/key-value-expansion-scope.rs:23:14 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | #![doc = in_mod_escape!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:16:14 + --> $DIR/key-value-expansion-scope.rs:25:14 | LL | #![doc = in_block!()] | ^^^^^^^^ @@ -79,7 +79,7 @@ LL | #![doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:50:9 + --> $DIR/key-value-expansion-scope.rs:60:9 | LL | #[doc = in_block!()] | ^^^^^^^^ @@ -87,7 +87,7 @@ LL | #[doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:52:14 + --> $DIR/key-value-expansion-scope.rs:63:14 | LL | #![doc = in_block!()] | ^^^^^^^^ @@ -95,7 +95,7 @@ LL | #![doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod` in this scope - --> $DIR/key-value-expansion-scope.rs:63:9 + --> $DIR/key-value-expansion-scope.rs:75:9 | LL | #[doc = in_mod!()] | ^^^^^^ @@ -103,7 +103,7 @@ LL | #[doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:65:9 + --> $DIR/key-value-expansion-scope.rs:78:9 | LL | #[doc = in_block!()] | ^^^^^^^^ @@ -111,7 +111,7 @@ LL | #[doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod` in this scope - --> $DIR/key-value-expansion-scope.rs:68:14 + --> $DIR/key-value-expansion-scope.rs:82:14 | LL | #![doc = in_mod!()] | ^^^^^^ @@ -119,7 +119,7 @@ LL | #![doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:70:14 + --> $DIR/key-value-expansion-scope.rs:85:14 | LL | #![doc = in_block!()] | ^^^^^^^^ @@ -138,7 +138,7 @@ LL | #![doc = in_root!()] = note: `#[deny(out_of_scope_macro_calls)]` (part of `#[deny(future_incompatible)]`) on by default error: cannot find macro `in_mod_escape` in the current scope when looking from the crate root - --> $DIR/key-value-expansion-scope.rs:4:10 + --> $DIR/key-value-expansion-scope.rs:5:10 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from the crate root @@ -148,7 +148,7 @@ LL | #![doc = in_mod_escape!()] = help: import `macro_rules` with `use` to make it callable above its definition error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` - --> $DIR/key-value-expansion-scope.rs:21:9 + --> $DIR/key-value-expansion-scope.rs:31:9 | LL | #[doc = in_mod!()] | ^^^^^^ not found from module `macros_stay` @@ -158,7 +158,7 @@ LL | #[doc = in_mod!()] = help: import `macro_rules` with `use` to make it callable above its definition error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` - --> $DIR/key-value-expansion-scope.rs:24:14 + --> $DIR/key-value-expansion-scope.rs:34:14 | LL | #![doc = in_mod!()] | ^^^^^^ not found from module `macros_stay` @@ -168,7 +168,7 @@ LL | #![doc = in_mod!()] = help: import `macro_rules` with `use` to make it callable above its definition error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` - --> $DIR/key-value-expansion-scope.rs:36:9 + --> $DIR/key-value-expansion-scope.rs:46:9 | LL | #[doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from module `macros_escape` @@ -178,7 +178,7 @@ LL | #[doc = in_mod_escape!()] = help: import `macro_rules` with `use` to make it callable above its definition error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` - --> $DIR/key-value-expansion-scope.rs:39:14 + --> $DIR/key-value-expansion-scope.rs:49:14 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from module `macros_escape` @@ -187,7 +187,103 @@ LL | #![doc = in_mod_escape!()] = note: for more information, see issue #124535 = help: import `macro_rules` with `use` to make it callable above its definition -error: aborting due to 22 previous errors +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:3:10 + | +LL | #![doc = in_mod!()] + | ^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:7:10 + | +LL | #![doc = in_block!()] + | ^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:10:9 + | +LL | #[doc = in_root!()] + | ^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:12:9 + | +LL | #[doc = in_mod!()] + | ^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:14:9 + | +LL | #[doc = in_mod_escape!()] + | ^^^^^^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:16:9 + | +LL | #[doc = in_block!()] + | ^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:19:14 + | +LL | #![doc = in_root!()] + | ^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:21:14 + | +LL | #![doc = in_mod!()] + | ^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:23:14 + | +LL | #![doc = in_mod_escape!()] + | ^^^^^^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:25:14 + | +LL | #![doc = in_block!()] + | ^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:60:9 + | +LL | #[doc = in_block!()] + | ^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:63:14 + | +LL | #![doc = in_block!()] + | ^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:75:9 + | +LL | #[doc = in_mod!()] + | ^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:78:9 + | +LL | #[doc = in_block!()] + | ^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:82:14 + | +LL | #![doc = in_mod!()] + | ^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:85:14 + | +LL | #![doc = in_block!()] + | ^^^^^^^^^^^ + +error: aborting due to 38 previous errors Future incompatibility report: Future breakage diagnostic: error: cannot find macro `in_root` in the current scope when looking from the crate root @@ -203,7 +299,7 @@ LL | #![doc = in_root!()] Future breakage diagnostic: error: cannot find macro `in_mod_escape` in the current scope when looking from the crate root - --> $DIR/key-value-expansion-scope.rs:4:10 + --> $DIR/key-value-expansion-scope.rs:5:10 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from the crate root @@ -215,7 +311,7 @@ LL | #![doc = in_mod_escape!()] Future breakage diagnostic: error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` - --> $DIR/key-value-expansion-scope.rs:21:9 + --> $DIR/key-value-expansion-scope.rs:31:9 | LL | #[doc = in_mod!()] | ^^^^^^ not found from module `macros_stay` @@ -227,7 +323,7 @@ LL | #[doc = in_mod!()] Future breakage diagnostic: error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` - --> $DIR/key-value-expansion-scope.rs:24:14 + --> $DIR/key-value-expansion-scope.rs:34:14 | LL | #![doc = in_mod!()] | ^^^^^^ not found from module `macros_stay` @@ -239,7 +335,7 @@ LL | #![doc = in_mod!()] Future breakage diagnostic: error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` - --> $DIR/key-value-expansion-scope.rs:36:9 + --> $DIR/key-value-expansion-scope.rs:46:9 | LL | #[doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from module `macros_escape` @@ -251,7 +347,7 @@ LL | #[doc = in_mod_escape!()] Future breakage diagnostic: error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` - --> $DIR/key-value-expansion-scope.rs:39:14 + --> $DIR/key-value-expansion-scope.rs:49:14 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from module `macros_escape` diff --git a/tests/ui/attributes/key-value-expansion.stderr b/tests/ui/attributes/key-value-expansion.stderr index d785bf978196..54d79c5bebb7 100644 --- a/tests/ui/attributes/key-value-expansion.stderr +++ b/tests/ui/attributes/key-value-expansion.stderr @@ -1,3 +1,9 @@ +error: attribute value must be a literal + --> $DIR/key-value-expansion.rs:21:6 + | +LL | bug!((column!())); + | ^^^^^^^^^^^ + error: attribute value must be a literal --> $DIR/key-value-expansion.rs:27:14 | @@ -20,11 +26,5 @@ LL | some_macro!(u8); | = note: this error originates in the macro `some_macro` (in Nightly builds, run with -Z macro-backtrace for more info) -error: attribute value must be a literal - --> $DIR/key-value-expansion.rs:21:6 - | -LL | bug!((column!())); - | ^^^^^^^^^^^ - error: aborting due to 3 previous errors diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 0ef62d70a15c..a6bd62fa1214 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -182,27 +182,6 @@ LL | #[allow_internal_unsafe = 1] = help: add `#![feature(allow_internal_unsafe)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:41:1 - | -LL | #[doc] - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit - = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default - -error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:77:1 - | -LL | #[doc] - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit - error[E0539]: malformed `windows_subsystem` attribute input --> $DIR/malformed-attrs.rs:26:1 | @@ -790,6 +769,16 @@ LL | #[diagnostic::on_unimplemented = 1] | = help: only `message`, `note` and `label` are allowed as options +error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` + --> $DIR/malformed-attrs.rs:41:1 + | +LL | #[doc] + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default + error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` --> $DIR/malformed-attrs.rs:52:1 | @@ -814,6 +803,15 @@ LL | | #[coroutine = 63] || {} LL | | } | |_^ +error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` + --> $DIR/malformed-attrs.rs:77:1 + | +LL | #[doc] + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + warning: `#[link_name]` attribute cannot be used on functions --> $DIR/malformed-attrs.rs:88:1 | @@ -875,7 +873,7 @@ error: aborting due to 76 previous errors; 8 warnings emitted Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805. For more information about an error, try `rustc --explain E0308`. Future incompatibility report: Future breakage diagnostic: -error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` +error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` --> $DIR/malformed-attrs.rs:41:1 | LL | #[doc] @@ -883,19 +881,6 @@ LL | #[doc] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 - = note: for more information, visit - = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default - -Future breakage diagnostic: -error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:77:1 - | -LL | #[doc] - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default Future breakage diagnostic: @@ -909,6 +894,17 @@ LL | #[inline = 5] = note: for more information, see issue #57571 = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default +Future breakage diagnostic: +error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` + --> $DIR/malformed-attrs.rs:77:1 + | +LL | #[doc] + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default + Future breakage diagnostic: error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` --> $DIR/malformed-attrs.rs:98:1 diff --git a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr index bd8c56c61c3c..d9556560b01c 100644 --- a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr +++ b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr @@ -11,7 +11,7 @@ error: unknown `doc` attribute `include` --> $DIR/removed-features-note-version-and-pr-issue-141619.rs:2:8 | LL | #![doc(include("README.md"))] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: `#[deny(invalid_doc_attributes)]` on by default diff --git a/tests/ui/include-macros/invalid-utf8-binary-file.rs b/tests/ui/include-macros/invalid-utf8-binary-file.rs index 0bbdbac611fd..c733f07c26f0 100644 --- a/tests/ui/include-macros/invalid-utf8-binary-file.rs +++ b/tests/ui/include-macros/invalid-utf8-binary-file.rs @@ -5,6 +5,8 @@ //! Ensure that ICE does not occur when reading an invalid UTF8 file with an absolute path. //! regression test for issue -#![doc = include_str!(concat!(env!("INVALID_UTF8_BIN")))] //~ ERROR: wasn't a utf-8 file +#![doc = include_str!(concat!(env!("INVALID_UTF8_BIN")))] +//~^ ERROR: wasn't a utf-8 file +//~| ERROR: attribute value must be a literal fn main() {} diff --git a/tests/ui/include-macros/invalid-utf8-binary-file.stderr b/tests/ui/include-macros/invalid-utf8-binary-file.stderr index 4ac4def1b00a..232cb5042b72 100644 --- a/tests/ui/include-macros/invalid-utf8-binary-file.stderr +++ b/tests/ui/include-macros/invalid-utf8-binary-file.stderr @@ -6,5 +6,11 @@ LL | #![doc = include_str!(concat!(env!("INVALID_UTF8_BIN")))] | = note: invalid utf-8 at byte `$BYTE` -error: aborting due to 1 previous error +error: attribute value must be a literal + --> $DIR/invalid-utf8-binary-file.rs:8:10 + | +LL | #![doc = include_str!(concat!(env!("INVALID_UTF8_BIN")))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/tests/ui/lint/unused/useless-comment.rs b/tests/ui/lint/unused/useless-comment.rs index 898665278e39..fee6cff640f6 100644 --- a/tests/ui/lint/unused/useless-comment.rs +++ b/tests/ui/lint/unused/useless-comment.rs @@ -1,6 +1,7 @@ #![feature(stmt_expr_attributes)] #![deny(unused_doc_comments)] +#![deny(unused_attributes)] macro_rules! mac { () => {} @@ -15,7 +16,10 @@ macro_rules! mac { fn foo() { /// a //~ ERROR unused doc comment - #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment + #[doc(test(attr(allow(dead_code))))] + //~^ ERROR unused doc comment + //~| ERROR `#[doc]` attribute cannot be used on statements + //~| WARN this was previously accepted by the compiler let x = 12; /// multi-line //~ ERROR unused doc comment @@ -24,7 +28,10 @@ fn foo() { match x { /// c //~ ERROR unused doc comment 1 => {}, - #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment + #[doc(test(attr(allow(dead_code))))] + //~^ ERROR unused doc comment + //~| ERROR `#[doc]` attribute cannot be used on match arms [unused_attributes] + //~| WARN this was previously accepted by the compiler _ => {} } @@ -38,7 +45,10 @@ fn foo() { /// bar //~ ERROR unused doc comment mac!(); - #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment + #[doc(test(attr(allow(dead_code))))] + //~^ ERROR unused doc comment + //~| ERROR `#[doc]` attribute cannot be used on statements + //~| WARN this was previously accepted by the compiler let x = /** comment */ 47; //~ ERROR unused doc comment /// dox //~ ERROR unused doc comment diff --git a/tests/ui/lint/unused/useless-comment.stderr b/tests/ui/lint/unused/useless-comment.stderr index 39873b82b757..3d3937e7a402 100644 --- a/tests/ui/lint/unused/useless-comment.stderr +++ b/tests/ui/lint/unused/useless-comment.stderr @@ -1,5 +1,5 @@ error: unused doc comment - --> $DIR/useless-comment.rs:9:1 + --> $DIR/useless-comment.rs:10:1 | LL | /// foo | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macro invocations @@ -12,7 +12,7 @@ LL | #![deny(unused_doc_comments)] | ^^^^^^^^^^^^^^^^^^^ error: unused doc comment - --> $DIR/useless-comment.rs:12:1 + --> $DIR/useless-comment.rs:13:1 | LL | /// a | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | unsafe extern "C" { } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:13:1 + --> $DIR/useless-comment.rs:14:1 | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | unsafe extern "C" { } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:38:5 + --> $DIR/useless-comment.rs:45:5 | LL | /// bar | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macro invocations @@ -41,28 +41,29 @@ LL | /// bar = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion error: unused doc comment - --> $DIR/useless-comment.rs:17:5 + --> $DIR/useless-comment.rs:18:5 | LL | /// a | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | #[doc(test(attr(allow(dead_code))))] +... LL | let x = 12; | ----------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:18:5 + --> $DIR/useless-comment.rs:19:5 | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | let x = 12; | ----------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:21:5 + --> $DIR/useless-comment.rs:25:5 | LL | / /// multi-line LL | | /// doc comment @@ -72,6 +73,7 @@ LL | / match x { LL | | /// c LL | | 1 => {}, LL | | #[doc(test(attr(allow(dead_code))))] +... | LL | | _ => {} LL | | } | |_____- rustdoc does not generate documentation for expressions @@ -79,7 +81,7 @@ LL | | } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:25:9 + --> $DIR/useless-comment.rs:29:9 | LL | /// c | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -89,17 +91,18 @@ LL | 1 => {}, = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:27:9 + --> $DIR/useless-comment.rs:31:9 | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | _ => {} | ------- rustdoc does not generate documentation for match arms | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:31:5 + --> $DIR/useless-comment.rs:38:5 | LL | /// foo | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +112,7 @@ LL | unsafe {} = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:34:5 + --> $DIR/useless-comment.rs:41:5 | LL | #[doc = "foo"] | ^^^^^^^^^^^^^^ @@ -120,7 +123,7 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:35:5 + --> $DIR/useless-comment.rs:42:5 | LL | #[doc = "bar"] | ^^^^^^^^^^^^^^ @@ -130,17 +133,18 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:41:5 + --> $DIR/useless-comment.rs:48:5 | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | let x = /** comment */ 47; | -------------------------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:42:13 + --> $DIR/useless-comment.rs:52:13 | LL | let x = /** comment */ 47; | ^^^^^^^^^^^^^^ -- rustdoc does not generate documentation for expressions @@ -148,7 +152,7 @@ LL | let x = /** comment */ 47; = help: use `/* */` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:44:5 + --> $DIR/useless-comment.rs:54:5 | LL | /// dox | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -159,5 +163,37 @@ LL | | } | = help: use `//` for a plain comment -error: aborting due to 15 previous errors +error: `#[doc]` attribute cannot be used on statements + --> $DIR/useless-comment.rs:19:5 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements +note: the lint level is defined here + --> $DIR/useless-comment.rs:4:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: `#[doc]` attribute cannot be used on match arms + --> $DIR/useless-comment.rs:31:9 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + +error: `#[doc]` attribute cannot be used on statements + --> $DIR/useless-comment.rs:48:5 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + +error: aborting due to 18 previous errors diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr index 181207984877..29734fd84e6b 100644 --- a/tests/ui/malformed/malformed-regressions.stderr +++ b/tests/ui/malformed/malformed-regressions.stderr @@ -1,14 +1,3 @@ -error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` - --> $DIR/malformed-regressions.rs:1:1 - | -LL | #[doc] - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit - = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default - error[E0539]: malformed `link` attribute input --> $DIR/malformed-regressions.rs:7:1 | @@ -63,6 +52,16 @@ LL | fn main() {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: requested on the command line with `-W unused-attributes` +error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` + --> $DIR/malformed-regressions.rs:1:1 + | +LL | #[doc] + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default + error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` --> $DIR/malformed-regressions.rs:3:1 | @@ -85,7 +84,7 @@ error: aborting due to 5 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0539`. Future incompatibility report: Future breakage diagnostic: -error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` +error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` --> $DIR/malformed-regressions.rs:1:1 | LL | #[doc] @@ -93,7 +92,6 @@ LL | #[doc] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 - = note: for more information, visit = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default Future breakage diagnostic: diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.stderr b/tests/ui/parser/attribute/attr-unquoted-ident.stderr index f1af60dec9bb..00fb539f8a86 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.stderr +++ b/tests/ui/parser/attribute/attr-unquoted-ident.stderr @@ -20,19 +20,6 @@ help: surround the identifier with quotation marks to make it into a string lite LL | #[cfg(key="foo bar baz")] | + + -error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression - --> $DIR/attr-unquoted-ident.rs:18:15 - | -LL | #[cfg(key=foo 1 bar 2.0 baz.)] - | ^^^ expressions are not allowed here - | -help: surround the identifier with quotation marks to make it into a string literal - | -LL | #[cfg(key="foo 1 bar 2.0 baz.")] - | + + - -error: expected unsuffixed literal, found identifier `nickname` - --> $DIR/attr-unquoted-ident.rs:28:38 | LL | ($name:ident) => { #[doc(alias = $name)] pub struct S; } | ^^^^^ diff --git a/tests/ui/rustdoc/check-doc-alias-attr-location.rs b/tests/ui/rustdoc/check-doc-alias-attr-location.rs index 10609e5d8f4d..8ba6cfde2d6d 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr-location.rs +++ b/tests/ui/rustdoc/check-doc-alias-attr-location.rs @@ -21,11 +21,22 @@ impl Foo for Bar { type X = i32; fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X { //~^ ERROR - #[doc(alias = "stmt")] //~ ERROR + //~| WARN `#[doc]` attribute cannot be used on function params + //~| WARN: this was previously accepted by the compiler + #[doc(alias = "stmt")] + //~^ ERROR + //~| WARN `#[doc]` attribute cannot be used on statements + //~| WARN: this was previously accepted by the compiler let x = 0; - #[doc(alias = "expr")] //~ ERROR + #[doc(alias = "expr")] + //~^ ERROR + //~| WARN `#[doc]` attribute cannot be used on expressions + //~| WARN: this was previously accepted by the compiler match x { - #[doc(alias = "arm")] //~ ERROR + #[doc(alias = "arm")] + //~^ ERROR + //~| WARN `#[doc]` attribute cannot be used on match arms + //~| WARN: this was previously accepted by the compiler _ => 0 } } diff --git a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr index 23c93a4ed8bd..24be42036f6f 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr +++ b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr @@ -5,46 +5,83 @@ LL | fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X { | ^^^^^^^^^^^^^^^^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on foreign module - --> $DIR/check-doc-alias-attr-location.rs:9:7 + --> $DIR/check-doc-alias-attr-location.rs:9:15 | LL | #[doc(alias = "foo")] - | ^^^^^^^^^^^^^ + | ^^^^^ error: `#[doc(alias = "...")]` isn't allowed on implementation block - --> $DIR/check-doc-alias-attr-location.rs:12:7 + --> $DIR/check-doc-alias-attr-location.rs:12:15 | LL | #[doc(alias = "bar")] - | ^^^^^^^^^^^^^ + | ^^^^^ error: `#[doc(alias = "...")]` isn't allowed on implementation block - --> $DIR/check-doc-alias-attr-location.rs:18:7 + --> $DIR/check-doc-alias-attr-location.rs:18:15 | LL | #[doc(alias = "foobar")] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on type alias in implementation block - --> $DIR/check-doc-alias-attr-location.rs:20:11 + --> $DIR/check-doc-alias-attr-location.rs:20:19 | LL | #[doc(alias = "assoc")] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on statement - --> $DIR/check-doc-alias-attr-location.rs:24:15 + --> $DIR/check-doc-alias-attr-location.rs:26:23 | LL | #[doc(alias = "stmt")] - | ^^^^^^^^^^^^^^ + | ^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on expression - --> $DIR/check-doc-alias-attr-location.rs:26:15 + --> $DIR/check-doc-alias-attr-location.rs:31:23 | LL | #[doc(alias = "expr")] - | ^^^^^^^^^^^^^^ + | ^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on match arm - --> $DIR/check-doc-alias-attr-location.rs:28:19 + --> $DIR/check-doc-alias-attr-location.rs:36:27 | LL | #[doc(alias = "arm")] - | ^^^^^^^^^^^^^ + | ^^^^^ -error: aborting due to 8 previous errors +warning: `#[doc]` attribute cannot be used on function params + --> $DIR/check-doc-alias-attr-location.rs:22:12 + | +LL | fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + = note: requested on the command line with `-W unused-attributes` + +warning: `#[doc]` attribute cannot be used on statements + --> $DIR/check-doc-alias-attr-location.rs:26:9 + | +LL | #[doc(alias = "stmt")] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + +warning: `#[doc]` attribute cannot be used on expressions + --> $DIR/check-doc-alias-attr-location.rs:31:9 + | +LL | #[doc(alias = "expr")] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + +warning: `#[doc]` attribute cannot be used on match arms + --> $DIR/check-doc-alias-attr-location.rs:36:13 + | +LL | #[doc(alias = "arm")] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + +error: aborting due to 8 previous errors; 4 warnings emitted diff --git a/tests/ui/rustdoc/check-doc-alias-attr.stderr b/tests/ui/rustdoc/check-doc-alias-attr.stderr index 250568be3333..6c33f10e8785 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr.stderr +++ b/tests/ui/rustdoc/check-doc-alias-attr.stderr @@ -4,11 +4,29 @@ error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of s LL | #[doc(alias)] | ^^^^^ -error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` - --> $DIR/check-doc-alias-attr.rs:8:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/check-doc-alias-attr.rs:8:1 | LL | #[doc(alias = 0)] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(alias = 0)] +LL + #[doc = "string"] + | +LL - #[doc(alias = 0)] +LL + #[doc(alias)] + | +LL - #[doc(alias = 0)] +LL + #[doc(attribute)] + | +LL - #[doc(alias = 0)] +LL + #[doc(auto_cfg)] + | + = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:9:15 @@ -54,25 +72,43 @@ error: `#[doc(alias = "...")]` attribute cannot have empty value LL | #[doc(alias = "")] | ^^ -error: `#[doc(alias("a"))]` expects string literals - --> $DIR/check-doc-alias-attr.rs:19:13 +error[E0539]: malformed `doc` attribute input + --> $DIR/check-doc-alias-attr.rs:19:1 | LL | #[doc(alias(0))] - | ^ + | ^^^^^^^^^^^^-^^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(alias(0))] +LL + #[doc = "string"] + | +LL - #[doc(alias(0))] +LL + #[doc(alias)] + | +LL - #[doc(alias(0))] +LL + #[doc(attribute)] + | +LL - #[doc(alias(0))] +LL + #[doc(auto_cfg)] + | + = and 22 other candidates -error: '"' character isn't allowed in `#[doc(alias("..."))]` +error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:20:13 | LL | #[doc(alias("\""))] | ^^^^ -error: '\n' character isn't allowed in `#[doc(alias("..."))]` +error: '\n' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:21:13 | LL | #[doc(alias("\n"))] | ^^^^ -error: '\n' character isn't allowed in `#[doc(alias("..."))]` +error: '\n' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:22:13 | LL | #[doc(alias(" @@ -80,25 +116,25 @@ LL | #[doc(alias(" LL | | "))] | |_^ -error: '\t' character isn't allowed in `#[doc(alias("..."))]` +error: '\t' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:24:13 | LL | #[doc(alias("\t"))] | ^^^^ -error: `#[doc(alias("..."))]` cannot start or end with ' ' +error: `#[doc(alias = "...")]` cannot start or end with ' ' --> $DIR/check-doc-alias-attr.rs:25:13 | LL | #[doc(alias(" hello"))] | ^^^^^^^^ -error: `#[doc(alias("..."))]` cannot start or end with ' ' +error: `#[doc(alias = "...")]` cannot start or end with ' ' --> $DIR/check-doc-alias-attr.rs:26:13 | LL | #[doc(alias("hello "))] | ^^^^^^^^ -error: `#[doc(alias("..."))]` attribute cannot have empty value +error: `#[doc(alias = "...")]` attribute cannot have empty value --> $DIR/check-doc-alias-attr.rs:27:13 | LL | #[doc(alias(""))] @@ -106,3 +142,4 @@ LL | #[doc(alias(""))] error: aborting due to 17 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/rustdoc/doc-alias-crate-level.stderr b/tests/ui/rustdoc/doc-alias-crate-level.stderr index bd32609ade29..a40e31714f14 100644 --- a/tests/ui/rustdoc/doc-alias-crate-level.stderr +++ b/tests/ui/rustdoc/doc-alias-crate-level.stderr @@ -5,10 +5,10 @@ LL | #[doc(alias = "shouldn't work!")] | ^^^^^^^^^^^^^^^^^ error: `#![doc(alias = "...")]` isn't allowed as a crate-level attribute - --> $DIR/doc-alias-crate-level.rs:5:8 + --> $DIR/doc-alias-crate-level.rs:5:16 | LL | #![doc(alias = "not working!")] - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/rustdoc/doc-alias-same-name.stderr b/tests/ui/rustdoc/doc-alias-same-name.stderr index a9da75c0171c..a76ff5ee0b67 100644 --- a/tests/ui/rustdoc/doc-alias-same-name.stderr +++ b/tests/ui/rustdoc/doc-alias-same-name.stderr @@ -1,8 +1,8 @@ -error: `#[doc(alias = "...")]` is the same as the item's name - --> $DIR/doc-alias-same-name.rs:3:7 +error: `#[doc(alias = "Foo"]` is the same as the item's name + --> $DIR/doc-alias-same-name.rs:3:15 | LL | #[doc(alias = "Foo")] - | ^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/rustdoc/doc-primitive.stderr b/tests/ui/rustdoc/doc-primitive.stderr index 8f6f330b3e5d..4ba310ca2410 100644 --- a/tests/ui/rustdoc/doc-primitive.stderr +++ b/tests/ui/rustdoc/doc-primitive.stderr @@ -2,7 +2,7 @@ error: unknown `doc` attribute `primitive` --> $DIR/doc-primitive.rs:3:7 | LL | #[doc(primitive = "foo")] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | note: the lint level is defined here --> $DIR/doc-primitive.rs:1:9 diff --git a/tests/ui/rustdoc/doc-test-attr.stderr b/tests/ui/rustdoc/doc-test-attr.stderr index 51672314a431..1a4b5e45142a 100644 --- a/tests/ui/rustdoc/doc-test-attr.stderr +++ b/tests/ui/rustdoc/doc-test-attr.stderr @@ -11,10 +11,10 @@ LL | #![deny(invalid_doc_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^ error: `#[doc(test(...)]` takes a list of attributes - --> $DIR/doc-test-attr.rs:6:8 + --> $DIR/doc-test-attr.rs:6:13 | LL | #![doc(test = "hello")] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^ error: unknown `doc(test)` attribute `a` --> $DIR/doc-test-attr.rs:8:13 diff --git a/tests/ui/rustdoc/doc_keyword.rs b/tests/ui/rustdoc/doc_keyword.rs index e0995f336da3..abf06d7a7866 100644 --- a/tests/ui/rustdoc/doc_keyword.rs +++ b/tests/ui/rustdoc/doc_keyword.rs @@ -1,14 +1,14 @@ #![crate_type = "lib"] #![feature(rustdoc_internals)] -#![doc(keyword = "hello")] +#![doc(keyword = "match")] //~^ ERROR `#![doc(keyword = "...")]` isn't allowed as a crate-level attribute -#[doc(keyword = "hell")] //~ ERROR `#[doc(keyword = "...")]` should be used on empty modules +#[doc(keyword = "match")] //~ ERROR `#[doc(keyword = "...")]` should be used on empty modules mod foo { fn hell() {} } -#[doc(keyword = "hall")] //~ ERROR `#[doc(keyword = "...")]` should be used on modules +#[doc(keyword = "match")] //~ ERROR `#[doc(keyword = "...")]` should be used on modules fn foo() {} diff --git a/tests/ui/rustdoc/doc_keyword.stderr b/tests/ui/rustdoc/doc_keyword.stderr index 584daae2f1aa..56da4b00724a 100644 --- a/tests/ui/rustdoc/doc_keyword.stderr +++ b/tests/ui/rustdoc/doc_keyword.stderr @@ -1,15 +1,3 @@ -error: `#[doc(keyword = "...")]` should be used on empty modules - --> $DIR/doc_keyword.rs:6:7 - | -LL | #[doc(keyword = "hell")] - | ^^^^^^^^^^^^^^^^ - -error: `#[doc(keyword = "...")]` should be used on modules - --> $DIR/doc_keyword.rs:11:7 - | -LL | #[doc(keyword = "hall")] - | ^^^^^^^^^^^^^^^^ - error: nonexistent keyword `tadam` used in `#[doc(keyword = "...")]` --> $DIR/doc_keyword.rs:22:17 | @@ -18,17 +6,29 @@ LL | #[doc(keyword = "tadam")] | = help: only existing keywords are allowed in core/std +error: `#[doc(keyword = "...")]` should be used on empty modules + --> $DIR/doc_keyword.rs:6:7 + | +LL | #[doc(keyword = "match")] + | ^^^^^^^ + +error: `#[doc(keyword = "...")]` should be used on modules + --> $DIR/doc_keyword.rs:11:7 + | +LL | #[doc(keyword = "match")] + | ^^^^^^^ + error: `#[doc(keyword = "...")]` should be used on modules --> $DIR/doc_keyword.rs:17:11 | LL | #[doc(keyword = "match")] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: `#![doc(keyword = "...")]` isn't allowed as a crate-level attribute --> $DIR/doc_keyword.rs:4:8 | -LL | #![doc(keyword = "hello")] - | ^^^^^^^^^^^^^^^^^ +LL | #![doc(keyword = "match")] + | ^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/rustdoc/duplicate_doc_alias.stderr b/tests/ui/rustdoc/duplicate_doc_alias.stderr index 4b2dd1f8eb68..eba48ca599b0 100644 --- a/tests/ui/rustdoc/duplicate_doc_alias.stderr +++ b/tests/ui/rustdoc/duplicate_doc_alias.stderr @@ -1,10 +1,10 @@ error: doc alias is duplicated - --> $DIR/duplicate_doc_alias.rs:4:7 + --> $DIR/duplicate_doc_alias.rs:4:15 | LL | #[doc(alias = "A")] - | ----------- first defined here + | --- first defined here LL | #[doc(alias = "A")] - | ^^^^^^^^^^^ + | ^^^ | note: the lint level is defined here --> $DIR/duplicate_doc_alias.rs:1:9 @@ -16,7 +16,7 @@ error: doc alias is duplicated --> $DIR/duplicate_doc_alias.rs:6:13 | LL | #[doc(alias = "B")] - | ----------- first defined here + | --- first defined here LL | #[doc(alias("B"))] | ^^^ From 348d9d98e07753c2adb0a303bc3855e0843efbcb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 5 Dec 2025 22:54:56 +0100 Subject: [PATCH 472/585] Correctly iterate doc comments in intra-doc resolution in `rustc_resolve` --- compiler/rustc_ast/src/attr/mod.rs | 16 ++++++++++++++++ compiler/rustc_hir/src/hir.rs | 4 ++++ compiler/rustc_resolve/src/rustdoc.rs | 10 +--------- tests/rustdoc/doc-on-keyword.rs | 13 +++++++++++++ 4 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 tests/rustdoc/doc-on-keyword.rs diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 94e7462d26df..a5e630a09afe 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -233,6 +233,19 @@ fn is_doc_hidden(&self) -> bool { self.has_name(sym::doc) && self.meta_item_list().is_some_and(|l| list_contains_name(&l, sym::hidden)) } + + fn is_doc_keyword_or_attribute(&self) -> bool { + if self.has_name(sym::doc) + && let Some(items) = self.meta_item_list() + { + for item in items { + if item.has_name(sym::keyword) || item.has_name(sym::attribute) { + return true; + } + } + } + false + } } impl Attribute { @@ -865,6 +878,9 @@ fn is_proc_macro_attr(&self) -> bool { /// Returns `true` if this attribute contains `doc(hidden)`. fn is_doc_hidden(&self) -> bool; + + /// Returns `true` is this attribute contains `doc(keyword)` or `doc(attribute)`. + fn is_doc_keyword_or_attribute(&self) -> bool; } // FIXME(fn_delegation): use function delegation instead of manually forwarding diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index afa1a33fe769..f5470adb87e0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1418,6 +1418,10 @@ fn is_proc_macro_attr(&self) -> bool { fn is_doc_hidden(&self) -> bool { matches!(self, Attribute::Parsed(AttributeKind::Doc(d)) if d.hidden.is_some()) } + + fn is_doc_keyword_or_attribute(&self) -> bool { + matches!(self, Attribute::Parsed(AttributeKind::Doc(d)) if d.attribute.is_some() || d.keyword.is_some()) + } } // FIXME(fn_delegation): use function delegation instead of manually forwarding diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 0ac8e68ad968..7f7c423acb40 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -367,16 +367,8 @@ pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool { /// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]` or `#[doc(attribute)]`. pub fn has_primitive_or_keyword_or_attribute_docs(attrs: &[impl AttributeExt]) -> bool { for attr in attrs { - if attr.has_name(sym::rustc_doc_primitive) { + if attr.has_name(sym::rustc_doc_primitive) || attr.is_doc_keyword_or_attribute() { return true; - } else if attr.has_name(sym::doc) - && let Some(items) = attr.meta_item_list() - { - for item in items { - if item.has_name(sym::keyword) || item.has_name(sym::attribute) { - return true; - } - } } } false diff --git a/tests/rustdoc/doc-on-keyword.rs b/tests/rustdoc/doc-on-keyword.rs new file mode 100644 index 000000000000..0c62eda60a6b --- /dev/null +++ b/tests/rustdoc/doc-on-keyword.rs @@ -0,0 +1,13 @@ +// While working on , the +// intra doc links on keyword/attribute items were not processed. + +#![feature(rustdoc_internals)] +#![crate_name = "foo"] + +//@ has 'foo/keyword.trait.html' +//@ has - '//a[@href="{{channel}}/core/marker/trait.Send.html"]' 'Send' +//@ has - '//a[@href="{{channel}}/core/marker/trait.Sync.html"]' 'Sync' +#[doc(keyword = "trait")] +// +/// [`Send`] and [Sync] +mod bar {} From 8d4f59bed7af3c8be61f1b96c5bbb25dc4d5b3a8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 5 Dec 2025 23:13:09 +0100 Subject: [PATCH 473/585] Clean up code --- compiler/rustc_attr_parsing/src/attributes/doc.rs | 6 ++---- compiler/rustc_attr_parsing/src/context.rs | 1 - compiler/rustc_attr_parsing/src/lib.rs | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 83a6c4fc44d9..4c0a7a19e5b8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -1,6 +1,3 @@ -// FIXME: to be removed -#![allow(unused_imports)] - use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit}; use rustc_feature::template; use rustc_hir::attrs::{ @@ -13,7 +10,6 @@ use super::prelude::{Allow, AllowedTargets, Error, MethodKind, Target}; use super::{AcceptMapping, AttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; -use crate::fluent_generated as fluent; use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, PathParser}; use crate::session_diagnostics::{ DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttributeNotAttribute, @@ -355,6 +351,8 @@ macro_rules! string_arg { // FIXME: It's errorring when the attribute is passed multiple times on the command // line. + // The right fix for this would be to only check this rule if the attribute is + // not set on the command line but directly in the code. // if self.attribute.$ident.is_some() { // cx.duplicate_key(path.span(), path.word_sym().unwrap()); // return; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 5d15588033fd..f41ea3708788 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -165,7 +165,6 @@ mod late { ConstStabilityParser, DocParser, MacroUseParser, - NakedParser, StabilityParser, UsedParser, diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 3e9d8087a192..cb02bb9d501f 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -78,10 +78,10 @@ // tidy-alphabetical-start #![feature(decl_macro)] -#![recursion_limit = "256"] -// tidy-alphabetical-end #![feature(if_let_guard)] #![feature(iter_intersperse)] +#![recursion_limit = "256"] +// tidy-alphabetical-end #[macro_use] /// All the individual attribute parsers for each of rustc's built-in attributes. From 2340f8054c7a97c44bcee69eb314c56667e337a0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 6 Dec 2025 21:29:35 +0100 Subject: [PATCH 474/585] Update to new lint API --- compiler/rustc_attr_parsing/messages.ftl | 65 -------------- .../rustc_attr_parsing/src/attributes/doc.rs | 73 ++++++++++++--- .../src/session_diagnostics.rs | 88 ------------------- compiler/rustc_hir/src/lints.rs | 70 +-------------- compiler/rustc_lint/messages.ftl | 52 +++++++++++ compiler/rustc_lint/src/early/diagnostics.rs | 50 +++++++++++ compiler/rustc_lint/src/lints.rs | 88 +++++++++++++++++++ compiler/rustc_lint_defs/src/lib.rs | 35 ++++++++ src/librustdoc/lib.rs | 14 ++- 9 files changed, 301 insertions(+), 234 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 2a98b87e7a7e..f2642838b3c8 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -17,9 +17,6 @@ attr_parsing_deprecated_item_suggestion = attr_parsing_doc_alias_bad_char = {$char_} character isn't allowed in {$attr_str} -attr_parsing_doc_alias_duplicated = doc alias is duplicated - .label = first defined here - attr_parsing_doc_alias_empty = {$attr_str} attribute cannot have empty value @@ -33,69 +30,10 @@ attr_parsing_doc_attribute_not_attribute = nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` .help = only existing builtin attributes are allowed in core/std -attr_parsing_doc_auto_cfg_expects_hide_or_show = - only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` - -attr_parsing_doc_auto_cfg_hide_show_expects_list = - `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items - -attr_parsing_doc_auto_cfg_hide_show_unexpected_item = - `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items - -attr_parsing_doc_auto_cfg_wrong_literal = - expected boolean for `#[doc(auto_cfg = ...)]` - -attr_parsing_doc_invalid = - invalid `doc` attribute - attr_parsing_doc_keyword_not_keyword = nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]` .help = only existing keywords are allowed in core/std -attr_parsing_doc_test_literal = `#![doc(test(...)]` does not take a literal - -attr_parsing_doc_test_takes_list = - `#[doc(test(...)]` takes a list of attributes - -attr_parsing_doc_test_unknown = - unknown `doc(test)` attribute `{$name}` - -attr_parsing_doc_unknown_any = - unknown `doc` attribute `{$name}` - -attr_parsing_doc_unknown_include = - unknown `doc` attribute `include` - .suggestion = use `doc = include_str!` instead - -attr_parsing_doc_unknown_passes = - unknown `doc` attribute `{$name}` - .note = `doc` attribute `{$name}` no longer functions; see issue #44136 - .label = no longer functions - .no_op_note = `doc({$name})` is now a no-op - -attr_parsing_doc_unknown_plugins = - unknown `doc` attribute `plugins` - .note = `doc` attribute `plugins` no longer functions; see issue #44136 and CVE-2018-1000622 - .label = no longer functions - .no_op_note = `doc(plugins)` is now a no-op - -attr_parsing_doc_unknown_spotlight = - unknown `doc` attribute `spotlight` - .note = `doc(spotlight)` was renamed to `doc(notable_trait)` - .suggestion = use `notable_trait` instead - .no_op_note = `doc(spotlight)` is now a no-op - -attr_parsing_empty_attribute = - unused attribute - .suggestion = {$valid_without_list -> - [true] remove these parentheses - *[other] remove this attribute - } - .note = {$valid_without_list -> - [true] using `{$attr_path}` with an empty list is equivalent to not using a list at all - *[other] using `{$attr_path}` with an empty list has no effect - } - attr_parsing_empty_confusables = expected at least one confusable name @@ -317,8 +255,5 @@ attr_parsing_unused_multiple = .suggestion = remove this attribute .note = attribute also specified here -attr_parsing_doc_alias_duplicated = doc alias is duplicated - .label = first defined here - attr_parsing_whole_archive_needs_static = linking modifier `whole-archive` is only compatible with `static` linking kind diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 4c0a7a19e5b8..5714d33e861f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -116,10 +116,18 @@ fn parse_single_test_doc_attr_item<'c, S: Stage>( } } Some(name) => { - cx.emit_lint(AttributeLintKind::DocTestUnknown { name }, path.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocTestUnknown { name }, + path.span(), + ); } None => { - cx.emit_lint(AttributeLintKind::DocTestLiteral, path.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocTestLiteral, + path.span(), + ); } } } @@ -151,7 +159,11 @@ fn add_alias<'c, S: Stage>( } if let Some(first_definition) = self.attribute.aliases.get(&alias).copied() { - cx.emit_lint(AttributeLintKind::DuplicateDocAlias { first_definition }, span); + cx.emit_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, + AttributeLintKind::DuplicateDocAlias { first_definition }, + span, + ); } self.attribute.aliases.insert(alias, span); @@ -239,7 +251,11 @@ fn parse_auto_cfg<'c, S: Stage>( ArgParser::List(list) => { for meta in list.mixed() { let MetaItemOrLitParser::MetaItemParser(item) = meta else { - cx.emit_lint(AttributeLintKind::DocAutoCfgExpectsHideOrShow, meta.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocAutoCfgExpectsHideOrShow, + meta.span(), + ); continue; }; let (kind, attr_name) = match item.path().word_sym() { @@ -247,6 +263,7 @@ fn parse_auto_cfg<'c, S: Stage>( Some(sym::show) => (HideOrShow::Show, sym::show), _ => { cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, AttributeLintKind::DocAutoCfgExpectsHideOrShow, item.span(), ); @@ -255,6 +272,7 @@ fn parse_auto_cfg<'c, S: Stage>( }; let ArgParser::List(list) = item.args() else { cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name }, item.span(), ); @@ -266,6 +284,7 @@ fn parse_auto_cfg<'c, S: Stage>( for item in list.mixed() { let MetaItemOrLitParser::MetaItemParser(sub_item) = item else { cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name }, item.span(), ); @@ -291,6 +310,7 @@ fn parse_auto_cfg<'c, S: Stage>( } _ => { cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name, }, @@ -306,7 +326,11 @@ fn parse_auto_cfg<'c, S: Stage>( ArgParser::NameValue(nv) => { let MetaItemLit { kind: LitKind::Bool(bool_value), span, .. } = nv.value_as_lit() else { - cx.emit_lint(AttributeLintKind::DocAutoCfgWrongLiteral, nv.value_span); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocAutoCfgWrongLiteral, + nv.value_span, + ); return; }; self.attribute.auto_cfg_change.push((*bool_value, *span)); @@ -397,6 +421,7 @@ macro_rules! string_arg { Some(sym::test) => { let Some(list) = args.list() else { cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, AttributeLintKind::DocTestTakesList, args.span().unwrap_or(path.span()), ); @@ -418,7 +443,11 @@ macro_rules! string_arg { } } Some(sym::spotlight) => { - cx.emit_lint(AttributeLintKind::DocUnknownSpotlight, path.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocUnknownSpotlight { span: path.span() }, + path.span(), + ); } Some(sym::include) if let Some(nv) = args.name_value() => { let inner = match cx.attr_style { @@ -426,23 +455,41 @@ macro_rules! string_arg { AttrStyle::Inner => "!", }; cx.emit_lint( - AttributeLintKind::DocUnknownInclude { inner, value: nv.value_as_lit().symbol }, + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocUnknownInclude { + inner, + value: nv.value_as_lit().symbol, + span: path.span(), + }, path.span(), ); } Some(name @ (sym::passes | sym::no_default_passes)) => { - cx.emit_lint(AttributeLintKind::DocUnknownPasses { name }, path.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocUnknownPasses { name, span: path.span() }, + path.span(), + ); } Some(sym::plugins) => { - cx.emit_lint(AttributeLintKind::DocUnknownPlugins, path.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocUnknownPlugins { span: path.span() }, + path.span(), + ); } Some(name) => { - cx.emit_lint(AttributeLintKind::DocUnknownAny { name }, path.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocUnknownAny { name }, + path.span(), + ); } None => { let full_name = path.segments().map(|s| s.as_str()).intersperse("::").collect::(); cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, AttributeLintKind::DocUnknownAny { name: Symbol::intern(&full_name) }, path.span(), ); @@ -459,7 +506,11 @@ fn accept_single_doc_attr<'c, S: Stage>( ArgParser::NoArgs => { let suggestions = cx.suggestions(); let span = cx.attr_span; - cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); + cx.emit_lint( + rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT, + AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None }, + span, + ); } ArgParser::List(items) => { for i in items.mixed() { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 38ae597000d2..092bf67249f2 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -581,13 +581,6 @@ pub(crate) struct NakedFunctionIncompatibleAttribute { pub attr: String, } -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_alias_duplicated)] -pub(crate) struct DocAliasDuplicated { - #[label] - pub first_defn: Span, -} - #[derive(Diagnostic)] #[diag(attr_parsing_link_ordinal_out_of_range)] #[note] @@ -995,87 +988,6 @@ pub(crate) struct CfgAttrBadDelim { pub sugg: MetaBadDelimSugg, } -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_auto_cfg_expects_hide_or_show)] -pub(crate) struct DocAutoCfgExpectsHideOrShow; - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_auto_cfg_hide_show_unexpected_item)] -pub(crate) struct DocAutoCfgHideShowUnexpectedItem { - pub attr_name: Symbol, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_auto_cfg_hide_show_expects_list)] -pub(crate) struct DocAutoCfgHideShowExpectsList { - pub attr_name: Symbol, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_invalid)] -pub(crate) struct DocInvalid; - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_unknown_include)] -pub(crate) struct DocUnknownInclude { - pub inner: &'static str, - pub value: Symbol, - #[suggestion(code = "#{inner}[doc = include_str!(\"{value}\")]")] - pub sugg: (Span, Applicability), -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_unknown_spotlight)] -#[note] -#[note(attr_parsing_no_op_note)] -pub(crate) struct DocUnknownSpotlight { - #[suggestion(style = "short", applicability = "machine-applicable", code = "notable_trait")] - pub sugg_span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_unknown_passes)] -#[note] -#[note(attr_parsing_no_op_note)] -pub(crate) struct DocUnknownPasses { - pub name: Symbol, - #[label] - pub note_span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_unknown_plugins)] -#[note] -#[note(attr_parsing_no_op_note)] -pub(crate) struct DocUnknownPlugins { - #[label] - pub label_span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_unknown_any)] -pub(crate) struct DocUnknownAny { - pub name: Symbol, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_auto_cfg_wrong_literal)] -pub(crate) struct DocAutoCfgWrongLiteral; - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_test_takes_list)] -pub(crate) struct DocTestTakesList; - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_test_unknown)] -pub(crate) struct DocTestUnknown { - pub name: Symbol, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_test_literal)] -pub(crate) struct DocTestLiteral; - #[derive(Diagnostic)] #[diag(attr_parsing_doc_alias_malformed)] pub(crate) struct DocAliasMalformed { diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index 2d13ceabf8ca..eba2d182d2c4 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -2,7 +2,7 @@ pub use rustc_lint_defs::AttributeLintKind; use rustc_lint_defs::LintId; use rustc_macros::HashStable_Generic; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; use crate::HirId; @@ -31,71 +31,3 @@ pub struct AttributeLint { pub span: Span, pub kind: AttributeLintKind, } - -#[derive(Debug, HashStable_Generic)] -pub enum AttributeLintKind { - /// Copy of `IllFormedAttributeInput` - /// specifically for the `invalid_macro_export_arguments` lint until that is removed, - /// see - InvalidMacroExportArguments { - suggestions: Vec, - }, - UnusedDuplicate { - this: Span, - other: Span, - warning: bool, - }, - IllFormedAttributeInput { - suggestions: Vec, - }, - EmptyAttribute { - first_span: Span, - attr_path: AttrPath, - valid_without_list: bool, - }, - InvalidTarget { - name: AttrPath, - target: Target, - applied: Vec, - only: &'static str, - }, - InvalidStyle { - name: AttrPath, - is_used_as_inner: bool, - target: Target, - target_span: Span, - }, - UnsafeAttrOutsideUnsafe { - attribute_name_span: Span, - sugg_spans: (Span, Span), - }, - DuplicateDocAlias { - first_definition: Span, - }, - DocAutoCfgExpectsHideOrShow, - DocAutoCfgHideShowUnexpectedItem { - attr_name: Symbol, - }, - DocAutoCfgHideShowExpectsList { - attr_name: Symbol, - }, - DocInvalid, - DocUnknownInclude { - inner: &'static str, - value: Symbol, - }, - DocUnknownSpotlight, - DocUnknownPasses { - name: Symbol, - }, - DocUnknownPlugins, - DocUnknownAny { - name: Symbol, - }, - DocAutoCfgWrongLiteral, - DocTestTakesList, - DocTestUnknown { - name: Symbol, - }, - DocTestLiteral, -} diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 0553bc95caa2..94f638b676e8 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -233,6 +233,58 @@ lint_deprecated_where_clause_location = where clause not allowed here lint_diag_out_of_impl = diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls +lint_doc_alias_duplicated = doc alias is duplicated + .label = first defined here + +lint_doc_auto_cfg_expects_hide_or_show = + only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` + +lint_doc_auto_cfg_hide_show_expects_list = + `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items + +lint_doc_auto_cfg_hide_show_unexpected_item = + `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items + +lint_doc_auto_cfg_wrong_literal = + expected boolean for `#[doc(auto_cfg = ...)]` + +lint_doc_invalid = + invalid `doc` attribute + +lint_doc_test_literal = `#![doc(test(...)]` does not take a literal + +lint_doc_test_takes_list = + `#[doc(test(...)]` takes a list of attributes + +lint_doc_test_unknown = + unknown `doc(test)` attribute `{$name}` + +lint_doc_unknown_any = + unknown `doc` attribute `{$name}` + +lint_doc_unknown_include = + unknown `doc` attribute `include` + .suggestion = use `doc = include_str!` instead + +lint_doc_unknown_passes = + unknown `doc` attribute `{$name}` + .note = `doc` attribute `{$name}` no longer functions; see issue #44136 + .label = no longer functions + .no_op_note = `doc({$name})` is now a no-op + +lint_doc_unknown_plugins = + unknown `doc` attribute `plugins` + .note = `doc` attribute `plugins` no longer functions; see issue #44136 and CVE-2018-1000622 + .label = no longer functions + .no_op_note = `doc(plugins)` is now a no-op + +lint_doc_unknown_spotlight = + unknown `doc` attribute `spotlight` + .note = `doc(spotlight)` was renamed to `doc(notable_trait)` + .suggestion = use `notable_trait` instead + .no_op_note = `doc(spotlight)` is now a no-op + + lint_drop_glue = types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 589594a3ec5e..4eb50bda53a1 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -367,5 +367,55 @@ pub fn decorate_attribute_lint( &AttributeLintKind::UnexpectedCfgValue(name, value) => { check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag) } + &AttributeLintKind::DuplicateDocAlias { first_definition } => { + lints::DocAliasDuplicated { first_defn: first_definition }.decorate_lint(diag) + } + + &AttributeLintKind::DocAutoCfgExpectsHideOrShow => { + lints::DocAutoCfgExpectsHideOrShow.decorate_lint(diag) + } + + &AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name } => { + lints::DocAutoCfgHideShowUnexpectedItem { attr_name }.decorate_lint(diag) + } + + &AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name } => { + lints::DocAutoCfgHideShowExpectsList { attr_name }.decorate_lint(diag) + } + + &AttributeLintKind::DocInvalid => { lints::DocInvalid }.decorate_lint(diag), + + &AttributeLintKind::DocUnknownInclude { span, inner, value } => { + lints::DocUnknownInclude { inner, value, sugg: (span, Applicability::MaybeIncorrect) } + } + .decorate_lint(diag), + + &AttributeLintKind::DocUnknownSpotlight { span } => { + lints::DocUnknownSpotlight { sugg_span: span }.decorate_lint(diag) + } + + &AttributeLintKind::DocUnknownPasses { name, span } => { + lints::DocUnknownPasses { name, note_span: span }.decorate_lint(diag) + } + + &AttributeLintKind::DocUnknownPlugins { span } => { + lints::DocUnknownPlugins { label_span: span }.decorate_lint(diag) + } + + &AttributeLintKind::DocUnknownAny { name } => { + lints::DocUnknownAny { name }.decorate_lint(diag) + } + + &AttributeLintKind::DocAutoCfgWrongLiteral => { + lints::DocAutoCfgWrongLiteral.decorate_lint(diag) + } + + &AttributeLintKind::DocTestTakesList => lints::DocTestTakesList.decorate_lint(diag), + + &AttributeLintKind::DocTestUnknown { name } => { + lints::DocTestUnknown { name }.decorate_lint(diag) + } + + &AttributeLintKind::DocTestLiteral => lints::DocTestLiteral.decorate_lint(diag), } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 1bec316ce45a..4aeeddcac71d 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3199,3 +3199,91 @@ pub(crate) struct UnusedVisibility { #[suggestion(style = "short", code = "", applicability = "machine-applicable")] pub span: Span, } + +#[derive(LintDiagnostic)] +#[diag(lint_doc_alias_duplicated)] +pub(crate) struct DocAliasDuplicated { + #[label] + pub first_defn: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_auto_cfg_expects_hide_or_show)] +pub(crate) struct DocAutoCfgExpectsHideOrShow; + +#[derive(LintDiagnostic)] +#[diag(lint_doc_auto_cfg_hide_show_unexpected_item)] +pub(crate) struct DocAutoCfgHideShowUnexpectedItem { + pub attr_name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_auto_cfg_hide_show_expects_list)] +pub(crate) struct DocAutoCfgHideShowExpectsList { + pub attr_name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_invalid)] +pub(crate) struct DocInvalid; + +#[derive(LintDiagnostic)] +#[diag(lint_doc_unknown_include)] +pub(crate) struct DocUnknownInclude { + pub inner: &'static str, + pub value: Symbol, + #[suggestion(code = "#{inner}[doc = include_str!(\"{value}\")]")] + pub sugg: (Span, Applicability), +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_unknown_spotlight)] +#[note] +#[note(lint_no_op_note)] +pub(crate) struct DocUnknownSpotlight { + #[suggestion(style = "short", applicability = "machine-applicable", code = "notable_trait")] + pub sugg_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_unknown_passes)] +#[note] +#[note(lint_no_op_note)] +pub(crate) struct DocUnknownPasses { + pub name: Symbol, + #[label] + pub note_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_unknown_plugins)] +#[note] +#[note(lint_no_op_note)] +pub(crate) struct DocUnknownPlugins { + #[label] + pub label_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_unknown_any)] +pub(crate) struct DocUnknownAny { + pub name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_auto_cfg_wrong_literal)] +pub(crate) struct DocAutoCfgWrongLiteral; + +#[derive(LintDiagnostic)] +#[diag(lint_doc_test_takes_list)] +pub(crate) struct DocTestTakesList; + +#[derive(LintDiagnostic)] +#[diag(lint_doc_test_unknown)] +pub(crate) struct DocTestUnknown { + pub name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_test_literal)] +pub(crate) struct DocTestLiteral; diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 376310838cc7..28657c7474b4 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -733,6 +733,41 @@ pub enum AttributeLintKind { }, UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), + DuplicateDocAlias { + first_definition: Span, + }, + DocAutoCfgExpectsHideOrShow, + DocAutoCfgHideShowUnexpectedItem { + attr_name: Symbol, + }, + DocAutoCfgHideShowExpectsList { + attr_name: Symbol, + }, + DocInvalid, + DocUnknownInclude { + span: Span, + inner: &'static str, + value: Symbol, + }, + DocUnknownSpotlight { + span: Span, + }, + DocUnknownPasses { + name: Symbol, + span: Span, + }, + DocUnknownPlugins { + span: Span, + }, + DocUnknownAny { + name: Symbol, + }, + DocAutoCfgWrongLiteral, + DocTestTakesList, + DocTestUnknown { + name: Symbol, + }, + DocTestLiteral, } pub type RegisteredTools = FxIndexSet; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 13be1a04dbc5..5e582eb61997 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -907,7 +907,19 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { for lint in &delayed_lints.lints { match lint { DelayedLint::AttributeParsing(attribute_lint) => { - rustc_attr_parsing::emit_attribute_lint(attribute_lint, tcx) + tcx.node_span_lint( + attribute_lint.lint_id.lint, + attribute_lint.id, + attribute_lint.span, + |diag| { + rustc_lint::decorate_attribute_lint( + tcx.sess, + Some(tcx), + &attribute_lint.kind, + diag, + ); + }, + ); } } } From 06238bd93e6a871f46b09519cd14676c2642a253 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 6 Dec 2025 22:33:24 +0100 Subject: [PATCH 475/585] Update rustdoc JSON output to new attribute API --- .../rustc_hir/src/attrs/data_structures.rs | 38 ++++++ src/librustdoc/json/conversions.rs | 129 ++++++++++++++++-- 2 files changed, 155 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 0419e219afe4..696d85631e16 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::fmt; use std::path::PathBuf; pub use ReprAttr::*; @@ -231,6 +232,43 @@ pub fn is_equivalent_to(&self, other: &Self) -> bool { } } +impl fmt::Display for CfgEntry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn write_entries( + name: &str, + entries: &[CfgEntry], + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + write!(f, "{name}(")?; + for (nb, entry) in entries.iter().enumerate() { + if nb != 0 { + f.write_str(", ")?; + } + entry.fmt(f)?; + } + f.write_str(")") + } + match self { + Self::All(entries, _) => write_entries("all", entries, f), + Self::Any(entries, _) => write_entries("any", entries, f), + Self::Not(entry, _) => write!(f, "not({entry})"), + Self::Bool(value, _) => write!(f, "{value}"), + Self::NameValue { name, value, .. } => { + match value { + // We use `as_str` and debug display to have characters escaped and `"` + // characters surrounding the string. + Some((value, _)) => write!(f, "{name} = {:?}", value.as_str()), + None => write!(f, "{name}"), + } + } + Self::Version(version, _) => match version { + Some(version) => write!(f, "{version}"), + None => Ok(()), + }, + } + } +} + /// Possible values for the `#[linkage]` attribute, allowing to specify the /// linkage type for a `MonoItem`. /// diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index edafc9e7a089..892cc483dbd6 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -7,14 +7,14 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; -use rustc_hir::attrs::{self, DeprecatedSince}; +use rustc_hir::attrs::{self, DeprecatedSince, DocAttribute, DocInline, HideOrShow}; 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 rustc_span::{Pos, Symbol, kw, sym}; use rustdoc_json_types::*; use crate::clean::{self, ItemId}; @@ -46,7 +46,7 @@ pub(super) fn convert_item(&self, item: &clean::Item) -> Option { .attrs .other_attrs .iter() - .filter_map(|a| maybe_from_hir_attr(a, item.item_id, self.tcx)) + .flat_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); @@ -902,11 +902,7 @@ fn from_clean(kind: &ItemType, _renderer: &JsonRenderer<'_>) -> Self { /// 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 { +fn maybe_from_hir_attr(attr: &hir::Attribute, item_id: ItemId, tcx: TyCtxt<'_>) -> Vec { use attrs::AttributeKind as AK; let kind = match attr { @@ -914,12 +910,12 @@ fn maybe_from_hir_attr( hir::Attribute::Unparsed(_) => { // FIXME: We should handle `#[doc(hidden)]`. - return Some(other_attr(tcx, attr)); + return vec![other_attr(tcx, attr)]; } }; - Some(match kind { - AK::Deprecation { .. } => return None, // Handled separately into Item::deprecation. + vec![match kind { + AK::Deprecation { .. } => return Vec::new(), // Handled separately into Item::deprecation. AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"), AK::MacroExport { .. } => Attribute::MacroExport, @@ -939,9 +935,118 @@ fn maybe_from_hir_attr( AK::NoMangle(_) => Attribute::NoMangle, AK::NonExhaustive(_) => Attribute::NonExhaustive, AK::AutomaticallyDerived(_) => Attribute::AutomaticallyDerived, + AK::Doc(d) => { + fn toggle_attr(ret: &mut Vec, name: &str, v: &Option) { + if v.is_some() { + ret.push(Attribute::Other(format!("#[doc({name})]"))); + } + } + + fn name_value_attr( + ret: &mut Vec, + name: &str, + v: &Option<(Symbol, rustc_span::Span)>, + ) { + if let Some((v, _)) = v { + // We use `as_str` and debug display to have characters escaped and `"` + // characters surrounding the string. + ret.push(Attribute::Other(format!("#[doc({name} = {:?})]", v.as_str()))); + } + } + + let DocAttribute { + aliases, + hidden, + inline, + cfg, + auto_cfg, + auto_cfg_change, + fake_variadic, + keyword, + attribute, + masked, + notable_trait, + search_unbox, + html_favicon_url, + html_logo_url, + html_playground_url, + html_root_url, + html_no_source, + issue_tracker_base_url, + rust_logo, + test_attrs, + no_crate_inject, + } = &**d; + + let mut ret = Vec::new(); + + for (alias, _) in aliases { + // We use `as_str` and debug display to have characters escaped and `"` characters + // surrounding the string. + ret.push(Attribute::Other(format!("#[doc(alias = {:?})]", alias.as_str()))); + } + toggle_attr(&mut ret, "hidden", hidden); + if let Some(inline) = inline.first() { + ret.push(Attribute::Other(format!( + "#[doc({})]", + match inline.0 { + DocInline::Inline => "inline", + DocInline::NoInline => "no_inline", + } + ))); + } + for sub_cfg in cfg { + ret.push(Attribute::Other(format!("#[doc(cfg({sub_cfg}))]"))); + } + for (auto_cfg, _) in auto_cfg { + let kind = match auto_cfg.kind { + HideOrShow::Hide => "hide", + HideOrShow::Show => "show", + }; + let mut out = format!("#[doc(auto_cfg({kind}("); + for (pos, value) in auto_cfg.values.iter().enumerate() { + if pos > 0 { + out.push_str(", "); + } + out.push_str(value.name.as_str()); + if let Some((value, _)) = value.value { + // We use `as_str` and debug display to have characters escaped and `"` + // characters surrounding the string. + out.push_str(&format!(" = {:?}", value.as_str())); + } + } + out.push_str(")))]"); + ret.push(Attribute::Other(out)); + } + for (change, _) in auto_cfg_change { + ret.push(Attribute::Other(format!("#[doc(auto_cfg = {change})]"))); + } + toggle_attr(&mut ret, "fake_variadic", fake_variadic); + name_value_attr(&mut ret, "keyword", keyword); + name_value_attr(&mut ret, "attribute", attribute); + toggle_attr(&mut ret, "masked", masked); + toggle_attr(&mut ret, "notable_trait", notable_trait); + toggle_attr(&mut ret, "search_unbox", search_unbox); + name_value_attr(&mut ret, "html_favicon_url", html_favicon_url); + name_value_attr(&mut ret, "html_logo_url", html_logo_url); + name_value_attr(&mut ret, "html_playground_url", html_playground_url); + name_value_attr(&mut ret, "html_root_url", html_root_url); + toggle_attr(&mut ret, "html_no_source", html_no_source); + name_value_attr(&mut ret, "issue_tracker_base_url", issue_tracker_base_url); + toggle_attr(&mut ret, "rust_logo", rust_logo); + let source_map = tcx.sess.source_map(); + for attr_span in test_attrs { + // FIXME: This is ugly, remove when `test_attrs` has been ported to new attribute API. + if let Ok(snippet) = source_map.span_to_snippet(*attr_span) { + ret.push(Attribute::Other(format!("#[doc(test(attr({snippet})))"))); + } + } + toggle_attr(&mut ret, "no_crate_inject", no_crate_inject); + return ret; + } _ => other_attr(tcx, attr), - }) + }] } fn other_attr(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Attribute { From 1da7684c7d0f1ec2bd9aa99a9844cff3296502ea Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 7 Dec 2025 12:18:53 +0100 Subject: [PATCH 476/585] Improve code and add more comments --- .../rustc_hir/src/attrs/data_structures.rs | 30 +--------------- src/librustdoc/clean/cfg.rs | 34 +++++++++---------- src/librustdoc/clean/types.rs | 18 ++++------ src/librustdoc/doctest/rust.rs | 9 +++++ src/librustdoc/passes/collect_trait_impls.rs | 3 ++ 5 files changed, 36 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 696d85631e16..09ef6dc18814 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -510,7 +510,7 @@ pub struct CfgHideShow { pub values: ThinVec, } -#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +#[derive(Clone, Debug, Default, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub struct DocAttribute { pub aliases: FxIndexMap, pub hidden: Option, @@ -546,34 +546,6 @@ pub struct DocAttribute { pub no_crate_inject: Option, } -impl Default for DocAttribute { - fn default() -> Self { - Self { - aliases: FxIndexMap::default(), - hidden: None, - inline: ThinVec::new(), - cfg: ThinVec::new(), - auto_cfg: ThinVec::new(), - auto_cfg_change: ThinVec::new(), - fake_variadic: None, - keyword: None, - attribute: None, - masked: None, - notable_trait: None, - search_unbox: None, - html_favicon_url: None, - html_logo_url: None, - html_playground_url: None, - html_root_url: None, - html_no_source: None, - issue_tracker_base_url: None, - rust_logo: None, - test_attrs: ThinVec::new(), - no_crate_inject: None, - } - } -} - /// Represents parsed *built-in* inert attributes. /// /// ## Overview diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 99409cf838cd..6cad4301b313 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -59,11 +59,11 @@ fn is_all_cfg(cfg: &CfgEntry) -> bool { } } -fn strip_hidden(cfg: &CfgEntry, hidden: &FxHashSet) -> Option { +fn strip_hidden(cfg: &CfgEntry, hidden: &FxHashSet) -> Option { match cfg { CfgEntry::Bool(..) => Some(cfg.clone()), CfgEntry::NameValue { .. } => { - if !hidden.contains(&SimpleCfg::from(cfg)) { + if !hidden.contains(&NameValueCfg::from(cfg)) { Some(cfg.clone()) } else { None @@ -109,7 +109,7 @@ impl Cfg { /// Parses a `MetaItemInner` into a `Cfg`. fn parse_nested( nested_cfg: &MetaItemInner, - exclude: &FxHashSet, + exclude: &FxHashSet, ) -> Result, InvalidCfgError> { match nested_cfg { MetaItemInner::MetaItem(cfg) => Cfg::parse_without(cfg, exclude), @@ -124,7 +124,7 @@ fn parse_nested( fn parse_without( cfg: &MetaItem, - exclude: &FxHashSet, + exclude: &FxHashSet, ) -> Result, InvalidCfgError> { let name = match cfg.ident() { Some(ident) => ident.name, @@ -137,7 +137,7 @@ fn parse_without( }; match cfg.kind { MetaItemKind::Word => { - if exclude.contains(&SimpleCfg::new(name)) { + if exclude.contains(&NameValueCfg::new(name)) { Ok(None) } else { Ok(Some(Cfg(CfgEntry::NameValue { @@ -150,7 +150,7 @@ fn parse_without( } MetaItemKind::NameValue(ref lit) => match lit.kind { LitKind::Str(value, _) => { - if exclude.contains(&SimpleCfg::new_value(name, value)) { + if exclude.contains(&NameValueCfg::new_value(name, value)) { Ok(None) } else { Ok(Some(Cfg(CfgEntry::NameValue { @@ -666,12 +666,12 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -struct SimpleCfg { +struct NameValueCfg { name: Symbol, value: Option, } -impl SimpleCfg { +impl NameValueCfg { fn new(name: Symbol) -> Self { Self { name, value: None } } @@ -681,18 +681,18 @@ fn new_value(name: Symbol, value: Symbol) -> Self { } } -impl<'a> From<&'a CfgEntry> for SimpleCfg { +impl<'a> From<&'a CfgEntry> for NameValueCfg { fn from(cfg: &'a CfgEntry) -> Self { match cfg { CfgEntry::NameValue { name, value, .. } => { - SimpleCfg { name: *name, value: (*value).map(|(v, _)| v) } + NameValueCfg { name: *name, value: (*value).map(|(v, _)| v) } } - _ => SimpleCfg { name: sym::empty, value: None }, + _ => NameValueCfg { name: sym::empty, value: None }, } } } -impl<'a> From<&'a attrs::CfgInfo> for SimpleCfg { +impl<'a> From<&'a attrs::CfgInfo> for NameValueCfg { fn from(cfg: &'a attrs::CfgInfo) -> Self { Self { name: cfg.name, value: cfg.value.map(|(value, _)| value) } } @@ -703,7 +703,7 @@ fn from(cfg: &'a attrs::CfgInfo) -> Self { pub(crate) struct CfgInfo { /// List of currently active `doc(auto_cfg(hide(...)))` cfgs, minus currently active /// `doc(auto_cfg(show(...)))` cfgs. - hidden_cfg: FxHashSet, + hidden_cfg: FxHashSet, /// Current computed `cfg`. Each time we enter a new item, this field is updated as well while /// taking into account the `hidden_cfg` information. current_cfg: Cfg, @@ -719,9 +719,9 @@ impl Default for CfgInfo { fn default() -> Self { Self { hidden_cfg: FxHashSet::from_iter([ - SimpleCfg::new(sym::test), - SimpleCfg::new(sym::doc), - SimpleCfg::new(sym::doctest), + NameValueCfg::new(sym::test), + NameValueCfg::new(sym::doc), + NameValueCfg::new(sym::doctest), ]), current_cfg: Cfg(CfgEntry::Bool(true, DUMMY_SP)), auto_cfg_active: true, @@ -761,7 +761,7 @@ fn handle_auto_cfg_hide_show( new_hide_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, ) { for value in &attr.values { - let simple = SimpleCfg::from(value); + let simple = NameValueCfg::from(value); if attr.kind == HideOrShow::Show { if let Some(span) = new_hide_attrs.get(&(simple.name, simple.value)) { show_hide_show_conflict_error(tcx, attr_span, *span); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index cefaf1102fb9..7a4650feac1c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -229,34 +229,28 @@ fn mapped_root_modules( } pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> impl Iterator { - self.retrieve_keywords_or_documented_attributes(tcx, true) + self.retrieve_keywords_or_documented_attributes(tcx, |d| d.keyword.map(|(v, _)| v)) } pub(crate) fn documented_attributes( &self, tcx: TyCtxt<'_>, ) -> impl Iterator { - self.retrieve_keywords_or_documented_attributes(tcx, false) + self.retrieve_keywords_or_documented_attributes(tcx, |d| d.attribute.map(|(v, _)| v)) } - fn retrieve_keywords_or_documented_attributes( + fn retrieve_keywords_or_documented_attributes Option>( &self, tcx: TyCtxt<'_>, - look_for_keyword: bool, + callback: F, ) -> impl Iterator { let as_target = move |did: DefId, tcx: TyCtxt<'_>| -> Option<(DefId, Symbol)> { tcx.get_all_attrs(did) .iter() .find_map(|attr| match attr { - Attribute::Parsed(AttributeKind::Doc(d)) => { - if look_for_keyword { - d.keyword - } else { - d.attribute - } - } + Attribute::Parsed(AttributeKind::Doc(d)) => callback(d), _ => None, }) - .map(|(value, _)| (did, value)) + .map(|value| (did, value)) }; self.mapped_root_modules(tcx, as_target) } diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index 6f294ad96267..987e1c2ddbf9 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -143,6 +143,13 @@ fn visit_testable( if let TokenTree::Ident(i) = token { let i = i.to_string(); let peek = iter.peek(); + // From this ident, we can have things like: + // + // * Group: `allow(...)` + // * Name/value: `crate_name = "..."` + // * Tokens: `html_no_url` + // + // So we peek next element to know what case we are in. match peek { Some(TokenTree::Group(g)) => { let g = g.to_string(); @@ -150,6 +157,8 @@ fn visit_testable( // Add the additional attributes to the global_crate_attrs vector self.collector.global_crate_attrs.push(format!("{i}{g}")); } + // If next item is `=`, it means it's a name value so we will need + // to get the value as well. Some(TokenTree::Punct(p)) if p.as_char() == '=' => { let p = p.to_string(); iter.next(); diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 357d00ef6521..c2a69baf2989 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -68,6 +68,9 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> while let Some(did) = parent { attr_buf.extend(tcx.get_all_attrs(did).iter().filter_map(|attr| match attr { Attribute::Parsed(AttributeKind::Doc(d)) if !d.cfg.is_empty() => { + // The only doc attributes we're interested into for trait impls are the + // `cfg`s for the `doc_cfg` feature. So we create a new empty `DocAttribute` + // and then only clone the actual `DocAttribute::cfg` field. let mut new_attr = DocAttribute::default(); new_attr.cfg = d.cfg.clone(); Some(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr)))) From 4191e94715647b2490f0bb8040f589239ab65813 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 8 Dec 2025 18:06:36 +0100 Subject: [PATCH 477/585] Improve spans for `auto_cfg(hide/show)` errors --- compiler/rustc_hir/src/attrs/data_structures.rs | 10 ++++++++++ src/librustdoc/clean/cfg.rs | 14 ++++++-------- tests/rustdoc-ui/cfg-hide-show-conflict.stderr | 8 ++++---- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 09ef6dc18814..e4a55bf39333 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -504,6 +504,16 @@ pub struct CfgInfo { pub value: Option<(Symbol, Span)>, } +impl CfgInfo { + pub fn span_for_name_and_value(&self) -> Span { + if let Some((_, value_span)) = self.value { + self.name_span.with_hi(value_span.hi()) + } else { + self.name_span + } + } +} + #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub struct CfgHideShow { pub kind: HideOrShow, diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 6cad4301b313..1413f7f56c96 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -47,7 +47,7 @@ fn is_simple_cfg(cfg: &CfgEntry) -> bool { } } -/// Whether the configuration consists of just `Cfg`, `Not` or `All`. +/// Returns `false` if is `Any`, otherwise returns `true`. fn is_all_cfg(cfg: &CfgEntry) -> bool { match cfg { CfgEntry::Bool(..) @@ -756,7 +756,6 @@ fn handle_auto_cfg_hide_show( tcx: TyCtxt<'_>, cfg_info: &mut CfgInfo, attr: &CfgHideShow, - attr_span: Span, new_show_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, new_hide_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, ) { @@ -764,16 +763,16 @@ fn handle_auto_cfg_hide_show( let simple = NameValueCfg::from(value); if attr.kind == HideOrShow::Show { if let Some(span) = new_hide_attrs.get(&(simple.name, simple.value)) { - show_hide_show_conflict_error(tcx, attr_span, *span); + show_hide_show_conflict_error(tcx, value.span_for_name_and_value(), *span); } else { - new_show_attrs.insert((simple.name, simple.value), attr_span); + new_show_attrs.insert((simple.name, simple.value), value.span_for_name_and_value()); } cfg_info.hidden_cfg.remove(&simple); } else { if let Some(span) = new_show_attrs.get(&(simple.name, simple.value)) { - show_hide_show_conflict_error(tcx, attr_span, *span); + show_hide_show_conflict_error(tcx, value.span_for_name_and_value(), *span); } else { - new_hide_attrs.insert((simple.name, simple.value), attr_span); + new_hide_attrs.insert((simple.name, simple.value), value.span_for_name_and_value()); } cfg_info.hidden_cfg.insert(simple); } @@ -871,12 +870,11 @@ fn check_changed_auto_active_status( ) { return None; } - for (value, span) in &d.auto_cfg { + for (value, _) in &d.auto_cfg { handle_auto_cfg_hide_show( tcx, cfg_info, value, - *span, &mut new_show_attrs, &mut new_hide_attrs, ); diff --git a/tests/rustdoc-ui/cfg-hide-show-conflict.stderr b/tests/rustdoc-ui/cfg-hide-show-conflict.stderr index 384a9f1a0b1f..22231e82cd7b 100644 --- a/tests/rustdoc-ui/cfg-hide-show-conflict.stderr +++ b/tests/rustdoc-ui/cfg-hide-show-conflict.stderr @@ -1,14 +1,14 @@ error: same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item - --> $DIR/cfg-hide-show-conflict.rs:3:8 + --> $DIR/cfg-hide-show-conflict.rs:3:31 | LL | #![doc(auto_cfg(show(windows, target_os = "linux")))] - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | note: first change was here - --> $DIR/cfg-hide-show-conflict.rs:2:8 + --> $DIR/cfg-hide-show-conflict.rs:2:22 | LL | #![doc(auto_cfg(hide(target_os = "linux")))] - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error From 6230b56eaa04df03ee46100823ec4aedd78e522a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 8 Dec 2025 22:44:41 +0100 Subject: [PATCH 478/585] Update clippy code --- .../clippy_lints/src/doc/doc_suspicious_footnotes.rs | 9 ++++++++- .../clippy_lints/src/doc/suspicious_doc_comments.rs | 8 ++++---- src/tools/clippy/clippy_utils/src/attrs.rs | 7 +------ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs index 1944cd7c91d3..deca29a1885f 100644 --- a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs +++ b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs @@ -2,6 +2,7 @@ use rustc_ast::attr::AttributeExt as _; use rustc_ast::token::{CommentKind, DocFragmentKind}; use rustc_errors::Applicability; +use rustc_hir::attrs::AttributeKind; use rustc_hir::{AttrStyle, Attribute}; use rustc_lint::{LateContext, LintContext}; @@ -45,7 +46,13 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range, fragments: &F if let DocFragmentKind::Sugared(_) = this_fragment.kind { let (doc_attr, doc_attr_comment_kind, attr_style) = attrs .iter() - .filter(|attr| attr.span().overlaps(this_fragment.span)) + .filter(|attr| { + matches!( + attr, + Attribute::Parsed(AttributeKind::DocComment { span, .. }) + if span.overlaps(this_fragment.span), + ) + }) .rev() .find_map(|attr| { let (_, fragment) = attr.doc_str_and_fragment_kind()?; diff --git a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs index e751600f00a6..178d688264b7 100644 --- a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs @@ -39,15 +39,15 @@ fn collect_doc_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> { .filter_map(|attr| { if let Attribute::Parsed(AttributeKind::DocComment { style: AttrStyle::Outer, - kind, + kind: DocFragmentKind::Sugared(comment_kind), comment, .. }) = attr && let Some(com) = comment.as_str().strip_prefix('!') { - let sugg = match kind { - DocFragmentKind::Sugared(CommentKind::Block) => format!("/*!{com}*/"), - DocFragmentKind::Sugared(CommentKind::Line) | DocFragmentKind::Raw(_) => format!("//!{com}"), + let sugg = match comment_kind { + CommentKind::Block => format!("/*!{com}*/"), + CommentKind::Line => format!("//!{com}"), }; Some((attr.span(), sugg)) } else { diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index 671b266ba008..2fd773b06781 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -2,7 +2,6 @@ use crate::source::SpanRangeExt; use crate::{sym, tokenize_with_text}; -use rustc_ast::attr; use rustc_ast::attr::AttributeExt; use rustc_errors::Applicability; use rustc_hir::attrs::AttributeKind; @@ -87,11 +86,7 @@ pub fn is_proc_macro(attrs: &[impl AttributeExt]) -> bool { /// Checks whether `attrs` contain `#[doc(hidden)]` pub fn is_doc_hidden(attrs: &[impl AttributeExt]) -> bool { - attrs - .iter() - .filter(|attr| attr.has_name(sym::doc)) - .filter_map(AttributeExt::meta_item_list) - .any(|l| attr::list_contains_name(&l, sym::hidden)) + attrs.iter().any(|attr| attr.is_doc_hidden()) } /// Checks whether the given ADT, or any of its fields/variants, are marked as `#[non_exhaustive]` From 40907f522d6e57abb83f80db7c62719bed7d8d46 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 8 Dec 2025 23:17:16 +0100 Subject: [PATCH 479/585] Fix doc alias suggestion --- compiler/rustc_attr_parsing/src/attributes/doc.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 5714d33e861f..a26f22c4455d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -137,10 +137,8 @@ fn add_alias<'c, S: Stage>( cx: &'c mut AcceptContext<'_, '_, S>, alias: Symbol, span: Span, - is_list: bool, ) { - let attr_str = - &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" }); + let attr_str = "`#[doc(alias = \"...\")]`"; if alias == sym::empty { cx.emit_err(DocAliasEmpty { span, attr_str }); return; @@ -186,7 +184,7 @@ fn parse_alias<'c, S: Stage>( continue; }; - self.add_alias(cx, alias, i.span(), false); + self.add_alias(cx, alias, i.span()); } } ArgParser::NameValue(nv) => { @@ -194,7 +192,7 @@ fn parse_alias<'c, S: Stage>( cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); return; }; - self.add_alias(cx, alias, nv.value_span, false); + self.add_alias(cx, alias, nv.value_span); } } } From 64aaeacd7168ae1995fed60974142db14e246840 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 9 Dec 2025 22:27:28 +0100 Subject: [PATCH 480/585] Update to new API, allowing to remove `check_doc_cfg.rs` file from librustdoc --- .../src/attributes/cfg_old.rs | 1 - .../rustc_attr_parsing/src/attributes/doc.rs | 11 ++- .../rustc_hir/src/attrs/data_structures.rs | 11 +-- library/std/build.rs | 3 + src/librustdoc/clean/cfg.rs | 43 ++++------- src/librustdoc/clean/cfg/tests.rs | 11 +-- src/librustdoc/lib.rs | 1 - src/librustdoc/passes/check_doc_cfg.rs | 72 ------------------- src/librustdoc/passes/mod.rs | 5 -- tests/rustdoc-ui/doc-cfg-2.rs | 2 + tests/rustdoc-ui/doc-cfg-2.stderr | 20 +++++- .../doc-cfg-check-cfg.cfg_empty.stderr | 12 ++-- tests/rustdoc-ui/issues/issue-91713.stdout | 2 - 13 files changed, 59 insertions(+), 135 deletions(-) delete mode 100644 src/librustdoc/passes/check_doc_cfg.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs index 29be000d476d..acb234480d5d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs @@ -2,7 +2,6 @@ use rustc_ast_pretty::pprust; use rustc_feature::{Features, GatedCfg, find_gated_cfg}; use rustc_hir::RustcVersion; -use rustc_hir::lints::AttributeLintKind; use rustc_session::Session; use rustc_session::lint::{BuiltinLintDiag, Lint}; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index a26f22c4455d..ccb6a873fb12 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -294,7 +294,7 @@ fn parse_auto_cfg<'c, S: Stage>( cx.expected_identifier(sub_item.path().span()); continue; }; - if let Ok(CfgEntry::NameValue { name, name_span, value, .. }) = + if let Ok(CfgEntry::NameValue { name, value, .. }) = super::cfg::parse_name_value( name, sub_item.path().span(), @@ -303,7 +303,14 @@ fn parse_auto_cfg<'c, S: Stage>( cx, ) { - cfg_hide_show.values.push(CfgInfo { name, name_span, value }) + cfg_hide_show.values.push(CfgInfo { + name, + name_span: sub_item.path().span(), + // If `value` is `Some`, `a.name_value()` will always return + // `Some` as well. + value: value + .map(|v| (v, a.name_value().unwrap().value_span)), + }) } } _ => { diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index e4a55bf39333..b7f8be3ec88f 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -218,14 +218,7 @@ pub fn is_equivalent_to(&self, other: &Self) -> bool { ( Self::NameValue { name: name1, value: value1, .. }, Self::NameValue { name: name2, value: value2, .. }, - ) => { - name1 == name2 - && match (value1, value2) { - (Some((a, _)), Some((b, _))) => a == b, - (None, None) => true, - _ => false, - } - } + ) => name1 == name2 && value1 == value2, (Self::Version(a, _), Self::Version(b, _)) => a == b, _ => false, } @@ -257,7 +250,7 @@ fn write_entries( match value { // We use `as_str` and debug display to have characters escaped and `"` // characters surrounding the string. - Some((value, _)) => write!(f, "{name} = {:?}", value.as_str()), + Some(value) => write!(f, "{name} = {:?}", value.as_str()), None => write!(f, "{name}"), } } diff --git a/library/std/build.rs b/library/std/build.rs index bee28e88491d..c0a6e30b3808 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -13,6 +13,9 @@ fn main() { println!("cargo:rustc-cfg=netbsd10"); } + // Needed for `#![doc(auto_cfg(hide(no_global_oom_handling)))]` attribute. + println!("cargo::rustc-check-cfg=cfg(no_global_oom_handling)"); + println!("cargo:rustc-check-cfg=cfg(restricted_std)"); if target_os == "linux" || target_os == "android" diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 1413f7f56c96..97a60c5a5098 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -140,12 +140,7 @@ fn parse_without( if exclude.contains(&NameValueCfg::new(name)) { Ok(None) } else { - Ok(Some(Cfg(CfgEntry::NameValue { - name, - value: None, - name_span: DUMMY_SP, - span: DUMMY_SP, - }))) + Ok(Some(Cfg(CfgEntry::NameValue { name, value: None, span: DUMMY_SP }))) } } MetaItemKind::NameValue(ref lit) => match lit.kind { @@ -155,8 +150,7 @@ fn parse_without( } else { Ok(Some(Cfg(CfgEntry::NameValue { name, - value: Some((value, DUMMY_SP)), - name_span: DUMMY_SP, + value: Some(value), span: DUMMY_SP, }))) } @@ -226,9 +220,7 @@ fn cfg_matches(cfg: &CfgEntry, psess: &ParseSess) -> bool { CfgEntry::Any(sub_cfgs, _) => { sub_cfgs.iter().any(|sub_cfg| cfg_matches(sub_cfg, psess)) } - CfgEntry::NameValue { name, value, .. } => { - psess.config.contains(&(*name, value.clone().map(|(s, _)| s))) - } + CfgEntry::NameValue { name, value, .. } => psess.config.contains(&(*name, *value)), CfgEntry::Version(..) => { // FIXME: should be handled. false @@ -497,7 +489,7 @@ fn display_sub_cfgs( sub_cfgs .iter() .map(|sub_cfg| { - if let CfgEntry::NameValue { value: Some((feat, _)), .. } = sub_cfg + if let CfgEntry::NameValue { value: Some(feat), .. } = sub_cfg && short_longhand { Either::Left(self.code_wrappers().wrap(feat)) @@ -557,7 +549,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { (sym::unix, None) => "Unix", (sym::windows, None) => "Windows", (sym::debug_assertions, None) => "debug-assertions enabled", - (sym::target_os, Some((os, _))) => match os.as_str() { + (sym::target_os, Some(os)) => match os.as_str() { "android" => "Android", "cygwin" => "Cygwin", "dragonfly" => "DragonFly BSD", @@ -582,7 +574,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { "visionos" => "visionOS", _ => "", }, - (sym::target_arch, Some((arch, _))) => match arch.as_str() { + (sym::target_arch, Some(arch)) => match arch.as_str() { "aarch64" => "AArch64", "arm" => "ARM", "loongarch32" => "LoongArch LA32", @@ -605,14 +597,14 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { "x86_64" => "x86-64", _ => "", }, - (sym::target_vendor, Some((vendor, _))) => match vendor.as_str() { + (sym::target_vendor, Some(vendor)) => match vendor.as_str() { "apple" => "Apple", "pc" => "PC", "sun" => "Sun", "fortanix" => "Fortanix", _ => "", }, - (sym::target_env, Some((env, _))) => match env.as_str() { + (sym::target_env, Some(env)) => match env.as_str() { "gnu" => "GNU", "msvc" => "MSVC", "musl" => "musl", @@ -621,20 +613,20 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { "sgx" => "SGX", _ => "", }, - (sym::target_endian, Some((endian, _))) => { + (sym::target_endian, Some(endian)) => { return write!(fmt, "{endian}-endian"); } - (sym::target_pointer_width, Some((bits, _))) => { + (sym::target_pointer_width, Some(bits)) => { return write!(fmt, "{bits}-bit"); } - (sym::target_feature, Some((feat, _))) => match self.1 { + (sym::target_feature, Some(feat)) => match self.1 { Format::LongHtml => { return write!(fmt, "target feature {feat}"); } Format::LongPlain => return write!(fmt, "target feature `{feat}`"), Format::ShortHtml => return write!(fmt, "{feat}"), }, - (sym::feature, Some((feat, _))) => match self.1 { + (sym::feature, Some(feat)) => match self.1 { Format::LongHtml => { return write!(fmt, "crate feature {feat}"); } @@ -647,9 +639,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.write_str(human_readable) } else { let value = value - .map(|(v, _)| { - fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str()))) - }) + .map(|v| fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str())))) .maybe_display(); self.code_wrappers() .wrap(format_args!("{}{value}", self.1.escape(name.as_str()))) @@ -684,9 +674,7 @@ fn new_value(name: Symbol, value: Symbol) -> Self { impl<'a> From<&'a CfgEntry> for NameValueCfg { fn from(cfg: &'a CfgEntry) -> Self { match cfg { - CfgEntry::NameValue { name, value, .. } => { - NameValueCfg { name: *name, value: (*value).map(|(v, _)| v) } - } + CfgEntry::NameValue { name, value, .. } => NameValueCfg { name: *name, value: *value }, _ => NameValueCfg { name: sym::empty, value: None }, } } @@ -886,8 +874,7 @@ fn check_changed_auto_active_status( for (feature, _) in features { cfg_info.current_cfg &= Cfg(CfgEntry::NameValue { name: sym::target_feature, - value: Some((*feature, DUMMY_SP)), - name_span: DUMMY_SP, + value: Some(*feature), span: DUMMY_SP, }); } diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 4eb6c060cbd2..09316ead76ac 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -12,12 +12,7 @@ fn word_cfg(name: &str) -> Cfg { } fn word_cfg_e(name: &str) -> CfgEntry { - CfgEntry::NameValue { - name: Symbol::intern(name), - name_span: DUMMY_SP, - value: None, - span: DUMMY_SP, - } + CfgEntry::NameValue { name: Symbol::intern(name), value: None, span: DUMMY_SP } } fn name_value_cfg(name: &str, value: &str) -> Cfg { @@ -27,8 +22,8 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg { fn name_value_cfg_e(name: &str, value: &str) -> CfgEntry { CfgEntry::NameValue { name: Symbol::intern(name), - name_span: DUMMY_SP, - value: Some((Symbol::intern(value), DUMMY_SP)), + + value: Some(Symbol::intern(value)), span: DUMMY_SP, } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 5e582eb61997..cc8a308688d2 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -32,7 +32,6 @@ extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_ast_pretty; -extern crate rustc_attr_parsing; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; diff --git a/src/librustdoc/passes/check_doc_cfg.rs b/src/librustdoc/passes/check_doc_cfg.rs deleted file mode 100644 index 9e7fae5e14e4..000000000000 --- a/src/librustdoc/passes/check_doc_cfg.rs +++ /dev/null @@ -1,72 +0,0 @@ -use rustc_attr_parsing::{ShouldEmit, eval_config_entry}; -use rustc_hir::attrs::AttributeKind; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::{Attribute, HirId}; -use rustc_middle::ty::TyCtxt; - -use super::Pass; -use crate::clean::{Attributes, Crate, Item}; -use crate::core::DocContext; -use crate::visit::DocVisitor; - -pub(crate) const CHECK_DOC_CFG: Pass = Pass { - name: "check-doc-cfg", - run: Some(check_doc_cfg), - description: "checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs", -}; - -pub(crate) fn check_doc_cfg(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let mut checker = DocCfgChecker { cx }; - checker.visit_crate(&krate); - krate -} - -struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, HirId); - -impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> { - fn emit_span_lint( - &self, - sess: &rustc_session::Session, - lint: &'static rustc_lint::Lint, - sp: rustc_span::Span, - builtin_diag: rustc_lint_defs::BuiltinLintDiag, - ) { - self.0.node_span_lint(lint, self.1, sp, |diag| { - rustc_lint::decorate_builtin_lint(sess, Some(self.0), builtin_diag, diag) - }); - } -} - -struct DocCfgChecker<'a, 'tcx> { - cx: &'a mut DocContext<'tcx>, -} - -impl DocCfgChecker<'_, '_> { - fn check_attrs(&mut self, attrs: &Attributes, did: LocalDefId) { - for attr in &attrs.other_attrs { - let Attribute::Parsed(AttributeKind::Doc(d)) = attr else { continue }; - - for doc_cfg in &d.cfg { - let _ = eval_config_entry( - &self.cx.tcx.sess, - doc_cfg, - &RustdocCfgMatchesLintEmitter( - self.cx.tcx, - self.cx.tcx.local_def_id_to_hir_id(did), - ), - ShouldEmit::ErrorsAndLints, - ); - } - } - } -} - -impl DocVisitor<'_> for DocCfgChecker<'_, '_> { - fn visit_item(&mut self, item: &'_ Item) { - if let Some(Some(local_did)) = item.def_id().map(|did| did.as_local()) { - self.check_attrs(&item.attrs, local_did); - } - - self.visit_item_recur(item); - } -} diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index a1e8e7530623..18e1afaf8a24 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -32,9 +32,6 @@ mod check_doc_test_visibility; pub(crate) use self::check_doc_test_visibility::CHECK_DOC_TEST_VISIBILITY; -mod check_doc_cfg; -pub(crate) use self::check_doc_cfg::CHECK_DOC_CFG; - mod collect_trait_impls; pub(crate) use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; @@ -75,7 +72,6 @@ pub(crate) enum Condition { /// The full list of passes. pub(crate) const PASSES: &[Pass] = &[ - CHECK_DOC_CFG, CHECK_DOC_TEST_VISIBILITY, PROPAGATE_DOC_CFG, STRIP_ALIASED_NON_LOCAL, @@ -93,7 +89,6 @@ pub(crate) enum Condition { pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[ ConditionalPass::always(COLLECT_TRAIT_IMPLS), ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY), - ConditionalPass::always(CHECK_DOC_CFG), ConditionalPass::always(STRIP_ALIASED_NON_LOCAL), ConditionalPass::always(PROPAGATE_DOC_CFG), ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), diff --git a/tests/rustdoc-ui/doc-cfg-2.rs b/tests/rustdoc-ui/doc-cfg-2.rs index bd6a2dc18be9..7a5d1f3e3dbb 100644 --- a/tests/rustdoc-ui/doc-cfg-2.rs +++ b/tests/rustdoc-ui/doc-cfg-2.rs @@ -12,5 +12,7 @@ // Shouldn't lint #[doc(auto_cfg(hide(windows)))] #[doc(auto_cfg(hide(feature = "windows")))] +//~^ WARN unexpected `cfg` condition name: `feature` #[doc(auto_cfg(hide(foo)))] +//~^ WARN unexpected `cfg` condition name: `foo` pub fn foo() {} diff --git a/tests/rustdoc-ui/doc-cfg-2.stderr b/tests/rustdoc-ui/doc-cfg-2.stderr index f3d67abfb8dd..1272e569897b 100644 --- a/tests/rustdoc-ui/doc-cfg-2.stderr +++ b/tests/rustdoc-ui/doc-cfg-2.stderr @@ -56,5 +56,23 @@ error: expected boolean for `#[doc(auto_cfg = ...)]` LL | #[doc(auto_cfg = "a")] | ^^^ -error: aborting due to 6 previous errors; 2 warnings emitted +warning: unexpected `cfg` condition name: `feature` + --> $DIR/doc-cfg-2.rs:14:21 + | +LL | #[doc(auto_cfg(hide(feature = "windows")))] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(feature, values("windows"))` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `foo` + --> $DIR/doc-cfg-2.rs:16:21 + | +LL | #[doc(auto_cfg(hide(foo)))] + | ^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(foo)` + = note: see for more information about checking conditional configuration + +error: aborting due to 6 previous errors; 4 warnings emitted diff --git a/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr b/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr index 0878f7edbf48..3f67b85900aa 100644 --- a/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr +++ b/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr @@ -1,8 +1,8 @@ warning: unexpected `cfg` condition name: `foo` - --> $DIR/doc-cfg-check-cfg.rs:12:12 + --> $DIR/doc-cfg-check-cfg.rs:15:11 | -LL | #![doc(cfg(foo))] - | ^^^ +LL | #[doc(cfg(foo))] + | ^^^ | = help: to expect this configuration use `--check-cfg=cfg(foo)` = note: see for more information about checking conditional configuration @@ -18,10 +18,10 @@ LL | #[doc(cfg(foo))] = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition name: `foo` - --> $DIR/doc-cfg-check-cfg.rs:15:11 + --> $DIR/doc-cfg-check-cfg.rs:12:12 | -LL | #[doc(cfg(foo))] - | ^^^ +LL | #![doc(cfg(foo))] + | ^^^ | = help: to expect this configuration use `--check-cfg=cfg(foo)` = note: see for more information about checking conditional configuration diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout index c0cd454e8f3a..e7b8a1dccf80 100644 --- a/tests/rustdoc-ui/issues/issue-91713.stdout +++ b/tests/rustdoc-ui/issues/issue-91713.stdout @@ -1,5 +1,4 @@ Available passes for running rustdoc: - check-doc-cfg - checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs check_doc_test_visibility - run various visibility-related lints on doctests propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items strip-aliased-non-local - strips all non-local private aliased items from the output @@ -15,7 +14,6 @@ calculate-doc-coverage - counts the number of items with and without documentati Default passes for rustdoc: collect-trait-impls check_doc_test_visibility - check-doc-cfg strip-aliased-non-local propagate-doc-cfg strip-hidden (when not --document-hidden-items) From 3ea946216700c1c6ede64a0d5db658419afc3017 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Dec 2025 12:27:26 +0100 Subject: [PATCH 481/585] Remove `Cfg::matches` and use `eval_config_entry` instead --- src/librustdoc/clean/cfg.rs | 29 ++++------------------------- src/librustdoc/doctest/rust.rs | 3 ++- src/librustdoc/lib.rs | 1 + 3 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 97a60c5a5098..7ab2a72d75b5 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -14,7 +14,6 @@ use rustc_hir::Attribute; use rustc_hir::attrs::{self, AttributeKind, CfgEntry, CfgHideShow, HideOrShow}; use rustc_middle::ty::TyCtxt; -use rustc_session::parse::ParseSess; use rustc_span::symbol::{Symbol, sym}; use rustc_span::{DUMMY_SP, Span}; @@ -206,30 +205,6 @@ pub(crate) fn parse(cfg: &MetaItemInner) -> Result { Self::parse_nested(cfg, &FxHashSet::default()).map(|ret| ret.unwrap()) } - /// Checks whether the given configuration can be matched in the current session. - /// - /// Equivalent to `attr::cfg_matches`. - pub(crate) fn matches(&self, psess: &ParseSess) -> bool { - fn cfg_matches(cfg: &CfgEntry, psess: &ParseSess) -> bool { - match cfg { - CfgEntry::Bool(v, _) => *v, - CfgEntry::Not(child, _) => !cfg_matches(child, psess), - CfgEntry::All(sub_cfgs, _) => { - sub_cfgs.iter().all(|sub_cfg| cfg_matches(sub_cfg, psess)) - } - CfgEntry::Any(sub_cfgs, _) => { - sub_cfgs.iter().any(|sub_cfg| cfg_matches(sub_cfg, psess)) - } - CfgEntry::NameValue { name, value, .. } => psess.config.contains(&(*name, *value)), - CfgEntry::Version(..) => { - // FIXME: should be handled. - false - } - } - } - cfg_matches(&self.0, psess) - } - /// Renders the configuration for human display, as a short HTML description. pub(crate) fn render_short_html(&self) -> String { let mut msg = Display(&self.0, Format::ShortHtml).to_string(); @@ -320,6 +295,10 @@ pub(crate) fn simplify_with(&self, assume: &Self) -> Option { fn omit_preposition(&self) -> bool { matches!(self.0, CfgEntry::Bool(..)) } + + pub(crate) fn inner(&self) -> &CfgEntry { + &self.0 + } } impl ops::Not for Cfg { diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index 987e1c2ddbf9..ee1419d17d6e 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use proc_macro2::{TokenStream, TokenTree}; +use rustc_attr_parsing::eval_config_entry; use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{self as hir, Attribute, CRATE_HIR_ID, intravisit}; @@ -123,7 +124,7 @@ fn visit_testable( let ast_attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); if let Some(ref cfg) = extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &mut CfgInfo::default()) - && !cfg.matches(&self.tcx.sess.psess) + && !eval_config_entry(&self.tcx.sess, cfg.inner()).as_bool() { return; } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index cc8a308688d2..5e582eb61997 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -32,6 +32,7 @@ extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_ast_pretty; +extern crate rustc_attr_parsing; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; From 9fdec8194e6045133629d899bc4b7048d00311d4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Dec 2025 12:35:17 +0100 Subject: [PATCH 482/585] Fix new merge conflict --- .../parser/attribute/attr-unquoted-ident.rs | 5 ++++- .../attribute/attr-unquoted-ident.stderr | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.rs b/tests/ui/parser/attribute/attr-unquoted-ident.rs index 152448bf8a0f..6207662a6e19 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.rs +++ b/tests/ui/parser/attribute/attr-unquoted-ident.rs @@ -26,7 +26,10 @@ fn main() { macro_rules! make { ($name:ident) => { #[doc(alias = $name)] pub struct S; } - //~^ ERROR: expected unsuffixed literal, found identifier `nickname` + //~^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression + //~| NOTE: expressions are not allowed here + //~| HELP: surround the identifier with quotation marks to make it into a string literal } make!(nickname); //~ NOTE: in this expansion +//~^ NOTE in this expansion of make diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.stderr b/tests/ui/parser/attribute/attr-unquoted-ident.stderr index 00fb539f8a86..48ca499ba78f 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.stderr +++ b/tests/ui/parser/attribute/attr-unquoted-ident.stderr @@ -20,14 +20,31 @@ help: surround the identifier with quotation marks to make it into a string lite LL | #[cfg(key="foo bar baz")] | + + +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression + --> $DIR/attr-unquoted-ident.rs:18:15 + | +LL | #[cfg(key=foo 1 bar 2.0 baz.)] + | ^^^ expressions are not allowed here + | +help: surround the identifier with quotation marks to make it into a string literal + | +LL | #[cfg(key="foo 1 bar 2.0 baz.")] + | + + + +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression + --> $DIR/attr-unquoted-ident.rs:28:38 | LL | ($name:ident) => { #[doc(alias = $name)] pub struct S; } - | ^^^^^ + | ^^^^^ expressions are not allowed here ... LL | make!(nickname); | --------------- in this macro invocation | = note: this error originates in the macro `make` (in Nightly builds, run with -Z macro-backtrace for more info) +help: surround the identifier with quotation marks to make it into a string literal + | +LL | ($name:ident) => { #[doc(alias = "$name")] pub struct S; } + | + + error: aborting due to 4 previous errors From 0eed5ab5503df59f07cc149223a3e368e334f502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 10 Dec 2025 12:41:56 +0100 Subject: [PATCH 483/585] introduce fcw macro --- compiler/rustc_lint/src/builtin.rs | 14 +- compiler/rustc_lint/src/if_let_rescope.rs | 6 +- .../rustc_lint/src/impl_trait_overcaptures.rs | 6 +- ..._expr_fragment_specifier_2024_migration.rs | 5 +- compiler/rustc_lint/src/non_fmt_panic.rs | 5 +- compiler/rustc_lint/src/shadowed_into_iter.rs | 9 +- compiler/rustc_lint/src/static_mut_refs.rs | 6 +- compiler/rustc_lint_defs/src/builtin.rs | 148 ++++++------------ compiler/rustc_lint_defs/src/lib.rs | 146 ++++++++++++++--- .../rustc-dev-guide/src/bug-fix-procedure.md | 4 +- src/doc/rustc-dev-guide/src/diagnostics.md | 3 +- .../rustc-dev-guide/src/guides/editions.md | 3 +- 12 files changed, 197 insertions(+), 158 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index dd0aa848ed2c..7546d3948a8f 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -35,9 +35,9 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, AssocContainer, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef}; -use rustc_session::lint::FutureIncompatibilityReason; // hardwired lints from rustc_lint_defs pub use rustc_session::lint::builtin::*; +use rustc_session::lint::fcw; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; @@ -777,8 +777,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { Warn, "detects anonymous parameters", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018), - reference: "issue #41686 ", + reason: fcw!(EditionError 2018 "trait-fn-parameters"), }; } @@ -1664,8 +1663,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { Warn, "`...` range patterns are deprecated", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021), - reference: "", + reason: fcw!(EditionError 2021 "warnings-promoted-to-error"), }; } @@ -1800,8 +1798,7 @@ fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) { Allow, "detects edition keywords being used as an identifier", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018), - reference: "issue #49716 ", + reason: fcw!(EditionError 2018 "new-keywords"), }; } @@ -1845,8 +1842,7 @@ fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) { Allow, "detects edition keywords being used as an identifier", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), - reference: "", + reason: fcw!(EditionError 2024 "gen-keyword"), }; } diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 2521c2b4eb6a..612d542a27de 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -11,9 +11,8 @@ extract_component_with_significant_dtor, ty_dtor_span, }; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::lint::{FutureIncompatibilityReason, LintId}; +use rustc_session::lint::{LintId, fcw}; use rustc_session::{declare_lint, impl_lint_pass}; -use rustc_span::edition::Edition; use rustc_span::{DUMMY_SP, Span}; use smallvec::SmallVec; @@ -86,8 +85,7 @@ "`if let` assigns a shorter lifetime to temporary values being pattern-matched against in Edition 2024 and \ rewriting in `match` is an option to preserve the semantics up to Edition 2021", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), - reference: "", + reason: fcw!(EditionSemanticsChange 2024 "temporary-if-let-scope"), }; } diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index f54afce0615f..2fc9d562dc56 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -19,9 +19,8 @@ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_middle::{bug, span_bug}; -use rustc_session::lint::FutureIncompatibilityReason; +use rustc_session::lint::fcw; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::edition::Edition; use rustc_span::{Span, Symbol}; use rustc_trait_selection::errors::{ AddPreciseCapturingForOvercapture, impl_trait_overcapture_suggestion, @@ -71,8 +70,7 @@ Allow, "`impl Trait` will capture more lifetimes than possibly intended in edition 2024", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), - reference: "", + reason: fcw!(EditionSemanticsChange 2024 "rpit-lifetime-capture"), }; } diff --git a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs index 7de6fbd941b4..f20605c91495 100644 --- a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs +++ b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs @@ -2,7 +2,7 @@ use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; -use rustc_session::lint::FutureIncompatibilityReason; +use rustc_session::lint::fcw; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::edition::Edition; use rustc_span::sym; @@ -72,8 +72,7 @@ "The `expr` fragment specifier will accept more expressions in the 2024 edition. \ To keep the existing behavior, use the `expr_2021` fragment specifier.", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), - reference: "Migration Guide ", + reason: fcw!(EditionSemanticsChange 2024 "macro-fragment-specifiers"), }; } diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 2eabeeaa88f9..f6295698b281 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -4,9 +4,8 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::{bug, ty}; use rustc_parse_format::{ParseMode, Parser, Piece}; -use rustc_session::lint::FutureIncompatibilityReason; +use rustc_session::lint::fcw; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::edition::Edition; use rustc_span::{InnerSpan, Span, Symbol, hygiene, sym}; use rustc_trait_selection::infer::InferCtxtExt; @@ -38,7 +37,7 @@ Warn, "detect single-argument panic!() invocations in which the argument is not a format string", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021), + reason: fcw!(EditionSemanticsChange 2021 "panic-macro-consistency"), explain_reason: false, }; report_in_external_macro diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs index cfb2a7fb6186..05bb2113db09 100644 --- a/compiler/rustc_lint/src/shadowed_into_iter.rs +++ b/compiler/rustc_lint/src/shadowed_into_iter.rs @@ -1,8 +1,7 @@ use rustc_hir::{self as hir, LangItem}; use rustc_middle::ty::{self, Ty}; -use rustc_session::lint::FutureIncompatibilityReason; +use rustc_session::lint::fcw; use rustc_session::{declare_lint, impl_lint_pass}; -use rustc_span::edition::Edition; use crate::lints::{ShadowedIntoIterDiag, ShadowedIntoIterDiagSub}; use crate::{LateContext, LateLintPass, LintContext}; @@ -31,8 +30,7 @@ Warn, "detects calling `into_iter` on arrays in Rust 2015 and 2018", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021), - reference: "", + reason: fcw!(EditionSemanticsChange 2021 "IntoIterator-for-arrays"), }; } @@ -60,8 +58,7 @@ Warn, "detects calling `into_iter` on boxed slices in Rust 2015, 2018, and 2021", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), - reference: "" + reason: fcw!(EditionSemanticsChange 2024 "intoiterator-box-slice"), }; } diff --git a/compiler/rustc_lint/src/static_mut_refs.rs b/compiler/rustc_lint/src/static_mut_refs.rs index 1c0df1f4234a..1decb4b78e61 100644 --- a/compiler/rustc_lint/src/static_mut_refs.rs +++ b/compiler/rustc_lint/src/static_mut_refs.rs @@ -1,9 +1,8 @@ use rustc_hir as hir; use rustc_hir::{Expr, Stmt}; use rustc_middle::ty::{Mutability, TyKind}; -use rustc_session::lint::FutureIncompatibilityReason; +use rustc_session::lint::fcw; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::edition::Edition; use rustc_span::{BytePos, Span}; use crate::lints::{MutRefSugg, RefOfMutStatic}; @@ -53,8 +52,7 @@ Warn, "creating a shared reference to mutable static", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), - reference: "", + reason: fcw!(EditionError 2024 "static-mut-references"), explain_reason: false, }; @edition Edition2024 => Deny; diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 740530daf2bd..baecc14424ec 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -7,9 +7,7 @@ //! When removing a lint, make sure to also add a call to `register_removed` in //! compiler/rustc_lint/src/lib.rs. -use rustc_span::edition::Edition; - -use crate::{FutureIncompatibilityReason, declare_lint, declare_lint_pass}; +use crate::{declare_lint, declare_lint_pass, fcw}; declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s @@ -182,8 +180,7 @@ Warn, "applying forbid to lint-groups", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #81670 ", + reason: fcw!(FutureReleaseError #81670), report_in_deps: true, }; } @@ -219,8 +216,7 @@ Deny, "ill-formed attribute inputs that were previously accepted and used in practice", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #57571 ", + reason: fcw!(FutureReleaseError #57571), report_in_deps: true, }; crate_level_only @@ -257,8 +253,7 @@ Deny, "conflicts between `#[repr(..)]` hints that were previously accepted and used in practice", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #68585 ", + reason: fcw!(FutureReleaseError #68585), report_in_deps: true, }; } @@ -1267,8 +1262,7 @@ Deny, "detect public re-exports of private extern crates", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #127909 ", + reason: fcw!(FutureReleaseError #127909), report_in_deps: true, }; } @@ -1298,8 +1292,7 @@ Deny, "type parameter default erroneously allowed in invalid location", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #36887 ", + reason: fcw!(FutureReleaseError #36887), report_in_deps: true, }; } @@ -1438,8 +1431,7 @@ Deny, "patterns in functions without body were erroneously allowed", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #35203 ", + reason: fcw!(FutureReleaseError #35203), }; } @@ -1480,8 +1472,7 @@ Warn, "detects generic lifetime arguments in path segments with late bound lifetime parameters", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #42868 ", + reason: fcw!(FutureReleaseError #42868), }; } @@ -1520,8 +1511,7 @@ Warn, "distinct impls distinguished only by the leak-check code", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::Custom("the behavior may change in a future release"), - reference: "issue #56105 ", + reason: fcw!("the behavior may change in a future release" #56105), }; } @@ -1624,8 +1614,7 @@ Allow, "detects patterns whose meaning will change in Rust 2024", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), - reference: "", + reason: fcw!(EditionSemanticsChange 2024 "match-ergonomics"), }; } @@ -1772,8 +1761,7 @@ Warn, "raw pointer to an inference variable", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018), - reference: "issue #46906 ", + reason: fcw!(EditionError 2018 "tyvar-behind-raw-pointer"), }; } @@ -1839,8 +1827,7 @@ Warn, "suggest using `dyn Trait` for trait objects", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021), - reference: "", + reason: fcw!(EditionError 2021 "warnings-promoted-to-error"), }; } @@ -1894,8 +1881,7 @@ "fully qualified paths that start with a module name \ instead of `crate`, `self`, or an extern crate name", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018), - reference: "issue #53130 ", + reason: fcw!(EditionError 2018 "path-changes"), }; } @@ -1942,11 +1928,11 @@ Warn, "detects name collision with an existing but unstable method", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::Custom( + reason: fcw!( "once this associated item is added to the standard library, \ the ambiguity may cause an error or change in behavior!" + #48919 ), - reference: "issue #48919 ", // Note: this item represents future incompatibility of all unstable functions in the // standard library, and thus should never be removed or changed to an error. }; @@ -2075,8 +2061,7 @@ Deny, "detects proc macro derives using inaccessible names from parent modules", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #83583 ", + reason: fcw!(FutureReleaseError #83583), report_in_deps: true, }; } @@ -2179,8 +2164,7 @@ "macro-expanded `macro_export` macros from the current crate \ cannot be referred to by absolute paths", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #52234 ", + reason: fcw!(FutureReleaseError #52234), report_in_deps: true, }; crate_level_only @@ -2301,8 +2285,7 @@ Deny, "ambiguous associated items", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #57644 ", + reason: fcw!(FutureReleaseError #57644), }; } @@ -2317,8 +2300,7 @@ Deny, "a feature gate that doesn't break dependent crates", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #64266 ", + reason: fcw!(FutureReleaseError #64266), report_in_deps: true, }; } @@ -2529,8 +2511,7 @@ Allow, "unsafe operations in unsafe functions without an explicit unsafe block are deprecated", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), - reference: "", + reason: fcw!(EditionError 2024 "unsafe-op-in-unsafe-fn"), explain_reason: false }; @edition Edition2024 => Warn; @@ -2661,8 +2642,7 @@ Warn, "detects a generic constant is used in a type without a emitting a warning", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #76200 ", + reason: fcw!(FutureReleaseError #76200), }; } @@ -2720,8 +2700,7 @@ Warn, "uninhabited static", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #74840 ", + reason: fcw!(FutureReleaseError #74840), }; } @@ -2853,8 +2832,7 @@ Warn, "detect unsupported use of `Self` from outer item", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #124186 ", + reason: fcw!(FutureReleaseError #124186), }; } @@ -2899,8 +2877,7 @@ Deny, "trailing semicolon in macro body used as expression", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #79813 ", + reason: fcw!(FutureReleaseError #79813), report_in_deps: true, }; } @@ -2947,8 +2924,7 @@ Deny, "detects derive helper attributes that are used before they are introduced", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #79202 ", + reason: fcw!(FutureReleaseError #79202), report_in_deps: true, }; } @@ -3131,8 +3107,7 @@ Deny, "transparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #78586 ", + reason: fcw!(FutureReleaseError #78586), report_in_deps: true, }; } @@ -3183,8 +3158,7 @@ Warn, "unstable syntax can change at any point in the future, causing a hard error!", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #65860 ", + reason: fcw!(FutureReleaseError #65860), }; } @@ -3425,7 +3399,7 @@ Allow, "detects closures affected by Rust 2021 changes", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021), + reason: fcw!(EditionSemanticsChange 2021 "disjoint-capture-in-closures"), explain_reason: false, }; } @@ -3520,8 +3494,7 @@ Allow, "detects usage of old versions of or-patterns", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021), - reference: "", + reason: fcw!(EditionError 2021 "or-patterns-macro-rules"), }; } @@ -3569,8 +3542,7 @@ "detects the usage of trait methods which are ambiguous with traits added to the \ prelude in future editions", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021), - reference: "", + reason: fcw!(EditionError 2021 "prelude"), }; } @@ -3609,8 +3581,7 @@ "detects the usage of trait methods which are ambiguous with traits added to the \ prelude in future editions", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), - reference: "", + reason: fcw!(EditionError 2024 "prelude"), }; } @@ -3646,8 +3617,7 @@ Allow, "identifiers that will be parsed as a prefix in Rust 2021", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021), - reference: "", + reason: fcw!(EditionError 2021 "reserving-syntax"), }; crate_level_only } @@ -3694,9 +3664,8 @@ Warn, "use of unsupported calling convention", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, + reason: fcw!(FutureReleaseError #137018), report_in_deps: false, - reference: "issue #137018 ", }; } @@ -3739,8 +3708,7 @@ Warn, "use of unsupported calling convention for function pointer", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #130260 ", + reason: fcw!(FutureReleaseError #130260), report_in_deps: true, }; } @@ -4174,8 +4142,7 @@ Deny, "never type fallback affecting unsafe function calls", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(Edition::Edition2024), - reference: "", + reason: fcw!(EditionAndFutureReleaseSemanticsChange 2024 "never-type-fallback"), report_in_deps: true, }; @edition Edition2024 => Deny; @@ -4229,8 +4196,7 @@ Deny, "never type fallback affecting unsafe function calls", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionAndFutureReleaseError(Edition::Edition2024), - reference: "", + reason: fcw!(EditionAndFutureReleaseError 2024 "never-type-fallback"), report_in_deps: true, }; report_in_external_macro @@ -4265,8 +4231,7 @@ Deny, "\"invalid_parameter\" isn't a valid argument for `#[macro_export]`", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #57571 ", + reason: fcw!(FutureReleaseError #57571), report_in_deps: true, }; } @@ -4503,8 +4468,7 @@ Deny, "detects certain glob imports that require reporting an ambiguity error", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #114095 ", + reason: fcw!(FutureReleaseError #114095), report_in_deps: true, }; } @@ -4659,8 +4623,7 @@ Deny, "elided lifetimes cannot be used in associated constants in impls", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #115010 ", + reason: fcw!(FutureReleaseError #115010), }; } @@ -4706,8 +4669,7 @@ Deny, "detects certain macro bindings that should not be re-exported", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #120192 ", + reason: fcw!(FutureReleaseError #120192), report_in_deps: true, }; } @@ -4772,8 +4734,7 @@ Warn, "impl contains type parameters that are not covered", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #124559 ", + reason: fcw!(FutureReleaseError #124559), }; } @@ -4820,8 +4781,7 @@ Allow, "detects unsafe functions being used as safe functions", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), - reference: "", + reason: fcw!(EditionError 2024 "newly-unsafe-functions"), }; } @@ -4856,8 +4816,7 @@ Allow, "detects missing unsafe keyword on extern declarations", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), - reference: "", + reason: fcw!(EditionError 2024 "unsafe-extern"), }; } @@ -4897,8 +4856,7 @@ Allow, "detects unsafe attributes outside of unsafe", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), - reference: "", + reason: fcw!(EditionError 2024 "unsafe-attributes"), }; } @@ -4936,8 +4894,7 @@ Deny, "detects out of scope calls to `macro_rules` in key-value attributes", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #124535 ", + reason: fcw!(FutureReleaseError #124535), report_in_deps: true, }; } @@ -5099,8 +5056,7 @@ Allow, "Detect and warn on significant change in drop order in tail expression location", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), - reference: "", + reason: fcw!(EditionSemanticsChange 2024 "temporary-tail-expr-scope"), }; } @@ -5138,8 +5094,7 @@ Allow, "will be parsed as a guarded string in Rust 2024", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), - reference: "", + reason: fcw!(EditionError 2024 "reserved-syntax"), }; crate_level_only } @@ -5180,8 +5135,7 @@ Warn, "detects code that could be affected by ABI issues on aarch64 softfloat targets", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #134375 ", + reason: fcw!(FutureReleaseError #134375), report_in_deps: true, }; } @@ -5316,8 +5270,7 @@ Warn, "repr(C) enums with discriminant values that do not fit into a C int", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #124403 ", + reason: fcw!(FutureReleaseError #124403), report_in_deps: false, }; } @@ -5363,8 +5316,7 @@ Warn, "detects usage of `...` arguments without a pattern in non-foreign items", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #145544 ", + reason: fcw!(FutureReleaseError #145544), report_in_deps: false, }; } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 376310838cc7..1efb8355ca93 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::fmt::Display; use rustc_ast::AttrId; use rustc_ast::attr::AttributeExt; @@ -356,8 +357,6 @@ pub struct Lint { /// Extra information for a future incompatibility lint. #[derive(Copy, Clone, Debug)] pub struct FutureIncompatibleInfo { - /// e.g., a URL for an issue/PR/RFC or error code - pub reference: &'static str, /// The reason for the lint used by diagnostics to provide /// the right help message pub reason: FutureIncompatibilityReason, @@ -380,6 +379,17 @@ pub struct FutureIncompatibleInfo { pub report_in_deps: bool, } +#[derive(Copy, Clone, Debug)] +pub struct EditionFcw { + pub edition: Edition, + pub page_slug: &'static str, +} + +#[derive(Copy, Clone, Debug)] +pub struct ReleaseFcw { + pub issue_number: usize, +} + /// The reason for future incompatibility /// /// Future-incompatible lints come in roughly two categories: @@ -409,14 +419,14 @@ pub enum FutureIncompatibilityReason { /// hard errors (and the lint removed). Preferably when there is some /// confidence that the number of impacted projects is very small (few /// should have a broken dependency in their dependency tree). - FutureReleaseError, + FutureReleaseError(ReleaseFcw), /// Code that changes meaning in some way in a /// future release. /// /// Choose this variant when the semantics of existing code is changing, /// (as opposed to [`FutureIncompatibilityReason::FutureReleaseError`], /// which is for when code is going to be rejected in the future). - FutureReleaseSemanticsChange, + FutureReleaseSemanticsChange(ReleaseFcw), /// Previously accepted code that will become an /// error in the provided edition /// @@ -437,7 +447,7 @@ pub enum FutureIncompatibilityReason { /// See also [`FutureIncompatibilityReason::EditionSemanticsChange`] if /// you have code that is changing semantics across the edition (as /// opposed to being rejected). - EditionError(Edition), + EditionError(EditionFcw), /// Code that changes meaning in some way in /// the provided edition /// @@ -445,7 +455,7 @@ pub enum FutureIncompatibilityReason { /// except for situations where the semantics change across an edition. It /// slightly changes the text of the diagnostic, but is otherwise the /// same. - EditionSemanticsChange(Edition), + EditionSemanticsChange(EditionFcw), /// This will be an error in the provided edition *and* in a future /// release. /// @@ -455,7 +465,7 @@ pub enum FutureIncompatibilityReason { /// /// [`EditionError`]: FutureIncompatibilityReason::EditionError /// [`FutureReleaseError`]: FutureIncompatibilityReason::FutureReleaseError - EditionAndFutureReleaseError(Edition), + EditionAndFutureReleaseError(EditionFcw), /// This will change meaning in the provided edition *and* in a future /// release. /// @@ -466,14 +476,29 @@ pub enum FutureIncompatibilityReason { /// /// [`EditionSemanticsChange`]: FutureIncompatibilityReason::EditionSemanticsChange /// [`FutureReleaseSemanticsChange`]: FutureIncompatibilityReason::FutureReleaseSemanticsChange - EditionAndFutureReleaseSemanticsChange(Edition), + EditionAndFutureReleaseSemanticsChange(EditionFcw), /// A custom reason. /// /// Choose this variant if the built-in text of the diagnostic of the /// other variants doesn't match your situation. This is behaviorally /// equivalent to /// [`FutureIncompatibilityReason::FutureReleaseError`]. - Custom(&'static str), + Custom(&'static str, ReleaseFcw), + + /// Using the declare_lint macro a reason always needs to be specified. + /// So, this case can't actually be reached but a variant needs to exist for it. + /// Any code panics on seeing this varaint. Do not use. + Unreachable, +} + +impl FutureIncompatibleInfo { + pub const fn default_fields_for_macro() -> Self { + FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::Unreachable, + explain_reason: true, + report_in_deps: false, + } + } } impl FutureIncompatibilityReason { @@ -482,23 +507,52 @@ pub fn edition(self) -> Option { Self::EditionError(e) | Self::EditionSemanticsChange(e) | Self::EditionAndFutureReleaseError(e) - | Self::EditionAndFutureReleaseSemanticsChange(e) => Some(e), + | Self::EditionAndFutureReleaseSemanticsChange(e) => Some(e.edition), - FutureIncompatibilityReason::FutureReleaseError - | FutureIncompatibilityReason::FutureReleaseSemanticsChange - | FutureIncompatibilityReason::Custom(_) => None, + FutureIncompatibilityReason::FutureReleaseError(_) + | FutureIncompatibilityReason::FutureReleaseSemanticsChange(_) + | FutureIncompatibilityReason::Custom(_, _) => None, + Self::Unreachable => unreachable!(), + } + } + + fn fmt_reason(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::FutureReleaseSemanticsChange(release_fcw) + | Self::FutureReleaseError(release_fcw) + | Self::Custom(_, release_fcw) => release_fcw.fmt_reason(f), + Self::EditionError(edition_fcw) + | Self::EditionSemanticsChange(edition_fcw) + | Self::EditionAndFutureReleaseError(edition_fcw) + | Self::EditionAndFutureReleaseSemanticsChange(edition_fcw) => { + edition_fcw.fmt_reason(f) + } + Self::Unreachable => unreachable!(), } } } -impl FutureIncompatibleInfo { - pub const fn default_fields_for_macro() -> Self { - FutureIncompatibleInfo { - reference: "", - reason: FutureIncompatibilityReason::FutureReleaseError, - explain_reason: true, - report_in_deps: false, - } +impl ReleaseFcw { + fn fmt_reason(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let issue_number = self.issue_number; + write!(f, "issue #{issue_number} ") + } +} + +impl EditionFcw { + fn fmt_reason(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "", + match self.edition { + Edition::Edition2015 => "rust-2015", + Edition::Edition2018 => "rust-2018", + Edition::Edition2021 => "rust-2021", + Edition::Edition2024 => "rust-2024", + Edition::EditionFuture => "future", + }, + self.page_slug, + ) } } @@ -901,3 +955,53 @@ macro_rules! declare_lint_pass { $crate::impl_lint_pass!($name => [$($lint),*]); }; } + +#[macro_export] +macro_rules! fcw { + (FutureReleaseError # $issue_number: literal) => { + $crate:: FutureIncompatibilityReason::FutureReleaseError($crate::ReleaseFcw { issue_number: $issue_number }) + }; + (FutureReleaseSemanticsChange # $issue_number: literal) => { + $crate::FutureIncompatibilityReason::FutureReleaseSemanticsChange($crate::ReleaseFcw { + issue_number: $issue_number, + }) + }; + ($description: literal # $issue_number: literal) => { + $crate::FutureIncompatibilityReason::Custom($description, $crate::ReleaseFcw { + issue_number: $issue_number, + }) + }; + (EditionError $edition_name: tt $page_slug: literal) => { + $crate::FutureIncompatibilityReason::EditionError($crate::EditionFcw { + edition: fcw!(@edition $edition_name), + page_slug: $page_slug, + }) + }; + (EditionSemanticsChange $edition_name: tt $page_slug: literal) => { + $crate::FutureIncompatibilityReason::EditionSemanticsChange($crate::EditionFcw { + edition: fcw!(@edition $edition_name), + page_slug: $page_slug, + }) + }; + (EditionAndFutureReleaseSemanticsChange $edition_name: tt $page_slug: literal) => { + $crate::FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange($crate::EditionFcw { + edition: fcw!(@edition $edition_name), + page_slug: $page_slug, + }) + }; + (EditionAndFutureReleaseError $edition_name: tt $page_slug: literal) => { + $crate::FutureIncompatibilityReason::EditionAndFutureReleaseError($crate::EditionFcw { + edition: fcw!(@edition $edition_name), + page_slug: $page_slug, + }) + }; + (@edition 2024) => { + rustc_span::edition::Edition::Edition2024 + }; + (@edition 2021) => { + rustc_span::edition::Edition::Edition2021 + }; + (@edition 2018) => { + rustc_span::edition::Edition::Edition2018 + }; +} diff --git a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md index 6b13c97023f5..92488e8daeab 100644 --- a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md +++ b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md @@ -113,7 +113,7 @@ store.register_future_incompatible(sess, vec![ ..., FutureIncompatibleInfo { id: LintId::of(YOUR_ERROR_HERE), - reference: "issue #1234", // your tracking issue here! + reason: fcw!(FutureReleaseError #1234) // your tracking issue here! }, ]); @@ -238,7 +238,7 @@ compatibility lint": ```rust FutureIncompatibleInfo { id: LintId::of(OVERLAPPING_INHERENT_IMPLS), - reference: "issue #36889 ", + reason: fcw!(FutureReleaseError #1234), // your tracking issue here! }, ``` diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md index 82191e0a6eaf..89c18b8e40f1 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics.md +++ b/src/doc/rustc-dev-guide/src/diagnostics.md @@ -732,8 +732,7 @@ declare_lint! { Allow, "detects anonymous parameters", @future_incompatible = FutureIncompatibleInfo { - reference: "issue #41686 ", - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018), + reason: fcw!(EditionError 2018 "slug-of-edition-guide-page") }; } ``` diff --git a/src/doc/rustc-dev-guide/src/guides/editions.md b/src/doc/rustc-dev-guide/src/guides/editions.md index 107d5e737e83..535d82f8403b 100644 --- a/src/doc/rustc-dev-guide/src/guides/editions.md +++ b/src/doc/rustc-dev-guide/src/guides/editions.md @@ -179,8 +179,7 @@ declare_lint! { Allow, "detects edition keywords being used as an identifier", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018), - reference: "issue #49716 ", + reason: fcw!(EditionError 2018 "slug-of-edition-guide-page") }; } ``` From 1eabe65151de970f14a41c85a877db79d8b3c430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 10 Dec 2025 12:58:21 +0100 Subject: [PATCH 484/585] adapt formatting to use new fcw info structure --- compiler/rustc_hir_typeck/src/upvar.rs | 1 - compiler/rustc_lint_defs/src/builtin.rs | 1 - compiler/rustc_lint_defs/src/lib.rs | 16 ++++++------- compiler/rustc_middle/src/lint.rs | 32 +++++++++++++++---------- compiler/rustc_session/src/parse.rs | 2 +- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 0a7b458f3fb3..445386412058 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -1043,7 +1043,6 @@ fn perform_2229_migration_analysis( } } } - lint.note("for more information, see "); let diagnostic_msg = format!( "add a dummy let to cause {migrated_variables_concat} to be fully captured" diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index baecc14424ec..93bd7f03c8b2 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3400,7 +3400,6 @@ "detects closures affected by Rust 2021 changes", @future_incompatible = FutureIncompatibleInfo { reason: fcw!(EditionSemanticsChange 2021 "disjoint-capture-in-closures"), - explain_reason: false, }; } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 1efb8355ca93..d2219d11bece 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -516,31 +516,29 @@ pub fn edition(self) -> Option { } } - fn fmt_reason(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + pub fn reference(&self) -> String { match self { Self::FutureReleaseSemanticsChange(release_fcw) | Self::FutureReleaseError(release_fcw) - | Self::Custom(_, release_fcw) => release_fcw.fmt_reason(f), + | Self::Custom(_, release_fcw) => release_fcw.to_string(), Self::EditionError(edition_fcw) | Self::EditionSemanticsChange(edition_fcw) | Self::EditionAndFutureReleaseError(edition_fcw) - | Self::EditionAndFutureReleaseSemanticsChange(edition_fcw) => { - edition_fcw.fmt_reason(f) - } + | Self::EditionAndFutureReleaseSemanticsChange(edition_fcw) => edition_fcw.to_string(), Self::Unreachable => unreachable!(), } } } -impl ReleaseFcw { - fn fmt_reason(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl Display for ReleaseFcw { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let issue_number = self.issue_number; write!(f, "issue #{issue_number} ") } } -impl EditionFcw { - fn fmt_reason(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl Display for EditionFcw { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "", diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index f70b7b6fad7a..bed902e8334b 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -4,6 +4,7 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::{Diag, MultiSpan}; use rustc_hir::{HirId, ItemLocalId}; +use rustc_lint_defs::EditionFcw; use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_session::Session; use rustc_session::lint::builtin::{self, FORBIDDEN_LINT_GROUPS}; @@ -395,45 +396,52 @@ fn lint_level_impl( if let Some(future_incompatible) = future_incompatible { let explanation = match future_incompatible.reason { - FutureIncompatibilityReason::FutureReleaseError => { + FutureIncompatibilityReason::FutureReleaseError(_) => { "this was previously accepted by the compiler but is being phased out; \ it will become a hard error in a future release!" .to_owned() } - FutureIncompatibilityReason::FutureReleaseSemanticsChange => { + FutureIncompatibilityReason::FutureReleaseSemanticsChange(_) => { "this will change its meaning in a future release!".to_owned() } - FutureIncompatibilityReason::EditionError(edition) => { + FutureIncompatibilityReason::EditionError(EditionFcw { edition, .. }) => { let current_edition = sess.edition(); format!( "this is accepted in the current edition (Rust {current_edition}) but is a hard error in Rust {edition}!" ) } - FutureIncompatibilityReason::EditionSemanticsChange(edition) => { + FutureIncompatibilityReason::EditionSemanticsChange(EditionFcw { + edition, .. + }) => { format!("this changes meaning in Rust {edition}") } - FutureIncompatibilityReason::EditionAndFutureReleaseError(edition) => { + FutureIncompatibilityReason::EditionAndFutureReleaseError(EditionFcw { + edition, + .. + }) => { format!( "this was previously accepted by the compiler but is being phased out; \ it will become a hard error in Rust {edition} and in a future release in all editions!" ) } - FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(edition) => { + FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange( + EditionFcw { edition, .. }, + ) => { format!( "this changes meaning in Rust {edition} and in a future release in all editions!" ) } - FutureIncompatibilityReason::Custom(reason) => reason.to_owned(), + FutureIncompatibilityReason::Custom(reason, _) => reason.to_owned(), + FutureIncompatibilityReason::Unreachable => unreachable!(), }; if future_incompatible.explain_reason { err.warn(explanation); } - if !future_incompatible.reference.is_empty() { - let citation = - format!("for more information, see {}", future_incompatible.reference); - err.note(citation); - } + + let citation = + format!("for more information, see {}", future_incompatible.reason.reference()); + err.note(citation); } // Finally, run `decorate`. `decorate` can call `trimmed_path_str` (directly or indirectly), diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 8c70e18fb66d..edc5ae9e6f63 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -150,7 +150,7 @@ pub fn feature_warn_issue( let future_incompatible = lint.future_incompatible.as_ref().unwrap(); err.is_lint(lint.name_lower(), /* has_future_breakage */ false); err.warn(lint.desc); - err.note(format!("for more information, see {}", future_incompatible.reference)); + err.note(format!("for more information, see {}", future_incompatible.reason.reference())); // A later feature_err call can steal and cancel this warning. err.stash(span, StashKey::EarlySyntaxWarning); From 1ef1ec13d8d22bc768de42e55f09b2803c4e9735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 10 Dec 2025 13:38:07 +0100 Subject: [PATCH 485/585] bless the tests --- compiler/rustc_lint_defs/src/builtin.rs | 1 + compiler/rustc_lint_defs/src/lib.rs | 2 +- .../anon-params/anon-params-deprecated.stderr | 6 ++-- ...015-edition-error-various-positions.stderr | 20 +++++------ .../await-keyword/2015-edition-warning.stderr | 12 +++---- ...ice-mutability-error-slicing-121807.stderr | 2 +- .../trait-impl-argument-difference-ice.stderr | 2 +- .../const_panic_stability.e2018.stderr | 1 + ...dyn-2015-edition-keyword-ident-lint.stderr | 28 +++++++-------- .../edition-raw-pointer-method-2015.stderr | 2 +- ...89280-emitter-overflow-splice-lines.stderr | 2 +- tests/ui/fn/error-recovery-mismatch.stderr | 2 +- ...ference-variable-behind-raw-pointer.stderr | 2 +- tests/ui/lang-items/issue-83471.stderr | 2 +- .../future-incompatible-lint-group.stderr | 2 +- .../lint-pre-expansion-extern-module.stderr | 2 +- .../macros/expr_2021_cargo_fix_edition.stderr | 4 +-- tests/ui/macros/non-fmt-panic.stderr | 35 +++++++++++++++++++ tests/ui/rust-2018/async-ident-allowed.stderr | 2 +- tests/ui/rust-2018/async-ident.stderr | 28 +++++++-------- tests/ui/rust-2018/dyn-keyword.stderr | 2 +- .../edition-lint-fully-qualified-paths.stderr | 6 ++-- .../edition-lint-nested-empty-paths.stderr | 10 +++--- .../edition-lint-nested-paths.stderr | 8 ++--- tests/ui/rust-2018/edition-lint-paths.stderr | 18 +++++----- tests/ui/rust-2018/extern-crate-rename.stderr | 2 +- tests/ui/rust-2018/extern-crate-submod.stderr | 2 +- tests/ui/rust-2018/try-ident.stderr | 4 +-- tests/ui/rust-2018/try-macro.stderr | 2 +- ...ice-unwrap-probe-many-result-125876.stderr | 4 +-- 30 files changed, 126 insertions(+), 89 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 93bd7f03c8b2..baecc14424ec 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3400,6 +3400,7 @@ "detects closures affected by Rust 2021 changes", @future_incompatible = FutureIncompatibleInfo { reason: fcw!(EditionSemanticsChange 2021 "disjoint-capture-in-closures"), + explain_reason: false, }; } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index d2219d11bece..d5f5c8740d0d 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -487,7 +487,7 @@ pub enum FutureIncompatibilityReason { /// Using the declare_lint macro a reason always needs to be specified. /// So, this case can't actually be reached but a variant needs to exist for it. - /// Any code panics on seeing this varaint. Do not use. + /// Any code panics on seeing this variant. Do not use. Unreachable, } diff --git a/tests/ui/anon-params/anon-params-deprecated.stderr b/tests/ui/anon-params/anon-params-deprecated.stderr index 541cb004b5b2..0f508bad70b4 100644 --- a/tests/ui/anon-params/anon-params-deprecated.stderr +++ b/tests/ui/anon-params/anon-params-deprecated.stderr @@ -5,7 +5,7 @@ LL | fn foo(i32); | ^^^ help: try naming the parameter or explicitly ignoring it: `_: i32` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #41686 + = note: for more information, see note: the lint level is defined here --> $DIR/anon-params-deprecated.rs:1:9 | @@ -19,7 +19,7 @@ LL | fn bar_with_default_impl(String, String) {} | ^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: String` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #41686 + = note: for more information, see warning: anonymous parameters are deprecated and will be removed in the next edition --> $DIR/anon-params-deprecated.rs:13:38 @@ -28,7 +28,7 @@ LL | fn bar_with_default_impl(String, String) {} | ^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: String` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #41686 + = note: for more information, see warning: 3 warnings emitted diff --git a/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr b/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr index 70900e612f48..a2be23099415 100644 --- a/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr +++ b/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr @@ -5,7 +5,7 @@ LL | pub mod await { | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see note: the lint level is defined here --> $DIR/2015-edition-error-various-positions.rs:3:9 | @@ -20,7 +20,7 @@ LL | pub struct await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-error-various-positions.rs:12:16 @@ -29,7 +29,7 @@ LL | use outer_mod::await::await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-error-various-positions.rs:12:23 @@ -38,7 +38,7 @@ LL | use outer_mod::await::await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-error-various-positions.rs:17:14 @@ -47,7 +47,7 @@ LL | struct Foo { await: () } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-error-various-positions.rs:21:15 @@ -56,7 +56,7 @@ LL | impl Foo { fn await() {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-error-various-positions.rs:25:14 @@ -65,7 +65,7 @@ LL | macro_rules! await { | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-error-various-positions.rs:32:5 @@ -74,7 +74,7 @@ LL | await!(); | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-error-various-positions.rs:35:11 @@ -83,7 +83,7 @@ LL | match await { await => {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-error-various-positions.rs:35:19 @@ -92,7 +92,7 @@ LL | match await { await => {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: aborting due to 10 previous errors diff --git a/tests/ui/async-await/await-keyword/2015-edition-warning.stderr b/tests/ui/async-await/await-keyword/2015-edition-warning.stderr index 9d19a09092b9..97c69f2e7288 100644 --- a/tests/ui/async-await/await-keyword/2015-edition-warning.stderr +++ b/tests/ui/async-await/await-keyword/2015-edition-warning.stderr @@ -5,7 +5,7 @@ LL | pub mod await { | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see note: the lint level is defined here --> $DIR/2015-edition-warning.rs:5:9 | @@ -20,7 +20,7 @@ LL | pub struct await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-warning.rs:16:16 @@ -29,7 +29,7 @@ LL | use outer_mod::await::await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-warning.rs:16:23 @@ -38,7 +38,7 @@ LL | use outer_mod::await::await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-warning.rs:23:11 @@ -47,7 +47,7 @@ LL | match await { await => {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-warning.rs:23:19 @@ -56,7 +56,7 @@ LL | match await { await => {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: aborting due to 6 previous errors diff --git a/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr b/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr index 8e1cd800b372..54aa756e581d 100644 --- a/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr +++ b/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr @@ -20,7 +20,7 @@ LL | extern "C" fn read_dword(Self::Assoc<'_>) -> u16; | ^^^^^^^^^^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: Self::Assoc<'_>` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #41686 + = note: for more information, see = note: `#[warn(anonymous_parameters)]` (part of `#[warn(rust_2018_compatibility)]`) on by default error[E0185]: method `read_dword` has a `&self` declaration in the impl, but not in the trait diff --git a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr index 34fd29a8b50c..df1a5ce909a1 100644 --- a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr +++ b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr @@ -5,7 +5,7 @@ LL | extern "C" fn read_dword(Self::Assoc<'_>) -> u16; | ^^^^^^^^^^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: Self::Assoc<'_>` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #41686 + = note: for more information, see = note: `#[warn(anonymous_parameters)]` (part of `#[warn(rust_2018_compatibility)]`) on by default error[E0185]: method `read_dword` has a `&self` declaration in the impl, but not in the trait diff --git a/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr b/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr index 943695d75fce..c33d5b003042 100644 --- a/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr +++ b/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr @@ -4,6 +4,7 @@ warning: panic message is not a string literal LL | panic!({ "foo" }); | ^^^^^^^^^ | + = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see = note: `#[warn(non_fmt_panics)]` (part of `#[warn(rust_2021_compatibility)]`) on by default diff --git a/tests/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr b/tests/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr index 0d53fb024aca..c0e794cee292 100644 --- a/tests/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr +++ b/tests/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr @@ -5,7 +5,7 @@ LL | pub mod dyn { | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see note: the lint level is defined here --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:11:9 | @@ -20,7 +20,7 @@ LL | pub struct dyn; | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:22:16 @@ -29,7 +29,7 @@ LL | use outer_mod::dyn::dyn; | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:22:21 @@ -38,7 +38,7 @@ LL | use outer_mod::dyn::dyn; | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:29:11 @@ -47,7 +47,7 @@ LL | match dyn { dyn => {} } | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:29:17 @@ -56,7 +56,7 @@ LL | match dyn { dyn => {} } | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:34:17 @@ -65,7 +65,7 @@ LL | macro_defn::dyn(); | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:44:18 @@ -74,7 +74,7 @@ LL | macro_rules! dyn { | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:52:12 @@ -83,7 +83,7 @@ LL | pub fn dyn() -> ::outer_mod::dyn::dyn { | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:52:34 @@ -92,7 +92,7 @@ LL | pub fn dyn() -> ::outer_mod::dyn::dyn { | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:52:39 @@ -101,7 +101,7 @@ LL | pub fn dyn() -> ::outer_mod::dyn::dyn { | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:59:22 @@ -110,7 +110,7 @@ LL | ::outer_mod::dyn::dyn | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:59:27 @@ -119,7 +119,7 @@ LL | ::outer_mod::dyn::dyn | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:68:23 @@ -128,7 +128,7 @@ LL | pub fn boxed() -> dyn!( | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: aborting due to 14 previous errors diff --git a/tests/ui/editions/edition-raw-pointer-method-2015.stderr b/tests/ui/editions/edition-raw-pointer-method-2015.stderr index 3d8b3f633ce8..ad8beb049f9f 100644 --- a/tests/ui/editions/edition-raw-pointer-method-2015.stderr +++ b/tests/ui/editions/edition-raw-pointer-method-2015.stderr @@ -5,7 +5,7 @@ LL | let _ = y.is_null(); | ^^^^^^^ | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #46906 + = note: for more information, see note: the lint level is defined here --> $DIR/edition-raw-pointer-method-2015.rs:5:8 | diff --git a/tests/ui/errors/issue-89280-emitter-overflow-splice-lines.stderr b/tests/ui/errors/issue-89280-emitter-overflow-splice-lines.stderr index ed1ebe4466af..6878bde85b8b 100644 --- a/tests/ui/errors/issue-89280-emitter-overflow-splice-lines.stderr +++ b/tests/ui/errors/issue-89280-emitter-overflow-splice-lines.stderr @@ -8,7 +8,7 @@ LL | | )) {} | |_____^ | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #41686 + = note: for more information, see = note: `#[warn(anonymous_parameters)]` (part of `#[warn(rust_2018_compatibility)]`) on by default help: try naming the parameter or explicitly ignoring it | diff --git a/tests/ui/fn/error-recovery-mismatch.stderr b/tests/ui/fn/error-recovery-mismatch.stderr index 400af46e2a27..7a320c6bc695 100644 --- a/tests/ui/fn/error-recovery-mismatch.stderr +++ b/tests/ui/fn/error-recovery-mismatch.stderr @@ -26,7 +26,7 @@ LL | fn fold(&self, _: T, &self._) {} | ^ help: try naming the parameter or explicitly ignoring it: `_: _` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #41686 + = note: for more information, see = note: `#[warn(anonymous_parameters)]` (part of `#[warn(rust_2018_compatibility)]`) on by default error[E0121]: the placeholder `_` is not allowed within types on item signatures for methods diff --git a/tests/ui/inference/inference-variable-behind-raw-pointer.stderr b/tests/ui/inference/inference-variable-behind-raw-pointer.stderr index 50202ea3db3e..360d4dd22ceb 100644 --- a/tests/ui/inference/inference-variable-behind-raw-pointer.stderr +++ b/tests/ui/inference/inference-variable-behind-raw-pointer.stderr @@ -5,7 +5,7 @@ LL | if data.is_null() {} | ^^^^^^^ | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #46906 + = note: for more information, see = note: `#[warn(tyvar_behind_raw_pointer)]` (part of `#[warn(rust_2018_compatibility)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/lang-items/issue-83471.stderr b/tests/ui/lang-items/issue-83471.stderr index 0c2b403902e2..1d5b1c4cd3ed 100644 --- a/tests/ui/lang-items/issue-83471.stderr +++ b/tests/ui/lang-items/issue-83471.stderr @@ -47,7 +47,7 @@ LL | fn call(export_name); | ^^^^^^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: export_name` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #41686 + = note: for more information, see = note: `#[warn(anonymous_parameters)]` (part of `#[warn(rust_2018_compatibility)]`) on by default error[E0718]: `fn` lang item must be applied to a trait with 1 generic argument diff --git a/tests/ui/lint/future-incompatible-lint-group.stderr b/tests/ui/lint/future-incompatible-lint-group.stderr index bac24740fb4e..ff1e54f5dea3 100644 --- a/tests/ui/lint/future-incompatible-lint-group.stderr +++ b/tests/ui/lint/future-incompatible-lint-group.stderr @@ -5,7 +5,7 @@ LL | fn f(u8) {} | ^^ help: try naming the parameter or explicitly ignoring it: `_: u8` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #41686 + = note: for more information, see = note: `#[warn(anonymous_parameters)]` (part of `#[warn(rust_2018_compatibility)]`) on by default error: ambiguous associated item diff --git a/tests/ui/lint/lint-pre-expansion-extern-module.stderr b/tests/ui/lint/lint-pre-expansion-extern-module.stderr index 32c76da98b52..1de1784fc9c5 100644 --- a/tests/ui/lint/lint-pre-expansion-extern-module.stderr +++ b/tests/ui/lint/lint-pre-expansion-extern-module.stderr @@ -5,7 +5,7 @@ LL | pub fn try() {} | ^^^ help: you can use a raw identifier to stay compatible: `r#try` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see = note: `-W keyword-idents-2018` implied by `-W rust-2018-compatibility` = help: to override `-W rust-2018-compatibility` add `#[allow(keyword_idents_2018)]` diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.stderr b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr index 795d99449c26..17ec247bd4de 100644 --- a/tests/ui/macros/expr_2021_cargo_fix_edition.stderr +++ b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr @@ -5,7 +5,7 @@ LL | ($e:expr) => { | ^^^^ | = warning: this changes meaning in Rust 2024 - = note: for more information, see Migration Guide + = note: for more information, see note: the lint level is defined here --> $DIR/expr_2021_cargo_fix_edition.rs:4:9 | @@ -23,7 +23,7 @@ LL | ($($i:expr)*) => { }; | ^^^^ | = warning: this changes meaning in Rust 2024 - = note: for more information, see Migration Guide + = note: for more information, see help: to keep the existing behavior, use the `expr_2021` fragment specifier | LL | ($($i:expr_2021)*) => { }; diff --git a/tests/ui/macros/non-fmt-panic.stderr b/tests/ui/macros/non-fmt-panic.stderr index 43f59782ee72..8a89d5ea7939 100644 --- a/tests/ui/macros/non-fmt-panic.stderr +++ b/tests/ui/macros/non-fmt-panic.stderr @@ -4,6 +4,7 @@ warning: panic message contains a brace LL | panic!("here's a brace: {"); | ^ | + = note: for more information, see = note: this message is not used as a format string, but will be in Rust 2021 = note: `#[warn(non_fmt_panics)]` (part of `#[warn(rust_2021_compatibility)]`) on by default help: add a "{}" format string to use the message literally @@ -17,6 +18,7 @@ warning: panic message contains a brace LL | unreachable!("here's a brace: {"); | ^ | + = note: for more information, see = note: this message is not used as a format string, but will be in Rust 2021 help: add a "{}" format string to use the message literally | @@ -29,6 +31,7 @@ warning: panic message contains a brace LL | std::panic!("another one: }"); | ^ | + = note: for more information, see = note: this message is not used as a format string, but will be in Rust 2021 help: add a "{}" format string to use the message literally | @@ -41,6 +44,7 @@ warning: panic message contains an unused formatting placeholder LL | core::panic!("Hello {}"); | ^^ | + = note: for more information, see = note: this message is not used as a format string when given without arguments, but will be in Rust 2021 help: add the missing argument | @@ -57,6 +61,7 @@ warning: panic message contains unused formatting placeholders LL | assert!(false, "{:03x} {test} bla"); | ^^^^^^ ^^^^^^ | + = note: for more information, see = note: this message is not used as a format string when given without arguments, but will be in Rust 2021 help: add the missing arguments | @@ -73,6 +78,7 @@ warning: panic message is not a string literal LL | assert!(false, S); | ^ | + = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -86,6 +92,7 @@ warning: panic message is not a string literal LL | assert!(false, 123); | ^^^ | + = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -99,6 +106,7 @@ warning: panic message is not a string literal LL | assert!(false, Some(123)); | ^^^^^^^^^ | + = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{:?}" format string to use the `Debug` implementation of `Option` @@ -112,6 +120,7 @@ warning: panic message contains braces LL | debug_assert!(false, "{{}} bla"); | ^^^^ | + = note: for more information, see = note: this message is not used as a format string, but will be in Rust 2021 help: add a "{}" format string to use the message literally | @@ -124,6 +133,7 @@ warning: panic message is not a string literal LL | panic!(C); | ^ | + = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -137,6 +147,7 @@ warning: panic message is not a string literal LL | panic!(S); | ^ | + = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -150,6 +161,7 @@ warning: panic message is not a string literal LL | unreachable!(S); | ^ | + = note: for more information, see = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -163,6 +175,7 @@ warning: panic message is not a string literal LL | unreachable!(S); | ^ | + = note: for more information, see = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -176,6 +189,7 @@ warning: panic message is not a string literal LL | std::panic!(123); | ^^^ | + = note: for more information, see = note: this usage of `std::panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -194,6 +208,7 @@ warning: panic message is not a string literal LL | core::panic!(&*"abc"); | ^^^^^^^ | + = note: for more information, see = note: this usage of `core::panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -207,6 +222,7 @@ warning: panic message is not a string literal LL | panic!(Some(123)); | ^^^^^^^^^ | + = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{:?}" format string to use the `Debug` implementation of `Option` @@ -225,6 +241,7 @@ warning: panic message contains an unused formatting placeholder LL | panic!(concat!("{", "}")); | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see = note: this message is not used as a format string when given without arguments, but will be in Rust 2021 help: add the missing argument | @@ -241,6 +258,7 @@ warning: panic message contains braces LL | panic!(concat!("{", "{")); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see = note: this message is not used as a format string, but will be in Rust 2021 help: add a "{}" format string to use the message literally | @@ -253,6 +271,7 @@ warning: panic message contains an unused formatting placeholder LL | fancy_panic::fancy_panic!("test {} 123"); | ^^ | + = note: for more information, see = note: this message is not used as a format string when given without arguments, but will be in Rust 2021 warning: panic message is not a string literal @@ -261,6 +280,7 @@ warning: panic message is not a string literal LL | panic!(a!()); | ^^^^ | + = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -279,6 +299,7 @@ warning: panic message is not a string literal LL | unreachable!(a!()); | ^^^^ | + = note: for more information, see = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -292,6 +313,7 @@ warning: panic message is not a string literal LL | panic!(format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see = note: the `panic!()` macro supports formatting, so there's no need for the `format!()` macro here @@ -307,6 +329,7 @@ warning: panic message is not a string literal LL | unreachable!(format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see = note: the `unreachable!()` macro supports formatting, so there's no need for the `format!()` macro here @@ -322,6 +345,7 @@ warning: panic message is not a string literal LL | assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see = note: the `assert!()` macro supports formatting, so there's no need for the `format!()` macro here @@ -337,6 +361,7 @@ warning: panic message is not a string literal LL | debug_assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see = note: this usage of `debug_assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see = note: the `debug_assert!()` macro supports formatting, so there's no need for the `format!()` macro here @@ -352,6 +377,7 @@ warning: panic message is not a string literal LL | panic![123]; | ^^^ | + = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -370,6 +396,7 @@ warning: panic message is not a string literal LL | panic!{123}; | ^^^ | + = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -390,6 +417,7 @@ LL | panic!(v); | | | help: use std::panic::panic_any instead: `std::panic::panic_any` | + = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see @@ -399,6 +427,7 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | + = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see @@ -408,6 +437,7 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | + = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{:?}" format string to use the `Debug` implementation of `T` @@ -426,6 +456,7 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | + = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{:?}" format string to use the `Debug` implementation of `T` @@ -439,6 +470,7 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | + = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -457,6 +489,7 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | + = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -470,6 +503,7 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | + = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message @@ -488,6 +522,7 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | + = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see help: add a "{}" format string to `Display` the message diff --git a/tests/ui/rust-2018/async-ident-allowed.stderr b/tests/ui/rust-2018/async-ident-allowed.stderr index 378c81d3c770..1bdfc7bae102 100644 --- a/tests/ui/rust-2018/async-ident-allowed.stderr +++ b/tests/ui/rust-2018/async-ident-allowed.stderr @@ -5,7 +5,7 @@ LL | let async = 3; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see note: the lint level is defined here --> $DIR/async-ident-allowed.rs:3:9 | diff --git a/tests/ui/rust-2018/async-ident.stderr b/tests/ui/rust-2018/async-ident.stderr index 4ab061dd6f59..2c4cb7e1d96e 100644 --- a/tests/ui/rust-2018/async-ident.stderr +++ b/tests/ui/rust-2018/async-ident.stderr @@ -5,7 +5,7 @@ LL | fn async() {} | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see note: the lint level is defined here --> $DIR/async-ident.rs:2:9 | @@ -20,7 +20,7 @@ LL | ($async:expr, async) => {}; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:17:6 @@ -29,7 +29,7 @@ LL | foo!(async); | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:26:11 @@ -38,7 +38,7 @@ LL | trait async {} | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:30:10 @@ -47,7 +47,7 @@ LL | impl async for MyStruct {} | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:36:12 @@ -56,7 +56,7 @@ LL | static async: u32 = 0; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:42:11 @@ -65,7 +65,7 @@ LL | const async: u32 = 0; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:48:15 @@ -74,7 +74,7 @@ LL | impl Foo { fn async() {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:53:12 @@ -83,7 +83,7 @@ LL | struct async {} | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:56:9 @@ -92,7 +92,7 @@ LL | let async: async = async {}; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:56:16 @@ -101,7 +101,7 @@ LL | let async: async = async {}; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:56:24 @@ -110,7 +110,7 @@ LL | let async: async = async {}; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:67:19 @@ -119,7 +119,7 @@ LL | () => (pub fn async() {}) | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:74:6 @@ -128,7 +128,7 @@ LL | (async) => (1) | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see error: aborting due to 14 previous errors diff --git a/tests/ui/rust-2018/dyn-keyword.stderr b/tests/ui/rust-2018/dyn-keyword.stderr index f8245bc88f57..733583f32b9b 100644 --- a/tests/ui/rust-2018/dyn-keyword.stderr +++ b/tests/ui/rust-2018/dyn-keyword.stderr @@ -5,7 +5,7 @@ LL | let dyn = (); | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see note: the lint level is defined here --> $DIR/dyn-keyword.rs:5:9 | diff --git a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr index c0a322edcd64..b59604f6427e 100644 --- a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr +++ b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr @@ -5,7 +5,7 @@ LL | let _: ::Bar = (); | ^^^^^^^^^^ help: use `crate`: `crate::foo::Foo` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see note: the lint level is defined here --> $DIR/edition-lint-fully-qualified-paths.rs:4:9 | @@ -19,7 +19,7 @@ LL | let _: ::Bar = (); | ^^^^^^^^^^ help: use `crate`: `crate::foo::Foo` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition @@ -29,7 +29,7 @@ LL | let _: <::foo::Baz as foo::Foo>::Bar = (); | ^^^^^^^^^^ help: use `crate`: `crate::foo::Baz` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see error: aborting due to 3 previous errors diff --git a/tests/ui/rust-2018/edition-lint-nested-empty-paths.stderr b/tests/ui/rust-2018/edition-lint-nested-empty-paths.stderr index 041572be8441..af02b30a99bd 100644 --- a/tests/ui/rust-2018/edition-lint-nested-empty-paths.stderr +++ b/tests/ui/rust-2018/edition-lint-nested-empty-paths.stderr @@ -5,7 +5,7 @@ LL | use foo::{bar::{baz::{}}}; | ^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}}}` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see note: the lint level is defined here --> $DIR/edition-lint-nested-empty-paths.rs:4:9 | @@ -19,7 +19,7 @@ LL | use foo::{bar::{XX, baz::{}}}; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition --> $DIR/edition-lint-nested-empty-paths.rs:21:5 @@ -28,7 +28,7 @@ LL | use foo::{bar::{XX, baz::{}}}; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition @@ -38,7 +38,7 @@ LL | use foo::{bar::{baz::{}, baz1::{}}}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition --> $DIR/edition-lint-nested-empty-paths.rs:27:5 @@ -47,7 +47,7 @@ LL | use foo::{bar::{baz::{}, baz1::{}}}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 5 previous errors diff --git a/tests/ui/rust-2018/edition-lint-nested-paths.stderr b/tests/ui/rust-2018/edition-lint-nested-paths.stderr index 4a70bb7e5c87..0f60b16ac9aa 100644 --- a/tests/ui/rust-2018/edition-lint-nested-paths.stderr +++ b/tests/ui/rust-2018/edition-lint-nested-paths.stderr @@ -5,7 +5,7 @@ LL | use foo::{a, b}; | ^^^^^^^^^^^ help: use `crate`: `crate::foo::{a, b}` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see note: the lint level is defined here --> $DIR/edition-lint-nested-paths.rs:4:9 | @@ -19,7 +19,7 @@ LL | use foo::{a, b}; | ^^^^^^^^^^^ help: use `crate`: `crate::foo::{a, b}` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition @@ -29,7 +29,7 @@ LL | use foo::{self as x, c}; | ^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{self as x, c}` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition --> $DIR/edition-lint-nested-paths.rs:23:13 @@ -38,7 +38,7 @@ LL | use foo::{self as x, c}; | ^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{self as x, c}` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 4 previous errors diff --git a/tests/ui/rust-2018/edition-lint-paths.stderr b/tests/ui/rust-2018/edition-lint-paths.stderr index fde17338d98a..26db6e402a9e 100644 --- a/tests/ui/rust-2018/edition-lint-paths.stderr +++ b/tests/ui/rust-2018/edition-lint-paths.stderr @@ -5,7 +5,7 @@ LL | use bar::Bar; | ^^^^^^^^ help: use `crate`: `crate::bar::Bar` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see note: the lint level is defined here --> $DIR/edition-lint-paths.rs:5:9 | @@ -19,7 +19,7 @@ LL | use bar; | ^^^ help: use `crate`: `crate::bar` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition --> $DIR/edition-lint-paths.rs:25:9 @@ -28,7 +28,7 @@ LL | use {main, Bar as SomethingElse}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition --> $DIR/edition-lint-paths.rs:25:9 @@ -37,7 +37,7 @@ LL | use {main, Bar as SomethingElse}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition @@ -47,7 +47,7 @@ LL | use {main, Bar as SomethingElse}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition @@ -57,7 +57,7 @@ LL | use bar::Bar; | ^^^^^^^^ help: use `crate`: `crate::bar::Bar` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition --> $DIR/edition-lint-paths.rs:52:9 @@ -66,7 +66,7 @@ LL | use *; | ^ help: use `crate`: `crate::*` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition --> $DIR/edition-lint-paths.rs:57:6 @@ -75,7 +75,7 @@ LL | impl ::foo::SomeTrait for u32 {} | ^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::SomeTrait` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition --> $DIR/edition-lint-paths.rs:62:13 @@ -84,7 +84,7 @@ LL | let x = ::bar::Bar; | ^^^^^^^^^^ help: use `crate`: `crate::bar::Bar` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see error: aborting due to 9 previous errors diff --git a/tests/ui/rust-2018/extern-crate-rename.stderr b/tests/ui/rust-2018/extern-crate-rename.stderr index 36986c89c62b..bce9e73ee65a 100644 --- a/tests/ui/rust-2018/extern-crate-rename.stderr +++ b/tests/ui/rust-2018/extern-crate-rename.stderr @@ -5,7 +5,7 @@ LL | use my_crate::foo; | ^^^^^^^^^^^^^ help: use `crate`: `crate::my_crate::foo` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see note: the lint level is defined here --> $DIR/extern-crate-rename.rs:8:9 | diff --git a/tests/ui/rust-2018/extern-crate-submod.stderr b/tests/ui/rust-2018/extern-crate-submod.stderr index 85e26d72a673..ed4266d3b091 100644 --- a/tests/ui/rust-2018/extern-crate-submod.stderr +++ b/tests/ui/rust-2018/extern-crate-submod.stderr @@ -5,7 +5,7 @@ LL | use m::edition_lint_paths::foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::m::edition_lint_paths::foo` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #53130 + = note: for more information, see note: the lint level is defined here --> $DIR/extern-crate-submod.rs:9:9 | diff --git a/tests/ui/rust-2018/try-ident.stderr b/tests/ui/rust-2018/try-ident.stderr index aca623d7d482..3af2196ce35b 100644 --- a/tests/ui/rust-2018/try-ident.stderr +++ b/tests/ui/rust-2018/try-ident.stderr @@ -5,7 +5,7 @@ LL | try(); | ^^^ help: you can use a raw identifier to stay compatible: `r#try` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see note: the lint level is defined here --> $DIR/try-ident.rs:5:9 | @@ -20,7 +20,7 @@ LL | fn try() { | ^^^ help: you can use a raw identifier to stay compatible: `r#try` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see warning: 2 warnings emitted diff --git a/tests/ui/rust-2018/try-macro.stderr b/tests/ui/rust-2018/try-macro.stderr index 20105e1868f2..89366381c8c6 100644 --- a/tests/ui/rust-2018/try-macro.stderr +++ b/tests/ui/rust-2018/try-macro.stderr @@ -5,7 +5,7 @@ LL | try!(x); | ^^^ help: you can use a raw identifier to stay compatible: `r#try` | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 + = note: for more information, see note: the lint level is defined here --> $DIR/try-macro.rs:7:9 | diff --git a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr index 8bb2bb290d3d..2521341723a2 100644 --- a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr +++ b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr @@ -11,7 +11,7 @@ LL | std::ptr::from_ref(num).cast_mut().as_deref(); | ^^^^^^^^ | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #46906 + = note: for more information, see = note: `#[warn(tyvar_behind_raw_pointer)]` (part of `#[warn(rust_2018_compatibility)]`) on by default warning: type annotations needed @@ -21,7 +21,7 @@ LL | std::ptr::from_ref(num).cast_mut().as_deref(); | ^^^^^^^^ | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #46906 + = note: for more information, see error[E0599]: no method named `as_deref` found for raw pointer `*mut _` in the current scope --> $DIR/ice-unwrap-probe-many-result-125876.rs:5:40 From 787886861746f88af4b502e8691099223494b51c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 4 Nov 2025 13:42:30 +0000 Subject: [PATCH 486/585] don't normalize where-clauses in wfcheck --- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 0e8859facf58..0a6be9aa4b2f 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1147,17 +1147,16 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuarant /// /// Assuming the defaults are used, check that all predicates (bounds on the /// assoc type and where clauses on the trait) hold. -fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocItem, span: Span) { +fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocItem, _span: Span) { let bounds = wfcx.tcx().explicit_item_bounds(item.def_id); debug!("check_associated_type_bounds: bounds={:?}", bounds); let wf_obligations = bounds.iter_identity_copied().flat_map(|(bound, bound_span)| { - let normalized_bound = wfcx.normalize(span, None, bound); traits::wf::clause_obligations( wfcx.infcx, wfcx.param_env, wfcx.body_def_id, - normalized_bound, + bound, bound_span, ) }); @@ -1525,7 +1524,6 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result { assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| { - let p = wfcx.normalize(sp, None, p); traits::wf::clause_obligations(infcx, wfcx.param_env, wfcx.body_def_id, p, sp) }); let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect(); From fa775988245e635b20278551ecdc334193d754fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 4 Nov 2025 14:04:02 +0000 Subject: [PATCH 487/585] update tests and bless expectations just to show the diagnostics impact --- .../assoc-const-eq-bound-var-in-ty-not-wf.rs | 3 +- ...soc-const-eq-bound-var-in-ty-not-wf.stderr | 15 +--- tests/ui/associated-types/issue-38821.rs | 12 +-- tests/ui/associated-types/issue-38821.stderr | 85 ++++++++++++------- .../in-trait/refine-resolution-errors.rs | 1 + .../in-trait/refine-resolution-errors.stderr | 10 ++- .../ui/lifetimes/issue-76168-hr-outlives-3.rs | 3 - .../issue-76168-hr-outlives-3.stderr | 28 +----- tests/ui/methods/filter-relevant-fn-bounds.rs | 2 - .../methods/filter-relevant-fn-bounds.stderr | 32 ++----- .../regions-normalize-in-where-clause-list.rs | 1 + ...ions-normalize-in-where-clause-list.stderr | 27 +++++- .../regions-enum-not-wf.rs | 1 + .../regions-enum-not-wf.stderr | 16 +++- tests/ui/traits/deep-norm-pending.rs | 4 +- tests/ui/traits/deep-norm-pending.stderr | 20 +++-- 16 files changed, 137 insertions(+), 123 deletions(-) diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs index 5232b895803e..8334e67ae9a1 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs @@ -21,8 +21,7 @@ fn take( K = { () } >, ) {} -//~^^^^^ ERROR implementation of `Project` is not general enough -//~^^^^ ERROR higher-ranked subtype error +//~^^^ ERROR higher-ranked subtype error //~| ERROR higher-ranked subtype error trait Project { type Out; } diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr index a0329e2b15d1..9fac60763dae 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr @@ -12,18 +12,5 @@ LL | K = { () } | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: implementation of `Project` is not general enough - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:19:13 - | -LL | _: impl Trait< - | _____________^ -LL | | < fn(&'a str) -> &'a str as Project>::Out as Discard>::Out, -LL | | K = { () } -LL | | >, - | |_____^ implementation of `Project` is not general enough - | - = note: `Project` would have to be implemented for the type `for<'a> fn(&'a str) -> &'a str` - = note: ...but `Project` is actually implemented for the type `fn(&'0 str) -> &'0 str`, for some specific lifetime `'0` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/associated-types/issue-38821.rs b/tests/ui/associated-types/issue-38821.rs index 60d3b224a5bf..5212bc886f0d 100644 --- a/tests/ui/associated-types/issue-38821.rs +++ b/tests/ui/associated-types/issue-38821.rs @@ -32,16 +32,16 @@ pub trait Column: Expression {} //~| ERROR the trait bound `::SqlType: NotNull` is not satisfied //~| ERROR the trait bound `::SqlType: NotNull` is not satisfied //~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied pub enum ColumnInsertValue where //~^ ERROR the trait bound `::SqlType: NotNull` is not satisfied Col: Column, Expr: Expression::Nullable>, -//~^ ERROR the trait bound `::SqlType: NotNull` is not satisfied -//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied -//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied -//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied -//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied -//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~^ ERROR the trait bound `::SqlType: IntoNullable` is not satisfied { Expression(Col, Expr), Default(Col), diff --git a/tests/ui/associated-types/issue-38821.stderr b/tests/ui/associated-types/issue-38821.stderr index b03a3cf7f47e..01329f69c3be 100644 --- a/tests/ui/associated-types/issue-38821.stderr +++ b/tests/ui/associated-types/issue-38821.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:35:1 + --> $DIR/issue-38821.rs:40:1 | LL | pub enum ColumnInsertValue where | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` @@ -16,8 +16,8 @@ help: consider extending the `where` clause, but there might be an alternative b LL | Expr: Expression::Nullable>, ::SqlType: NotNull | +++++++++++++++++++++++++++++++++++++ -error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:38:22 +error[E0277]: the trait bound `::SqlType: IntoNullable` is not satisfied + --> $DIR/issue-38821.rs:43:22 | LL | Expr: Expression::Nullable>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` @@ -82,10 +82,36 @@ LL | impl IntoNullable for T { = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:38:22 + --> $DIR/issue-38821.rs:23:10 | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +note: required for `ColumnInsertValue` to implement `Debug` + --> $DIR/issue-38821.rs:23:10 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ +... LL | Expr: Expression::Nullable>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` + | ------------------------------------------------ unsatisfied trait bound introduced in this `derive` macro +help: consider further restricting the associated type + | +LL | Expr: Expression::Nullable>, ::SqlType: NotNull, + | +++++++++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:17 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^ the trait `NotNull` is not implemented for `::SqlType` | note: required for `::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -112,24 +138,14 @@ LL | impl IntoNullable for T { | ------- ^^^^^^^^^^^^ ^ | | | unsatisfied trait bound introduced here -help: consider further restricting the associated type - | -LL | Expr: Expression::Nullable>, ::SqlType: NotNull, - | +++++++++++++++++++++++++++++++++++++++ - -error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:38:22 +note: required for `ColumnInsertValue` to implement `Copy` + --> $DIR/issue-38821.rs:23:17 | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^ +... LL | Expr: Expression::Nullable>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` - | -note: required for `::SqlType` to implement `IntoNullable` - --> $DIR/issue-38821.rs:9:18 - | -LL | impl IntoNullable for T { - | ------- ^^^^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here + | ------------------------------------------------ unsatisfied trait bound introduced in this `derive` macro help: consider further restricting the associated type | LL | Expr: Expression::Nullable>, ::SqlType: NotNull, @@ -183,10 +199,10 @@ LL | impl IntoNullable for T { = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:38:22 + --> $DIR/issue-38821.rs:23:23 | -LL | Expr: Expression::Nullable>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType` | note: required for `::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -195,6 +211,14 @@ LL | impl IntoNullable for T { | ------- ^^^^^^^^^^^^ ^ | | | unsatisfied trait bound introduced here +note: required for `ColumnInsertValue` to implement `Clone` + --> $DIR/issue-38821.rs:23:23 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ +... +LL | Expr: Expression::Nullable>, + | ------------------------------------------------ unsatisfied trait bound introduced in this `derive` macro help: consider further restricting the associated type | LL | Expr: Expression::Nullable>, ::SqlType: NotNull, @@ -216,10 +240,10 @@ LL | impl IntoNullable for T { = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:38:22 + --> $DIR/issue-38821.rs:23:10 | -LL | Expr: Expression::Nullable>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType` | note: required for `::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -245,10 +269,10 @@ LL | impl IntoNullable for T { = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:38:22 + --> $DIR/issue-38821.rs:23:23 | -LL | Expr: Expression::Nullable>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType` | note: required for `::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -257,7 +281,6 @@ LL | impl IntoNullable for T { | ------- ^^^^^^^^^^^^ ^ | | | unsatisfied trait bound introduced here - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied --> $DIR/issue-38821.rs:23:10 diff --git a/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs b/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs index 8433fb72b5e0..fa4ce66d54e6 100644 --- a/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs +++ b/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs @@ -14,6 +14,7 @@ impl Mirror for () { pub trait First { async fn first() -> <() as Mirror>::Assoc; + //~^ ERROR type annotations needed } impl First for () { diff --git a/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr b/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr index fd53c9fef443..af71e52b87d7 100644 --- a/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr +++ b/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr @@ -28,7 +28,13 @@ help: consider relaxing the implicit `Sized` restriction LL | type Assoc: ?Sized; | ++++++++ -error: aborting due to 2 previous errors +error[E0282]: type annotations needed + --> $DIR/refine-resolution-errors.rs:16:25 + | +LL | async fn first() -> <() as Mirror>::Assoc; + | ^^^^^^^^^^^^^^^^^^^^^ cannot infer type -Some errors have detailed explanations: E0207, E0277. +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0207, E0277, E0282. For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs b/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs index d6fda129e363..85eeb5d4c901 100644 --- a/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs +++ b/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs @@ -10,9 +10,6 @@ async fn wrapper(f: F) where F:, for<'a> >::Output: Future + 'a, -//~^ ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` -//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` -//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` { //~^ ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` let mut i = 41; diff --git a/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr index bb8e84724257..6da9f7380d59 100644 --- a/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr +++ b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr @@ -9,30 +9,6 @@ LL | | for<'a> >::Output: Future + 'a | = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` -error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` - --> $DIR/issue-76168-hr-outlives-3.rs:12:50 - | -LL | for<'a> >::Output: Future + 'a, - | ^^^^^^^^^^^^^^^^^^^ expected an `FnOnce(&'a mut i32)` closure, found `i32` - | - = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` - -error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` - --> $DIR/issue-76168-hr-outlives-3.rs:12:57 - | -LL | for<'a> >::Output: Future + 'a, - | ^^^^^^^^^^^ expected an `FnOnce(&'a mut i32)` closure, found `i32` - | - = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` - -error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` - --> $DIR/issue-76168-hr-outlives-3.rs:12:72 - | -LL | for<'a> >::Output: Future + 'a, - | ^^ expected an `FnOnce(&'a mut i32)` closure, found `i32` - | - = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` - error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` --> $DIR/issue-76168-hr-outlives-3.rs:6:26 | @@ -51,7 +27,7 @@ LL | async fn wrapper(f: F) = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` - --> $DIR/issue-76168-hr-outlives-3.rs:16:1 + --> $DIR/issue-76168-hr-outlives-3.rs:13:1 | LL | / { LL | | @@ -62,6 +38,6 @@ LL | | } | = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` -error: aborting due to 7 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/methods/filter-relevant-fn-bounds.rs b/tests/ui/methods/filter-relevant-fn-bounds.rs index 6233c9db53a0..7945eaa0daa2 100644 --- a/tests/ui/methods/filter-relevant-fn-bounds.rs +++ b/tests/ui/methods/filter-relevant-fn-bounds.rs @@ -9,8 +9,6 @@ fn do_something_wrapper(self, _: F) //~^ ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied where F: for<'a> FnOnce(>::Type), - //~^ ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied - //~| ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied { } } diff --git a/tests/ui/methods/filter-relevant-fn-bounds.stderr b/tests/ui/methods/filter-relevant-fn-bounds.stderr index 82103e62ddfe..4efe40ae0903 100644 --- a/tests/ui/methods/filter-relevant-fn-bounds.stderr +++ b/tests/ui/methods/filter-relevant-fn-bounds.stderr @@ -12,37 +12,15 @@ help: consider further restricting type parameter `F` with trait `Output` LL | F: for<'a> FnOnce(>::Type) + for<'a> Output<'a>, | ++++++++++++++++++++ -error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied - --> $DIR/filter-relevant-fn-bounds.rs:11:12 - | -LL | F: for<'a> FnOnce(>::Type), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F` - | -help: consider further restricting type parameter `F` with trait `Output` - | -LL | F: for<'a> FnOnce(>::Type) + for<'a> Output<'a>, - | ++++++++++++++++++++ - -error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied - --> $DIR/filter-relevant-fn-bounds.rs:11:20 - | -LL | F: for<'a> FnOnce(>::Type), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F` - | -help: consider further restricting type parameter `F` with trait `Output` - | -LL | F: for<'a> FnOnce(>::Type) + for<'a> Output<'a>, - | ++++++++++++++++++++ - -error[E0277]: expected a `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:20:34: 20:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:20:34: 20:41}` - --> $DIR/filter-relevant-fn-bounds.rs:20:34 +error[E0277]: expected a `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:18:34: 18:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:18:34: 18:41}` + --> $DIR/filter-relevant-fn-bounds.rs:18:34 | LL | wrapper.do_something_wrapper(|value| ()); - | -------------------- ^^^^^^^^^^ expected an `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:20:34: 20:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:20:34: 20:41}` + | -------------------- ^^^^^^^^^^ expected an `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:18:34: 18:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:18:34: 18:41}` | | | required by a bound introduced by this call | - = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/filter-relevant-fn-bounds.rs:20:34: 20:41}` + = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/filter-relevant-fn-bounds.rs:18:34: 18:41}` help: this trait has no implementations, consider adding one --> $DIR/filter-relevant-fn-bounds.rs:1:1 | @@ -57,6 +35,6 @@ LL | fn do_something_wrapper(self, _: F) LL | F: for<'a> FnOnce(>::Type), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper` -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/regions/regions-normalize-in-where-clause-list.rs b/tests/ui/regions/regions-normalize-in-where-clause-list.rs index 9b046e6baed6..bcc5da406b4e 100644 --- a/tests/ui/regions/regions-normalize-in-where-clause-list.rs +++ b/tests/ui/regions/regions-normalize-in-where-clause-list.rs @@ -25,6 +25,7 @@ fn bar<'a, 'b>() where <() as Project<'a, 'b>>::Item: Eq, //~^ ERROR cannot infer + //~| ERROR cannot infer { } diff --git a/tests/ui/regions/regions-normalize-in-where-clause-list.stderr b/tests/ui/regions/regions-normalize-in-where-clause-list.stderr index 9a5c9ae53de3..1a20055836ac 100644 --- a/tests/ui/regions/regions-normalize-in-where-clause-list.stderr +++ b/tests/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -22,6 +22,31 @@ LL | <() as Project<'a, 'b>>::Item: Eq, = note: expected `Project<'a, 'b>` found `Project<'_, '_>` -error: aborting due to 1 previous error +error[E0803]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/regions-normalize-in-where-clause-list.rs:26:36 + | +LL | <() as Project<'a, 'b>>::Item: Eq, + | ^^ + | +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... + --> $DIR/regions-normalize-in-where-clause-list.rs:24:8 + | +LL | fn bar<'a, 'b>() + | ^^ +note: ...but the lifetime must also be valid for the lifetime `'b` as defined here... + --> $DIR/regions-normalize-in-where-clause-list.rs:24:12 + | +LL | fn bar<'a, 'b>() + | ^^ +note: ...so that the types are compatible + --> $DIR/regions-normalize-in-where-clause-list.rs:26:36 + | +LL | <() as Project<'a, 'b>>::Item: Eq, + | ^^ + = note: expected `Project<'a, 'b>` + found `Project<'_, '_>` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0803`. diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs index 038f53034ab0..c5e9d147d567 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs @@ -34,6 +34,7 @@ enum RefIndirect<'a, T> { enum RefDouble<'a, 'b, T> { RefDoubleVariant1(&'a RequireOutlives<'b, T>), //~^ ERROR the parameter type `T` may not live long enough [E0309] + //~| ERROR the parameter type `T` may not live long enough [E0309] } fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr index 5b605f3eef56..2799164bbda2 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr @@ -38,6 +38,20 @@ help: consider adding an explicit lifetime bound LL | enum RefDouble<'a, 'b, T: 'b> { | ++++ -error: aborting due to 3 previous errors +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-enum-not-wf.rs:35:23 + | +LL | enum RefDouble<'a, 'b, T> { + | -- the parameter type `T` must be valid for the lifetime `'b` as defined here... +LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | enum RefDouble<'a, 'b, T: 'b> { + | ++++ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0309`. diff --git a/tests/ui/traits/deep-norm-pending.rs b/tests/ui/traits/deep-norm-pending.rs index d6c498dcf2bd..9b1ec522bef3 100644 --- a/tests/ui/traits/deep-norm-pending.rs +++ b/tests/ui/traits/deep-norm-pending.rs @@ -7,11 +7,11 @@ trait Bar { //~^ ERROR the trait bound `T: Foo` is not satisfied } impl Bar for T -//~^ ERROR the trait bound `T: Foo` is not satisfied +//~^ ERROR the trait bound `T: Bar` is not satisfied +//~| ERROR the trait bound `T: Foo` is not satisfied where ::Assoc: Sized, //~^ ERROR the trait bound `T: Foo` is not satisfied - //~| ERROR the trait bound `T: Foo` is not satisfied { fn method() {} //~^ ERROR the trait bound `T: Foo` is not satisfied diff --git a/tests/ui/traits/deep-norm-pending.stderr b/tests/ui/traits/deep-norm-pending.stderr index c1d6120c390d..f2b59748ced9 100644 --- a/tests/ui/traits/deep-norm-pending.stderr +++ b/tests/ui/traits/deep-norm-pending.stderr @@ -3,6 +3,7 @@ error[E0277]: the trait bound `T: Foo` is not satisfied | LL | / impl Bar for T LL | | +LL | | LL | | where LL | | ::Assoc: Sized, | |_____________________________^ the trait `Foo` is not implemented for `T` @@ -85,12 +86,20 @@ help: consider further restricting type parameter `T` with trait `Foo` LL | ::Assoc: Sized, T: Foo | ++++++ -error[E0277]: the trait bound `T: Foo` is not satisfied - --> $DIR/deep-norm-pending.rs:12:24 +error[E0277]: the trait bound `T: Bar` is not satisfied + --> $DIR/deep-norm-pending.rs:9:17 | +LL | impl Bar for T + | ^ the trait `Foo` is not implemented for `T` + | +note: required for `T` to implement `Bar` + --> $DIR/deep-norm-pending.rs:9:9 + | +LL | impl Bar for T + | ^^^ ^ +... LL | ::Assoc: Sized, - | ^^^^^ the trait `Foo` is not implemented for `T` - | + | ----- unsatisfied trait bound introduced here help: consider further restricting type parameter `T` with trait `Foo` | LL | ::Assoc: Sized, T: Foo @@ -109,12 +118,11 @@ LL | ::Assoc: Sized, T: Foo | ++++++ error[E0277]: the trait bound `T: Foo` is not satisfied - --> $DIR/deep-norm-pending.rs:12:24 + --> $DIR/deep-norm-pending.rs:13:24 | LL | ::Assoc: Sized, | ^^^^^ the trait `Foo` is not implemented for `T` | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider further restricting type parameter `T` with trait `Foo` | LL | ::Assoc: Sized, T: Foo From cdf43ad5ef5986b42170cba38ce03c0f3e81c0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 26 Nov 2025 15:24:07 +0000 Subject: [PATCH 488/585] add test from modcholesky breakage --- .../wf/wf-where-clauses-pre-normalization.rs | 20 +++++++++++++++++++ .../wf-where-clauses-pre-normalization.stderr | 17 ++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/ui/wf/wf-where-clauses-pre-normalization.rs create mode 100644 tests/ui/wf/wf-where-clauses-pre-normalization.stderr diff --git a/tests/ui/wf/wf-where-clauses-pre-normalization.rs b/tests/ui/wf/wf-where-clauses-pre-normalization.rs new file mode 100644 index 000000000000..16c102f1faef --- /dev/null +++ b/tests/ui/wf/wf-where-clauses-pre-normalization.rs @@ -0,0 +1,20 @@ +// This is a test, extracted from `modcholesky`, that used to pass wfcheck because we checked +// well-formedness of where-clauses *after* normalization. We generally want to move to always check +// WF pre-normalization. + +pub struct View(A); +pub trait Data { + type Elem; +} +impl<'a, A> Data for View<&'a A> { + type Elem = A; +} + +pub fn repro<'a, T>() +where + as Data>::Elem: Sized, + //~^ ERROR: the parameter type `T` may not live long enough +{ +} + +fn main() {} diff --git a/tests/ui/wf/wf-where-clauses-pre-normalization.stderr b/tests/ui/wf/wf-where-clauses-pre-normalization.stderr new file mode 100644 index 000000000000..a7836cae5db2 --- /dev/null +++ b/tests/ui/wf/wf-where-clauses-pre-normalization.stderr @@ -0,0 +1,17 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/wf-where-clauses-pre-normalization.rs:15:34 + | +LL | pub fn repro<'a, T>() + | -- the parameter type `T` must be valid for the lifetime `'a` as defined here... +LL | where +LL | as Data>::Elem: Sized, + | ^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | pub fn repro<'a, T: 'a>() + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0309`. From 99f7e785c5276bd9ec6014c97a5688e2283953de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 26 Nov 2025 15:45:48 +0000 Subject: [PATCH 489/585] mark crash test as requiring debug-assertions --- tests/crashes/133613.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/crashes/133613.rs b/tests/crashes/133613.rs index f01780d7cf42..066c50b49477 100644 --- a/tests/crashes/133613.rs +++ b/tests/crashes/133613.rs @@ -1,3 +1,4 @@ +//@ needs-rustc-debug-assertions //@ known-bug: #133613 struct Wrapper<'a>(); From 4d697d243302066fcb5cb6a9daacf7e6cdc891c7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Dec 2025 15:16:41 +0100 Subject: [PATCH 490/585] Remove "tidy" tool for `tests/rustdoc` testsuite --- src/tools/compiletest/src/common.rs | 9 - src/tools/compiletest/src/executor.rs | 9 - src/tools/compiletest/src/lib.rs | 28 +-- src/tools/compiletest/src/runtest.rs | 164 +----------------- .../compiletest/src/runtest/compute_diff.rs | 57 ------ src/tools/compiletest/src/runtest/rustdoc.rs | 4 +- src/tools/compiletest/src/rustdoc_gui_test.rs | 2 - 7 files changed, 8 insertions(+), 265 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 02b93593cbbd..ddbe8601de20 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -9,7 +9,6 @@ use semver::Version; use crate::edition::Edition; -use crate::executor::ColorConfig; use crate::fatal; use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum}; @@ -597,11 +596,6 @@ pub struct Config { /// FIXME: this is *way* too coarse; the user can't select *which* info to verbosely dump. pub verbose: bool, - /// Whether to use colors in test output. - /// - /// Note: the exact control mechanism is delegated to [`colored`]. - pub color: ColorConfig, - /// Where to find the remote test client process, if we're using it. /// /// Note: this is *only* used for target platform executables created by `run-make` test @@ -623,9 +617,6 @@ pub struct Config { /// created in `$test_suite_build_root/rustfix_missing_coverage.txt` pub rustfix_coverage: bool, - /// Whether to run `tidy` (html-tidy) when a rustdoc test fails. - pub has_html_tidy: bool, - /// Whether to run `enzyme` autodiff tests. pub has_enzyme: bool, diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index 4dd4b1f85aaa..c800d11d6b2f 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -341,15 +341,6 @@ pub(crate) struct CollectedTestDesc { pub(crate) should_fail: ShouldFail, } -/// Whether console output should be colored or not. -#[derive(Copy, Clone, Default, Debug)] -pub enum ColorConfig { - #[default] - AutoColor, - AlwaysColor, - NeverColor, -} - /// Tests with `//@ should-fail` are tests of compiletest itself, and should /// be reported as successful if and only if they would have _failed_. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index ff4cd81d33ff..7c237102ed84 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -24,7 +24,6 @@ use std::collections::HashSet; use std::fmt::Write; use std::io::{self, ErrorKind}; -use std::process::{Command, Stdio}; use std::sync::{Arc, OnceLock}; use std::time::SystemTime; use std::{env, fs, vec}; @@ -43,7 +42,7 @@ }; use crate::directives::{AuxProps, DirectivesCache, FileDirectives}; use crate::edition::parse_edition; -use crate::executor::{CollectedTest, ColorConfig}; +use crate::executor::CollectedTest; /// Creates the `Config` instance for this invocation of compiletest. /// @@ -136,8 +135,9 @@ fn parse_config(args: Vec) -> Config { "overwrite stderr/stdout files instead of complaining about a mismatch", ) .optflag("", "fail-fast", "stop as soon as possible after any test fails") - .optopt("", "color", "coloring: auto, always, never", "WHEN") .optopt("", "target", "the target to build for", "TARGET") + // FIXME: Should be removed once `bootstrap` will be updated to not use this option. + .optopt("", "color", "coloring: auto, always, never", "WHEN") .optopt("", "host", "the host to build for", "HOST") .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH") .optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH") @@ -276,12 +276,6 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { let lldb = matches.opt_str("lldb").map(Utf8PathBuf::from); let lldb_version = matches.opt_str("lldb-version").as_deref().and_then(debuggers::extract_lldb_version); - let color = match matches.opt_str("color").as_deref() { - Some("auto") | None => ColorConfig::AutoColor, - Some("always") => ColorConfig::AlwaysColor, - Some("never") => ColorConfig::NeverColor, - Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), - }; // FIXME: this is very questionable, we really should be obtaining LLVM version info from // `bootstrap`, and not trying to be figuring out that in `compiletest` by running the // `FileCheck` binary. @@ -306,16 +300,6 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions"); let with_std_debug_assertions = matches.opt_present("with-std-debug-assertions"); let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); - let has_html_tidy = if mode == TestMode::Rustdoc { - Command::new("tidy") - .arg("--version") - .stdout(Stdio::null()) - .status() - .map_or(false, |status| status.success()) - } else { - // Avoid spawning an external command when we know html-tidy won't be used. - false - }; let has_enzyme = matches.opt_present("has-enzyme"); let filters = if mode == TestMode::RunMake { matches @@ -457,11 +441,9 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { adb_device_status, verbose: matches.opt_present("verbose"), only_modified: matches.opt_present("only-modified"), - color, remote_test_client: matches.opt_str("remote-test-client").map(Utf8PathBuf::from), compare_mode, rustfix_coverage: matches.opt_present("rustfix-coverage"), - has_html_tidy, has_enzyme, channel: matches.opt_str("channel").unwrap(), git_hash: matches.opt_present("git-hash"), @@ -1146,10 +1128,6 @@ fn check_for_overlapping_test_paths(found_path_stems: &HashSet) { } fn early_config_check(config: &Config) { - if !config.has_html_tidy && config.mode == TestMode::Rustdoc { - warning!("`tidy` (html-tidy.org) is not installed; diffs will not be generated"); - } - if !config.profiler_runtime && config.mode == TestMode::CoverageRun { let actioned = if config.bless { "blessed" } else { "checked" }; warning!("profiler runtime is not available, so `.coverage` files won't be {actioned}"); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 54d6e0190ddc..f28f70ed453e 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1,12 +1,11 @@ use std::borrow::Cow; use std::collections::{HashMap, HashSet}; use std::ffi::OsString; -use std::fs::{self, File, create_dir_all}; +use std::fs::{self, create_dir_all}; use std::hash::{DefaultHasher, Hash, Hasher}; use std::io::prelude::*; -use std::io::{self, BufReader}; use std::process::{Child, Command, ExitStatus, Output, Stdio}; -use std::{env, fmt, iter, str}; +use std::{env, fmt, io, iter, str}; use build_helper::fs::remove_and_create_dir_all; use camino::{Utf8Path, Utf8PathBuf}; @@ -23,9 +22,9 @@ use crate::errors::{Error, ErrorKind, load_errors}; use crate::output_capture::ConsoleOut; use crate::read2::{Truncated, read2_abbreviated}; -use crate::runtest::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; +use crate::runtest::compute_diff::{DiffLine, make_diff, write_diff}; use crate::util::{Utf8PathBufExt, add_dylib_path, static_regex}; -use crate::{ColorConfig, help, json, stamp_file_path, warning}; +use crate::{json, stamp_file_path}; // Helper modules that implement test running logic for each test suite. // tidy-alphabetical-start @@ -2162,161 +2161,6 @@ fn charset() -> &'static str { if cfg!(target_os = "freebsd") { "ISO-8859-1" } else { "UTF-8" } } - fn compare_to_default_rustdoc(&self, out_dir: &Utf8Path) { - if !self.config.has_html_tidy { - return; - } - writeln!(self.stdout, "info: generating a diff against nightly rustdoc"); - - let suffix = - self.safe_revision().map_or("nightly".into(), |path| path.to_owned() + "-nightly"); - let compare_dir = output_base_dir(self.config, self.testpaths, Some(&suffix)); - remove_and_create_dir_all(&compare_dir).unwrap_or_else(|e| { - panic!("failed to remove and recreate output directory `{compare_dir}`: {e}") - }); - - // We need to create a new struct for the lifetimes on `config` to work. - let new_rustdoc = TestCx { - config: &Config { - // FIXME: use beta or a user-specified rustdoc instead of - // hardcoding the default toolchain - rustdoc_path: Some("rustdoc".into()), - // Needed for building auxiliary docs below - rustc_path: "rustc".into(), - ..self.config.clone() - }, - ..*self - }; - - let output_file = TargetLocation::ThisDirectory(new_rustdoc.aux_output_dir_name()); - let mut rustc = new_rustdoc.make_compile_args( - &new_rustdoc.testpaths.file, - output_file, - Emit::None, - AllowUnused::Yes, - LinkToAux::Yes, - Vec::new(), - ); - let aux_dir = new_rustdoc.aux_output_dir(); - new_rustdoc.build_all_auxiliary(&aux_dir, &mut rustc); - - let proc_res = new_rustdoc.document(&compare_dir, DocKind::Html); - if !proc_res.status.success() { - writeln!(self.stderr, "failed to run nightly rustdoc"); - return; - } - - #[rustfmt::skip] - let tidy_args = [ - "--new-blocklevel-tags", "rustdoc-search,rustdoc-toolbar,rustdoc-topbar", - "--indent", "yes", - "--indent-spaces", "2", - "--wrap", "0", - "--show-warnings", "no", - "--markup", "yes", - "--quiet", "yes", - "-modify", - ]; - let tidy_dir = |dir| { - for entry in walkdir::WalkDir::new(dir) { - let entry = entry.expect("failed to read file"); - if entry.file_type().is_file() - && entry.path().extension().and_then(|p| p.to_str()) == Some("html") - { - let status = - Command::new("tidy").args(&tidy_args).arg(entry.path()).status().unwrap(); - // `tidy` returns 1 if it modified the file. - assert!(status.success() || status.code() == Some(1)); - } - } - }; - tidy_dir(out_dir); - tidy_dir(&compare_dir); - - let pager = { - let output = Command::new("git").args(&["config", "--get", "core.pager"]).output().ok(); - output.and_then(|out| { - if out.status.success() { - Some(String::from_utf8(out.stdout).expect("invalid UTF8 in git pager")) - } else { - None - } - }) - }; - - let diff_filename = format!("build/tmp/rustdoc-compare-{}.diff", std::process::id()); - - if !write_filtered_diff( - self, - &diff_filename, - out_dir, - &compare_dir, - self.config.verbose, - |file_type, extension| { - file_type.is_file() && (extension == Some("html") || extension == Some("js")) - }, - ) { - return; - } - - match self.config.color { - ColorConfig::AlwaysColor => colored::control::set_override(true), - ColorConfig::NeverColor => colored::control::set_override(false), - _ => {} - } - - if let Some(pager) = pager { - let pager = pager.trim(); - if self.config.verbose { - writeln!(self.stderr, "using pager {}", pager); - } - let output = Command::new(pager) - // disable paging; we want this to be non-interactive - .env("PAGER", "") - .stdin(File::open(&diff_filename).unwrap()) - // Capture output and print it explicitly so it will in turn be - // captured by output-capture. - .output() - .unwrap(); - assert!(output.status.success()); - writeln!(self.stdout, "{}", String::from_utf8_lossy(&output.stdout)); - writeln!(self.stderr, "{}", String::from_utf8_lossy(&output.stderr)); - } else { - warning!("no pager configured, falling back to unified diff"); - help!( - "try configuring a git pager (e.g. `delta`) with \ - `git config --global core.pager delta`" - ); - let mut out = io::stdout(); - let mut diff = BufReader::new(File::open(&diff_filename).unwrap()); - let mut line = Vec::new(); - loop { - line.truncate(0); - match diff.read_until(b'\n', &mut line) { - Ok(0) => break, - Ok(_) => {} - Err(e) => writeln!(self.stderr, "ERROR: {:?}", e), - } - match String::from_utf8(line.clone()) { - Ok(line) => { - if line.starts_with('+') { - write!(&mut out, "{}", line.green()).unwrap(); - } else if line.starts_with('-') { - write!(&mut out, "{}", line.red()).unwrap(); - } else if line.starts_with('@') { - write!(&mut out, "{}", line.blue()).unwrap(); - } else { - out.write_all(line.as_bytes()).unwrap(); - } - } - Err(_) => { - write!(&mut out, "{}", String::from_utf8_lossy(&line).reversed()).unwrap(); - } - } - } - }; - } - fn get_lines(&self, path: &Utf8Path, mut other_files: Option<&mut Vec>) -> Vec { let content = fs::read_to_string(path.as_std_path()).unwrap(); let mut ignore = false; diff --git a/src/tools/compiletest/src/runtest/compute_diff.rs b/src/tools/compiletest/src/runtest/compute_diff.rs index 3363127b3ea3..8418dcbaf963 100644 --- a/src/tools/compiletest/src/runtest/compute_diff.rs +++ b/src/tools/compiletest/src/runtest/compute_diff.rs @@ -1,9 +1,4 @@ use std::collections::VecDeque; -use std::fs::{File, FileType}; - -use camino::Utf8Path; - -use crate::runtest::TestCx; #[derive(Debug, PartialEq)] pub enum DiffLine { @@ -109,55 +104,3 @@ pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> S } output } - -/// Filters based on filetype and extension whether to diff a file. -/// -/// Returns whether any data was actually written. -pub(crate) fn write_filtered_diff( - cx: &TestCx<'_>, - diff_filename: &str, - out_dir: &Utf8Path, - compare_dir: &Utf8Path, - verbose: bool, - filter: Filter, -) -> bool -where - Filter: Fn(FileType, Option<&str>) -> bool, -{ - use std::io::{Read, Write}; - let mut diff_output = File::create(diff_filename).unwrap(); - let mut wrote_data = false; - for entry in walkdir::WalkDir::new(out_dir.as_std_path()) { - let entry = entry.expect("failed to read file"); - let extension = entry.path().extension().and_then(|p| p.to_str()); - if filter(entry.file_type(), extension) { - let expected_path = compare_dir - .as_std_path() - .join(entry.path().strip_prefix(&out_dir.as_std_path()).unwrap()); - let expected = if let Ok(s) = std::fs::read(&expected_path) { s } else { continue }; - let actual_path = entry.path(); - let actual = std::fs::read(&actual_path).unwrap(); - let diff = unified_diff::diff( - &expected, - &expected_path.to_str().unwrap(), - &actual, - &actual_path.to_str().unwrap(), - 3, - ); - wrote_data |= !diff.is_empty(); - diff_output.write_all(&diff).unwrap(); - } - } - - if !wrote_data { - writeln!(cx.stdout, "note: diff is identical to nightly rustdoc"); - assert!(diff_output.metadata().unwrap().len() == 0); - return false; - } else if verbose { - writeln!(cx.stderr, "printing diff:"); - let mut buf = Vec::new(); - diff_output.read_to_end(&mut buf).unwrap(); - std::io::stderr().lock().write_all(&mut buf).unwrap(); - } - true -} diff --git a/src/tools/compiletest/src/runtest/rustdoc.rs b/src/tools/compiletest/src/runtest/rustdoc.rs index a4558de5f1c0..3c80521e51ec 100644 --- a/src/tools/compiletest/src/runtest/rustdoc.rs +++ b/src/tools/compiletest/src/runtest/rustdoc.rs @@ -28,9 +28,7 @@ pub(super) fn run_rustdoc_test(&self) { } let res = self.run_command_to_procres(&mut cmd); if !res.status.success() { - self.fatal_proc_rec_general("htmldocck failed!", None, &res, || { - self.compare_to_default_rustdoc(&out_dir); - }); + self.fatal_proc_rec("htmldocck failed!", &res); } } } diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index f6d026ab9cfd..c30f3d1e10ea 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -108,11 +108,9 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { adb_test_dir: Default::default(), adb_device_status: Default::default(), verbose: Default::default(), - color: Default::default(), remote_test_client: Default::default(), compare_mode: Default::default(), rustfix_coverage: Default::default(), - has_html_tidy: Default::default(), has_enzyme: Default::default(), channel: Default::default(), git_hash: Default::default(), From 450916305fe8482dfe2f192c0d288b0490d3a517 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 11 Jun 2025 21:29:06 +0200 Subject: [PATCH 491/585] Put negative implementors first and apply same ordering logic to foreign implementors --- src/librustdoc/formats/mod.rs | 4 ++ src/librustdoc/html/render/print_item.rs | 43 ++++++++++++++++-- src/librustdoc/html/render/write_shared.rs | 45 +++++++++++++++++-- .../html/render/write_shared/tests.rs | 6 +-- src/librustdoc/html/static/css/rustdoc.css | 3 ++ src/librustdoc/html/static/js/main.js | 39 ++++++++++++---- src/librustdoc/html/static/js/rustdoc.d.ts | 2 +- 7 files changed, 122 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/formats/mod.rs b/src/librustdoc/formats/mod.rs index 2e8b5d9f5948..80c110ec07f5 100644 --- a/src/librustdoc/formats/mod.rs +++ b/src/librustdoc/formats/mod.rs @@ -76,4 +76,8 @@ pub(crate) fn is_on_local_type(&self, cx: &Context<'_>) -> bool { }; true } + + pub(crate) fn is_negative_trait_impl(&self) -> bool { + self.inner_impl().is_negative_trait_impl() + } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 0c511738d7c8..47e587626352 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -646,6 +646,27 @@ fn item_function(cx: &Context<'_>, it: &clean::Item, f: &clean::Function) -> imp }) } +/// Struct used to handle insertion of "negative impl" marker in the generated DOM. +/// +/// This marker appears once in all trait impl lists to divide negative impls from positive impls. +struct NegativeMarker { + inserted_negative_marker: bool, +} + +impl NegativeMarker { + fn new() -> Self { + Self { inserted_negative_marker: false } + } + + fn insert_if_needed(&mut self, w: &mut fmt::Formatter<'_>, implementor: &Impl) -> fmt::Result { + if !self.inserted_negative_marker && !implementor.is_negative_trait_impl() { + write!(w, "

")?; + self.inserted_negative_marker = true; + } + Ok(()) + } +} + fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt::Display { fmt::from_fn(|w| { let tcx = cx.tcx(); @@ -1072,7 +1093,9 @@ fn trait_item(cx: &Context<'_>, m: &clean::Item, t: &clean::Item) -> impl fmt::D "
", ) )?; + let mut negative_marker = NegativeMarker::new(); for implementor in concrete { + negative_marker.insert_if_needed(w, implementor)?; write!(w, "{}", render_implementor(cx, implementor, it, &implementor_dups, &[]))?; } w.write_str("
")?; @@ -1088,7 +1111,9 @@ fn trait_item(cx: &Context<'_>, m: &clean::Item, t: &clean::Item) -> impl fmt::D "
", ) )?; + let mut negative_marker = NegativeMarker::new(); for implementor in synthetic { + negative_marker.insert_if_needed(w, implementor)?; write!( w, "{}", @@ -2302,11 +2327,18 @@ fn wrap_item(w: &mut W, f: F) -> fmt::Result } #[derive(PartialEq, Eq)] -struct ImplString(String); +struct ImplString { + rendered: String, + is_negative: bool, +} impl ImplString { fn new(i: &Impl, cx: &Context<'_>) -> ImplString { - ImplString(format!("{}", print_impl(i.inner_impl(), false, cx))) + let impl_ = i.inner_impl(); + ImplString { + is_negative: impl_.is_negative_trait_impl(), + rendered: format!("{}", print_impl(impl_, false, cx)), + } } } @@ -2318,7 +2350,12 @@ fn partial_cmp(&self, other: &Self) -> Option { impl Ord for ImplString { fn cmp(&self, other: &Self) -> Ordering { - compare_names(&self.0, &other.0) + // We sort negative impls first. + match (self.is_negative, other.is_negative) { + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + _ => compare_names(&self.rendered, &other.rendered), + } } } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 6bf116c3b75a..ca33531174b1 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -14,6 +14,7 @@ //! or contains "invocation-specific". use std::cell::RefCell; +use std::cmp::Ordering; use std::ffi::{OsStr, OsString}; use std::fs::File; use std::io::{self, Write as _}; @@ -47,6 +48,7 @@ use crate::html::format::{print_impl, print_path}; use crate::html::layout; use crate::html::render::ordered_json::{EscapedJson, OrderedJson}; +use crate::html::render::print_item::compare_names; use crate::html::render::search_index::{SerializedSearchIndex, build_index}; use crate::html::render::sorted_template::{self, FileFormat, SortedTemplate}; use crate::html::render::{AssocItemLink, ImplRenderingParameters, StylePath}; @@ -667,7 +669,7 @@ impl TraitAliasPart { fn blank() -> SortedTemplate<::FileFormat> { SortedTemplate::from_before_after( r"(function() { - var implementors = Object.fromEntries([", + const implementors = Object.fromEntries([", r"]); if (window.register_implementors) { window.register_implementors(implementors); @@ -720,10 +722,12 @@ fn get( { None } else { + let impl_ = imp.inner_impl(); Some(Implementor { - text: print_impl(imp.inner_impl(), false, cx).to_string(), + text: print_impl(impl_, false, cx).to_string(), synthetic: imp.inner_impl().kind.is_auto(), types: collect_paths_for_type(&imp.inner_impl().for_, cache), + is_negative: impl_.is_negative_trait_impl(), }) } }) @@ -742,8 +746,15 @@ fn get( } path.push(format!("{remote_item_type}.{}.js", remote_path[remote_path.len() - 1])); - let part = OrderedJson::array_sorted( - implementors.map(|implementor| OrderedJson::serialize(implementor).unwrap()), + let mut implementors = implementors.collect::>(); + implementors.sort_unstable(); + + let part = OrderedJson::array_unsorted( + implementors + .iter() + .map(OrderedJson::serialize) + .collect::, _>>() + .unwrap(), ); path_parts.push(path, OrderedJson::array_unsorted([crate_name_json, &part])); } @@ -751,10 +762,12 @@ fn get( } } +#[derive(Eq)] struct Implementor { text: String, synthetic: bool, types: Vec, + is_negative: bool, } impl Serialize for Implementor { @@ -764,6 +777,7 @@ fn serialize(&self, serializer: S) -> Result { let mut seq = serializer.serialize_seq(None)?; seq.serialize_element(&self.text)?; + seq.serialize_element(if self.is_negative { &1 } else { &0 })?; if self.synthetic { seq.serialize_element(&1)?; seq.serialize_element(&self.types)?; @@ -772,6 +786,29 @@ fn serialize(&self, serializer: S) -> Result } } +impl PartialEq for Implementor { + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl PartialOrd for Implementor { + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} + +impl Ord for Implementor { + fn cmp(&self, other: &Self) -> Ordering { + // We sort negative impls first. + match (self.is_negative, other.is_negative) { + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + _ => compare_names(&self.text, &other.text), + } + } +} + /// Collect the list of aliased types and their aliases. /// /// diff --git a/src/librustdoc/html/render/write_shared/tests.rs b/src/librustdoc/html/render/write_shared/tests.rs index 1989a1f87aae..48d592c22f6f 100644 --- a/src/librustdoc/html/render/write_shared/tests.rs +++ b/src/librustdoc/html/render/write_shared/tests.rs @@ -68,7 +68,7 @@ fn trait_alias_template() { assert_eq!( but_last_line(&template.to_string()), r#"(function() { - var implementors = Object.fromEntries([]); + const implementors = Object.fromEntries([]); if (window.register_implementors) { window.register_implementors(implementors); } else { @@ -80,7 +80,7 @@ fn trait_alias_template() { assert_eq!( but_last_line(&template.to_string()), r#"(function() { - var implementors = Object.fromEntries([["a"]]); + const implementors = Object.fromEntries([["a"]]); if (window.register_implementors) { window.register_implementors(implementors); } else { @@ -92,7 +92,7 @@ fn trait_alias_template() { assert_eq!( but_last_line(&template.to_string()), r#"(function() { - var implementors = Object.fromEntries([["a"],["b"]]); + const implementors = Object.fromEntries([["a"],["b"]]); if (window.register_implementors) { window.register_implementors(implementors); } else { diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 7f4785694849..36f44a8072af 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2976,6 +2976,9 @@ in src-script.js and main.js { margin-bottom: 0.75em; } +.negative-marker { + display: none; +} .variants > .docblock, .implementors-toggle > .docblock, diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index dff40485e9a9..fb6b70492181 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -800,21 +800,34 @@ function preLoadCss(cssUrl) { // window.register_implementors = imp => { - const implementors = document.getElementById("implementors-list"); - const synthetic_implementors = document.getElementById("synthetic-implementors-list"); + /** Takes an ID as input and returns a list of two elements. The first element is the DOM + * element with the given ID and the second is the "negative marker", meaning the location + * between the negative and non-negative impls. + * + * @param {string} id: ID of the DOM element. + * + * @return {[HTMLElement|null, HTMLElement|null]} + */ + function implementorsElems(id) { + const elem = document.getElementById(id); + return [elem, elem ? elem.querySelector(".negative-marker") : null]; + } + const implementors = implementorsElems("implementors-list"); + const synthetic_implementors = implementorsElems("synthetic-implementors-list"); const inlined_types = new Set(); const TEXT_IDX = 0; - const SYNTHETIC_IDX = 1; - const TYPES_IDX = 2; + const IS_NEG_IDX = 1; + const SYNTHETIC_IDX = 2; + const TYPES_IDX = 3; - if (synthetic_implementors) { + if (synthetic_implementors[0]) { // This `inlined_types` variable is used to avoid having the same implementation // showing up twice. For example "String" in the "Sync" doc page. // // By the way, this is only used by and useful for traits implemented automatically // (like "Send" and "Sync"). - onEachLazy(synthetic_implementors.getElementsByClassName("impl"), el => { + onEachLazy(synthetic_implementors[0].getElementsByClassName("impl"), el => { const aliases = el.getAttribute("data-aliases"); if (!aliases) { return; @@ -827,7 +840,7 @@ function preLoadCss(cssUrl) { } // @ts-expect-error - let currentNbImpls = implementors.getElementsByClassName("impl").length; + let currentNbImpls = implementors[0].getElementsByClassName("impl").length; // @ts-expect-error const traitName = document.querySelector(".main-heading h1 > .trait").textContent; const baseIdName = "impl-" + traitName + "-"; @@ -884,8 +897,16 @@ function preLoadCss(cssUrl) { addClass(display, "impl"); display.appendChild(anchor); display.appendChild(code); - // @ts-expect-error - list.appendChild(display); + + // If this is a negative implementor, we put it into the right location (just + // before the negative impl marker). + if (struct[IS_NEG_IDX]) { + // @ts-expect-error + list[1].before(display); + } else { + // @ts-expect-error + list[0].appendChild(display); + } currentNbImpls += 1; } } diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index 18d3b6a455d3..60df4fc10b8c 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -520,7 +520,7 @@ declare namespace rustdoc { * Provided by generated `trait.impl` files. */ type Implementors = { - [key: string]: Array<[string, number, Array]> + [key: string]: Array<[string, 0|1, number, Array]> } type TypeImpls = { From 985178dacf81d2baa21d0261c2cc85b374d0dd8c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 11 Jun 2025 22:19:47 +0200 Subject: [PATCH 492/585] Add GUI test to ensure that negative impls are correctly sorted --- tests/rustdoc-gui/implementors.goml | 47 +++++++++++++++---- .../rustdoc-gui/src/lib2/implementors/lib.rs | 5 ++ tests/rustdoc-gui/src/lib2/lib.rs | 3 ++ 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/tests/rustdoc-gui/implementors.goml b/tests/rustdoc-gui/implementors.goml index b39b95c1a9bf..99fb9b9aff54 100644 --- a/tests/rustdoc-gui/implementors.goml +++ b/tests/rustdoc-gui/implementors.goml @@ -2,18 +2,45 @@ // have the same display than the "local" ones. go-to: "file://" + |DOC_PATH| + "/implementors/trait.Whatever.html" assert: "#implementors-list" -// There are supposed to be two implementors listed. -assert-count: ("#implementors-list .impl", 2) +// There are supposed to be four implementors listed. +assert-count: ("#implementors-list .impl", 4) +// There are supposed to be two non-negative implementors. +assert-count: ("#implementors-list .negative-marker ~ *", 2) // Now we check that both implementors have an anchor, an ID and a similar DOM. -assert: ("#implementors-list .impl:nth-child(1) > a.anchor") -assert-attribute: ("#implementors-list .impl:nth-child(1)", {"id": "impl-Whatever-for-Struct"}) -assert-attribute: ("#implementors-list .impl:nth-child(1) > a.anchor", {"href": "#impl-Whatever-for-Struct"}) -assert: "#implementors-list .impl:nth-child(1) > .code-header" +define-function: ( + "check-dom", + [id], + block { + assert-attribute: (|id| + " > a.anchor", {"href": |id|}) + assert: |id| + " > .code-header" + }, +) -assert: ("#implementors-list .impl:nth-child(2) > a.anchor") -assert-attribute: ("#implementors-list .impl:nth-child(2)", {"id": "impl-Whatever-1"}) -assert-attribute: ("#implementors-list .impl:nth-child(2) > a.anchor", {"href": "#impl-Whatever-1"}) -assert: "#implementors-list .impl:nth-child(2) > .code-header" +call-function: ("check-dom", {"id": "#impl-Whatever-for-Struct2"}) +call-function: ("check-dom", {"id": "#impl-Whatever-2"}) +call-function: ("check-dom", {"id": "#impl-Whatever-for-Struct"}) +call-function: ("check-dom", {"id": "#impl-Whatever-3"}) + +// Ensure that negative impl are sorted first. +assert-property: ( + "#implementors-list > *:nth-child(1) > h3", + {"textContent": "impl !Whatever for Struct2"}, +) +assert-property: ( + "#implementors-list > *:nth-child(2) > h3", + {"textContent": "impl !Whatever for StructToImplOnReexport"}, +) +// Third one is the negative marker. +assert-attribute: ("#implementors-list > *:nth-child(3)", {"class": "negative-marker"}) +// This one is a `` so the selector is a bit different. +assert-property: ( + "#implementors-list > *:nth-child(4) section > h3", + {"textContent": "impl Whatever for Struct"}, +) +assert-property: ( + "#implementors-list > *:nth-child(5) > h3", + {"textContent": "impl Whatever for Foo"}, +) go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HasEmptyTraits.html" compare-elements-position-near-false: ( diff --git a/tests/rustdoc-gui/src/lib2/implementors/lib.rs b/tests/rustdoc-gui/src/lib2/implementors/lib.rs index 2842ac50dc1e..f08182003927 100644 --- a/tests/rustdoc-gui/src/lib2/implementors/lib.rs +++ b/tests/rustdoc-gui/src/lib2/implementors/lib.rs @@ -1,3 +1,5 @@ +#![feature(negative_impls)] + pub trait Whatever { type Foo; @@ -5,11 +7,14 @@ fn method() {} } pub struct Struct; +pub struct Struct2; impl Whatever for Struct { type Foo = u8; } +impl !Whatever for Struct2 {} + impl http::HttpTrait for Struct {} mod traits { diff --git a/tests/rustdoc-gui/src/lib2/lib.rs b/tests/rustdoc-gui/src/lib2/lib.rs index 400488cbe857..b87fdeea89da 100644 --- a/tests/rustdoc-gui/src/lib2/lib.rs +++ b/tests/rustdoc-gui/src/lib2/lib.rs @@ -1,6 +1,7 @@ // ignore-tidy-linelength #![feature(doc_cfg)] +#![feature(negative_impls)] pub mod another_folder; pub mod another_mod; @@ -60,6 +61,8 @@ impl implementors::Whatever for Foo { type Foo = u32; } +impl !implementors::Whatever for StructToImplOnReexport {} + #[doc(inline)] pub use implementors::TraitToReexport; From 13091ddc932be37c0ad3db7581e5f7776cf429d0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 Jun 2025 17:05:43 +0200 Subject: [PATCH 493/585] Make implementors list visible only when filled --- src/librustdoc/html/static/css/noscript.css | 4 ++++ src/librustdoc/html/static/css/rustdoc.css | 6 ++++++ src/librustdoc/html/static/js/main.js | 14 ++++++++++---- tests/rustdoc-gui/implementors.goml | 7 ++++++- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index 5c02e2eb26a3..6b80d3e7bbee 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -29,6 +29,10 @@ nav.sub { display: none; } +#synthetic-implementors-list, #implementors-list { + display: block; +} + /* Begin: styles for themes Keep the default light and dark themes synchronized with the ones in rustdoc.css */ diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 36f44a8072af..a5e43e1d7d19 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1158,6 +1158,12 @@ div.where { margin-left: calc(var(--docblock-indent) + var(--impl-items-indent)); } +#synthetic-implementors-list, #implementors-list { + /* To prevent layout shift when loading the page with extra implementors being loaded + from JS, we hide the list until it's complete. */ + display: none; +} + .item-info code { font-size: 0.875rem; } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index fb6b70492181..72d7e6131814 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -813,7 +813,7 @@ function preLoadCss(cssUrl) { return [elem, elem ? elem.querySelector(".negative-marker") : null]; } const implementors = implementorsElems("implementors-list"); - const synthetic_implementors = implementorsElems("synthetic-implementors-list"); + const syntheticImplementors = implementorsElems("synthetic-implementors-list"); const inlined_types = new Set(); const TEXT_IDX = 0; @@ -821,13 +821,13 @@ function preLoadCss(cssUrl) { const SYNTHETIC_IDX = 2; const TYPES_IDX = 3; - if (synthetic_implementors[0]) { + if (syntheticImplementors[0]) { // This `inlined_types` variable is used to avoid having the same implementation // showing up twice. For example "String" in the "Sync" doc page. // // By the way, this is only used by and useful for traits implemented automatically // (like "Send" and "Sync"). - onEachLazy(synthetic_implementors[0].getElementsByClassName("impl"), el => { + onEachLazy(syntheticImplementors[0].getElementsByClassName("impl"), el => { const aliases = el.getAttribute("data-aliases"); if (!aliases) { return; @@ -862,7 +862,7 @@ function preLoadCss(cssUrl) { struct_loop: for (const struct of structs) { - const list = struct[SYNTHETIC_IDX] ? synthetic_implementors : implementors; + const list = struct[SYNTHETIC_IDX] ? syntheticImplementors : implementors; // The types list is only used for synthetic impls. // If this changes, `main.js` and `write_shared.rs` both need changed. @@ -910,6 +910,12 @@ function preLoadCss(cssUrl) { currentNbImpls += 1; } } + if (implementors[0]) { + implementors[0].style.display = "block"; + } + if (syntheticImplementors[0]) { + syntheticImplementors[0].style.display = "block"; + } }; if (window.pending_implementors) { window.register_implementors(window.pending_implementors); diff --git a/tests/rustdoc-gui/implementors.goml b/tests/rustdoc-gui/implementors.goml index 99fb9b9aff54..d4542c6f7817 100644 --- a/tests/rustdoc-gui/implementors.goml +++ b/tests/rustdoc-gui/implementors.goml @@ -1,7 +1,7 @@ // The goal of this test is to check that the external trait implementors, generated with JS, // have the same display than the "local" ones. go-to: "file://" + |DOC_PATH| + "/implementors/trait.Whatever.html" -assert: "#implementors-list" +wait-for-css: ("#implementors-list", {"display": "block"}) // There are supposed to be four implementors listed. assert-count: ("#implementors-list .impl", 4) // There are supposed to be two non-negative implementors. @@ -66,3 +66,8 @@ assert-count: ("#implementors-list .impl", 1) go-to: "file://" + |DOC_PATH| + "/http/trait.HttpTrait.html" assert-count: ("#implementors-list .impl", 1) assert-attribute: ("#implementors-list .impl a.trait", {"href": "../http/trait.HttpTrait.html"}) + +// Now we check that if JS is disabled, the implementors list will be visible. +javascript: false +reload: +assert-css: ("#implementors-list", {"display": "block"}) From 183048c83ecd14e7ebcb60a9bca9ca8cf16374eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 10 Dec 2025 15:06:08 +0100 Subject: [PATCH 494/585] update docs --- .../rustc-dev-guide/src/bug-fix-procedure.md | 89 ++++++++++--------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md index 92488e8daeab..ab5e0cd68cfa 100644 --- a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md +++ b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md @@ -91,40 +91,46 @@ future-compatibility warnings. These are a special category of lint warning. Adding a new future-compatibility warning can be done as follows. ```rust -// 1. Define the lint in `compiler/rustc_middle/src/lint/builtin.rs`: +// 1. Define the lint in `compiler/rustc_lint/src/builtin.rs` and +// add the metadata for the future incompatibility: declare_lint! { - pub YOUR_ERROR_HERE, + pub YOUR_LINT_HERE, Warn, "illegal use of foo bar baz" -} - -// 2. Add to the list of HardwiredLints in the same file: -impl LintPass for HardwiredLints { - fn get_lints(&self) -> LintArray { - lint_array!( - .., - YOUR_ERROR_HERE - ) - } -} - -// 3. Register the lint in `compiler/rustc_lint/src/lib.rs`: -store.register_future_incompatible(sess, vec![ - ..., - FutureIncompatibleInfo { - id: LintId::of(YOUR_ERROR_HERE), + @future_incompatible = FutureIncompatibleInfo { reason: fcw!(FutureReleaseError #1234) // your tracking issue here! }, -]); +} + +// 2. Add a decidacted lint pass for it. +// This step can be skipped if you emit the lint as part of an existing pass. + +#[derive(Default)] +pub struct MyLintPass { + ... +} + +impl {Early,Late}LintPass for MyLintPass { + ... +} + +impl_lint_pass!(MyLintPass => [YOUR_LINT_HERE]); + +// 3. emit the lint somewhere in your lint pass: +cx.emit_span_lint( + YOUR_LINT_HERE, + pat.span, + // some diagnostic struct + MyDiagnostic { + ... + }, +); -// 4. Report the lint: -tcx.lint_node( - lint::builtin::YOUR_ERROR_HERE, - path_id, - binding.span, - format!("some helper message here")); ``` +Finally, register the lint in `compiler/rustc_lint/src/lib.rs`. +There are many examples in that file that already show how to do so. + #### Helpful techniques It can often be challenging to filter out new warnings from older, pre-existing @@ -221,7 +227,10 @@ The first reference you will likely find is the lint definition [in declare_lint! { pub OVERLAPPING_INHERENT_IMPLS, Deny, // this may also say Warning - "two overlapping inherent impls define an item with the same name were erroneously allowed" + "two overlapping inherent impls define an item with the same name were erroneously allowed", + @future_incompatible = FutureIncompatibleInfo { + reason: fcw!(FutureReleaseError #1234), // your tracking issue here! + }, } ``` @@ -231,19 +240,6 @@ the file as [part of a `lint_array!`][lintarraysource]; remove it too. [lintarraysource]: https://github.com/rust-lang/rust/blob/085d71c3efe453863739c1fb68fd9bd1beff214f/src/librustc/lint/builtin.rs#L252-L290 -Next, you see [a reference to `OVERLAPPING_INHERENT_IMPLS` in -`rustc_lint/src/lib.rs`][futuresource]. This is defining the lint as a "future -compatibility lint": - -```rust -FutureIncompatibleInfo { - id: LintId::of(OVERLAPPING_INHERENT_IMPLS), - reason: fcw!(FutureReleaseError #1234), // your tracking issue here! -}, -``` - -Remove this too. - #### Add the lint to the list of removed lints. In `compiler/rustc_lint/src/lib.rs` there is a list of "renamed and removed lints". @@ -269,6 +265,8 @@ self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, msg); ``` +You'll also often find `node_span_lint` used for this. + We want to convert this into an error. In some cases, there may be an existing error for this scenario. In others, we will need to allocate a fresh diagnostic code. [Instructions for allocating a fresh diagnostic @@ -285,6 +283,17 @@ struct_span_code_err!(self.dcx(), self.tcx.span_of_impl(item1).unwrap(), E0592, .emit(); ``` +Or better: a structured diagnostic like this: + +```rust +#[derive(Diagnostic)] +struct MyDiagnostic { + #[label] + span: Span, + ... +} +``` + #### Update tests Finally, run the test suite. These should be some tests that used to reference From fb9d3a5db4c3358f8ca22302f0e078675bc1a596 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Dec 2025 17:34:08 +0100 Subject: [PATCH 495/585] Simplify the sorting of impls and use CSS classes instead of plain JS to show/hide implementors --- src/librustdoc/html/render/print_item.rs | 10 +++---- src/librustdoc/html/render/write_shared.rs | 33 +++++---------------- src/librustdoc/html/static/css/noscript.css | 2 +- src/librustdoc/html/static/css/rustdoc.css | 2 +- src/librustdoc/html/static/js/main.js | 4 +-- 5 files changed, 17 insertions(+), 34 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 47e587626352..f88a5b8974fb 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -650,18 +650,18 @@ fn item_function(cx: &Context<'_>, it: &clean::Item, f: &clean::Function) -> imp /// /// This marker appears once in all trait impl lists to divide negative impls from positive impls. struct NegativeMarker { - inserted_negative_marker: bool, + inserted: bool, } impl NegativeMarker { fn new() -> Self { - Self { inserted_negative_marker: false } + Self { inserted: false } } fn insert_if_needed(&mut self, w: &mut fmt::Formatter<'_>, implementor: &Impl) -> fmt::Result { - if !self.inserted_negative_marker && !implementor.is_negative_trait_impl() { - write!(w, "
")?; - self.inserted_negative_marker = true; + if !self.inserted && !implementor.is_negative_trait_impl() { + w.write_str("
")?; + self.inserted = true; } Ok(()) } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index ca33531174b1..e0a37c95257c 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -747,7 +747,14 @@ fn get( path.push(format!("{remote_item_type}.{}.js", remote_path[remote_path.len() - 1])); let mut implementors = implementors.collect::>(); - implementors.sort_unstable(); + implementors.sort_unstable_by(|a, b| { + // We sort negative impls first. + match (a.is_negative, b.is_negative) { + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + _ => compare_names(&a.text, &b.text), + } + }); let part = OrderedJson::array_unsorted( implementors @@ -762,7 +769,6 @@ fn get( } } -#[derive(Eq)] struct Implementor { text: String, synthetic: bool, @@ -786,29 +792,6 @@ fn serialize(&self, serializer: S) -> Result } } -impl PartialEq for Implementor { - fn eq(&self, other: &Self) -> bool { - self.cmp(other) == Ordering::Equal - } -} - -impl PartialOrd for Implementor { - fn partial_cmp(&self, other: &Self) -> Option { - Some(Ord::cmp(self, other)) - } -} - -impl Ord for Implementor { - fn cmp(&self, other: &Self) -> Ordering { - // We sort negative impls first. - match (self.is_negative, other.is_negative) { - (false, true) => Ordering::Greater, - (true, false) => Ordering::Less, - _ => compare_names(&self.text, &other.text), - } - } -} - /// Collect the list of aliased types and their aliases. /// /// diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index 6b80d3e7bbee..6f44854b6914 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -29,7 +29,7 @@ nav.sub { display: none; } -#synthetic-implementors-list, #implementors-list { +#synthetic-implementors-list:not(.loaded), #implementors-list:not(.loaded) { display: block; } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index a5e43e1d7d19..69a79f2736e7 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1158,7 +1158,7 @@ div.where { margin-left: calc(var(--docblock-indent) + var(--impl-items-indent)); } -#synthetic-implementors-list, #implementors-list { +#synthetic-implementors-list:not(.loaded), #implementors-list:not(.loaded) { /* To prevent layout shift when loading the page with extra implementors being loaded from JS, we hide the list until it's complete. */ display: none; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 72d7e6131814..476ecd42d6f9 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -911,10 +911,10 @@ function preLoadCss(cssUrl) { } } if (implementors[0]) { - implementors[0].style.display = "block"; + implementors[0].classList.add("loaded"); } if (syntheticImplementors[0]) { - syntheticImplementors[0].style.display = "block"; + syntheticImplementors[0].classList.add("loaded"); } }; if (window.pending_implementors) { From 40891c79e67bd4e83f98c5866e62d24e2f2e06eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 9 Dec 2025 11:31:24 +0100 Subject: [PATCH 496/585] Use ubuntu:24.04 for the `x86_64-gnu-miri` and `x86_64-gnu-aux` jobs --- src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile | 2 +- src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile index a74db2250fc6..d4113736b544 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ghcr.io/rust-lang/ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile index ad2ee85c7bb5..db4fca71d637 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/rust-lang/ubuntu:22.04 +FROM ghcr.io/rust-lang/ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ From 96a700010103799b6988ab9800f72f2f2b43b696 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Mon, 8 Dec 2025 16:25:43 +0300 Subject: [PATCH 497/585] Rename some issue-* tests --- src/tools/tidy/src/issues.txt | 4 ---- .../const-item-no-type/dont-suggest-type-error.rs} | 0 .../const-item-no-type/dont-suggest-type-error.stderr} | 4 ++-- .../const-item-no-type/empty-array.rs} | 0 .../const-item-no-type/empty-array.stderr} | 4 ++-- .../const-item-no-type/in-macro.rs} | 0 .../const-item-no-type/in-macro.stderr} | 6 +++--- .../const-item-no-type/with-colon.fixed} | 0 .../const-item-no-type/with-colon.rs} | 0 .../const-item-no-type/with-colon.stderr} | 4 ++-- 10 files changed, 9 insertions(+), 13 deletions(-) rename tests/ui/{typeck/issue-79040.rs => consts/const-item-no-type/dont-suggest-type-error.rs} (100%) rename tests/ui/{typeck/issue-79040.stderr => consts/const-item-no-type/dont-suggest-type-error.stderr} (85%) rename tests/ui/{parser/issues/issue-89574.rs => consts/const-item-no-type/empty-array.rs} (100%) rename tests/ui/{parser/issues/issue-89574.stderr => consts/const-item-no-type/empty-array.stderr} (88%) rename tests/ui/{macros/issue-69396-const-no-type-in-macro.rs => consts/const-item-no-type/in-macro.rs} (100%) rename tests/ui/{macros/issue-69396-const-no-type-in-macro.stderr => consts/const-item-no-type/in-macro.stderr} (89%) rename tests/ui/{typeck/issue-100164.fixed => consts/const-item-no-type/with-colon.fixed} (100%) rename tests/ui/{typeck/issue-100164.rs => consts/const-item-no-type/with-colon.rs} (100%) rename tests/ui/{typeck/issue-100164.stderr => consts/const-item-no-type/with-colon.stderr} (82%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 1500c82c411a..45187a0b6450 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1583,7 +1583,6 @@ ui/macros/issue-6596-1.rs ui/macros/issue-6596-2.rs ui/macros/issue-68058.rs ui/macros/issue-68060.rs -ui/macros/issue-69396-const-no-type-in-macro.rs ui/macros/issue-69838-mods-relative-to-included-path.rs ui/macros/issue-70446.rs ui/macros/issue-75982-foreign-macro-weird-mod.rs @@ -2100,7 +2099,6 @@ ui/parser/issues/issue-88770.rs ui/parser/issues/issue-88818.rs ui/parser/issues/issue-89388.rs ui/parser/issues/issue-89396.rs -ui/parser/issues/issue-89574.rs ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.rs ui/parser/issues/issue-90728.rs ui/parser/issues/issue-90993.rs @@ -2880,7 +2878,6 @@ ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.rs ui/typeck/auxiliary/issue-29181.rs ui/typeck/auxiliary/issue-36708.rs ui/typeck/auxiliary/issue-81943-lib.rs -ui/typeck/issue-100164.rs ui/typeck/issue-100246.rs ui/typeck/issue-100285.rs ui/typeck/issue-103899.rs @@ -2937,7 +2934,6 @@ ui/typeck/issue-74933.rs ui/typeck/issue-75883.rs ui/typeck/issue-75889.rs ui/typeck/issue-7813.rs -ui/typeck/issue-79040.rs ui/typeck/issue-80207-unsized-return.rs ui/typeck/issue-80779.rs ui/typeck/issue-81293.rs diff --git a/tests/ui/typeck/issue-79040.rs b/tests/ui/consts/const-item-no-type/dont-suggest-type-error.rs similarity index 100% rename from tests/ui/typeck/issue-79040.rs rename to tests/ui/consts/const-item-no-type/dont-suggest-type-error.rs diff --git a/tests/ui/typeck/issue-79040.stderr b/tests/ui/consts/const-item-no-type/dont-suggest-type-error.stderr similarity index 85% rename from tests/ui/typeck/issue-79040.stderr rename to tests/ui/consts/const-item-no-type/dont-suggest-type-error.stderr index 4ab8df8f6c93..8f1fcc645b9c 100644 --- a/tests/ui/typeck/issue-79040.stderr +++ b/tests/ui/consts/const-item-no-type/dont-suggest-type-error.stderr @@ -1,5 +1,5 @@ error[E0369]: cannot add `{integer}` to `&str` - --> $DIR/issue-79040.rs:2:25 + --> $DIR/dont-suggest-type-error.rs:2:25 | LL | const FOO = "hello" + 1; | ------- ^ - {integer} @@ -7,7 +7,7 @@ LL | const FOO = "hello" + 1; | &str error: missing type for `const` item - --> $DIR/issue-79040.rs:2:14 + --> $DIR/dont-suggest-type-error.rs:2:14 | LL | const FOO = "hello" + 1; | ^ diff --git a/tests/ui/parser/issues/issue-89574.rs b/tests/ui/consts/const-item-no-type/empty-array.rs similarity index 100% rename from tests/ui/parser/issues/issue-89574.rs rename to tests/ui/consts/const-item-no-type/empty-array.rs diff --git a/tests/ui/parser/issues/issue-89574.stderr b/tests/ui/consts/const-item-no-type/empty-array.stderr similarity index 88% rename from tests/ui/parser/issues/issue-89574.stderr rename to tests/ui/consts/const-item-no-type/empty-array.stderr index f40f5aded8ef..fe307d50353e 100644 --- a/tests/ui/parser/issues/issue-89574.stderr +++ b/tests/ui/consts/const-item-no-type/empty-array.stderr @@ -1,11 +1,11 @@ error[E0282]: type annotations needed - --> $DIR/issue-89574.rs:2:25 + --> $DIR/empty-array.rs:2:25 | LL | const EMPTY_ARRAY = []; | ^^ cannot infer type error: missing type for `const` item - --> $DIR/issue-89574.rs:2:22 + --> $DIR/empty-array.rs:2:22 | LL | const EMPTY_ARRAY = []; | ^ diff --git a/tests/ui/macros/issue-69396-const-no-type-in-macro.rs b/tests/ui/consts/const-item-no-type/in-macro.rs similarity index 100% rename from tests/ui/macros/issue-69396-const-no-type-in-macro.rs rename to tests/ui/consts/const-item-no-type/in-macro.rs diff --git a/tests/ui/macros/issue-69396-const-no-type-in-macro.stderr b/tests/ui/consts/const-item-no-type/in-macro.stderr similarity index 89% rename from tests/ui/macros/issue-69396-const-no-type-in-macro.stderr rename to tests/ui/consts/const-item-no-type/in-macro.stderr index 4342d7d88f54..d6182aa11427 100644 --- a/tests/ui/macros/issue-69396-const-no-type-in-macro.stderr +++ b/tests/ui/consts/const-item-no-type/in-macro.stderr @@ -1,5 +1,5 @@ error[E0428]: the name `A` is defined multiple times - --> $DIR/issue-69396-const-no-type-in-macro.rs:4:13 + --> $DIR/in-macro.rs:4:13 | LL | const A = "A".$fn(); | ^^^^^^^^^^^^^^^^^^^^ `A` redefined here @@ -14,7 +14,7 @@ LL | | } = note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) error: missing type for `const` item - --> $DIR/issue-69396-const-no-type-in-macro.rs:4:20 + --> $DIR/in-macro.rs:4:20 | LL | const A = "A".$fn(); | ^ help: provide a type for the constant: `: usize` @@ -28,7 +28,7 @@ LL | | } = note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0121]: missing type for item - --> $DIR/issue-69396-const-no-type-in-macro.rs:4:20 + --> $DIR/in-macro.rs:4:20 | LL | const A = "A".$fn(); | ^ not allowed in type signatures diff --git a/tests/ui/typeck/issue-100164.fixed b/tests/ui/consts/const-item-no-type/with-colon.fixed similarity index 100% rename from tests/ui/typeck/issue-100164.fixed rename to tests/ui/consts/const-item-no-type/with-colon.fixed diff --git a/tests/ui/typeck/issue-100164.rs b/tests/ui/consts/const-item-no-type/with-colon.rs similarity index 100% rename from tests/ui/typeck/issue-100164.rs rename to tests/ui/consts/const-item-no-type/with-colon.rs diff --git a/tests/ui/typeck/issue-100164.stderr b/tests/ui/consts/const-item-no-type/with-colon.stderr similarity index 82% rename from tests/ui/typeck/issue-100164.stderr rename to tests/ui/consts/const-item-no-type/with-colon.stderr index 06a132d65142..adbea1f355a0 100644 --- a/tests/ui/typeck/issue-100164.stderr +++ b/tests/ui/consts/const-item-no-type/with-colon.stderr @@ -1,11 +1,11 @@ error: missing type for `const` item - --> $DIR/issue-100164.rs:3:10 + --> $DIR/with-colon.rs:3:10 | LL | const _A: = 123; | ^ help: provide a type for the constant: `i32` error: missing type for `const` item - --> $DIR/issue-100164.rs:7:14 + --> $DIR/with-colon.rs:7:14 | LL | const _B: = 123; | ^ help: provide a type for the constant: `i32` From 2bc2a0db6956f960a5218cea19f07ff8dd4c04cd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Dec 2025 20:18:42 +0100 Subject: [PATCH 498/585] For now, ignore target checking for doc attributes in attr_parsing --- .../rustc_attr_parsing/src/attributes/doc.rs | 66 ++++++++++--------- .../ui/attributes/issue-115264-expr-field.rs | 2 - .../attributes/issue-115264-expr-field.stderr | 12 ---- tests/ui/attributes/issue-115264-pat-field.rs | 2 - .../attributes/issue-115264-pat-field.stderr | 12 ---- tests/ui/lint/unused/useless-comment.rs | 6 -- tests/ui/lint/unused/useless-comment.stderr | 62 +++++------------ .../rustdoc/check-doc-alias-attr-location.rs | 8 --- .../check-doc-alias-attr-location.stderr | 45 ++----------- 9 files changed, 53 insertions(+), 162 deletions(-) delete mode 100644 tests/ui/attributes/issue-115264-expr-field.stderr delete mode 100644 tests/ui/attributes/issue-115264-pat-field.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index ccb6a873fb12..2fe1b4ad174c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -7,7 +7,7 @@ use rustc_span::{Span, Symbol, edition, sym}; use thin_vec::ThinVec; -use super::prelude::{Allow, AllowedTargets, Error, MethodKind, Target}; +use super::prelude::{ALL_TARGETS, AllowedTargets}; use super::{AcceptMapping, AttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, PathParser}; @@ -583,37 +583,39 @@ impl AttributeParser for DocParser { this.accept_single_doc_attr(cx, args); }, )]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ - Allow(Target::ExternCrate), - Allow(Target::Use), - Allow(Target::Static), - Allow(Target::Const), - Allow(Target::Fn), - Allow(Target::Mod), - Allow(Target::ForeignMod), - Allow(Target::TyAlias), - Allow(Target::Enum), - Allow(Target::Variant), - Allow(Target::Struct), - Allow(Target::Field), - Allow(Target::Union), - Allow(Target::Trait), - Allow(Target::TraitAlias), - Allow(Target::Impl { of_trait: true }), - Allow(Target::Impl { of_trait: false }), - Allow(Target::AssocConst), - Allow(Target::Method(MethodKind::Inherent)), - Allow(Target::Method(MethodKind::Trait { body: true })), - Allow(Target::Method(MethodKind::Trait { body: false })), - Allow(Target::Method(MethodKind::TraitImpl)), - Allow(Target::AssocTy), - Allow(Target::ForeignFn), - Allow(Target::ForeignStatic), - Allow(Target::ForeignTy), - Allow(Target::MacroDef), - Allow(Target::Crate), - Error(Target::WherePredicate), - ]); + // FIXME: Currently emitted from 2 different places, generating duplicated warnings. + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + // const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + // Allow(Target::ExternCrate), + // Allow(Target::Use), + // Allow(Target::Static), + // Allow(Target::Const), + // Allow(Target::Fn), + // Allow(Target::Mod), + // Allow(Target::ForeignMod), + // Allow(Target::TyAlias), + // Allow(Target::Enum), + // Allow(Target::Variant), + // Allow(Target::Struct), + // Allow(Target::Field), + // Allow(Target::Union), + // Allow(Target::Trait), + // Allow(Target::TraitAlias), + // Allow(Target::Impl { of_trait: true }), + // Allow(Target::Impl { of_trait: false }), + // Allow(Target::AssocConst), + // Allow(Target::Method(MethodKind::Inherent)), + // Allow(Target::Method(MethodKind::Trait { body: true })), + // Allow(Target::Method(MethodKind::Trait { body: false })), + // Allow(Target::Method(MethodKind::TraitImpl)), + // Allow(Target::AssocTy), + // Allow(Target::ForeignFn), + // Allow(Target::ForeignStatic), + // Allow(Target::ForeignTy), + // Allow(Target::MacroDef), + // Allow(Target::Crate), + // Error(Target::WherePredicate), + // ]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.nb_doc_attrs != 0 { diff --git a/tests/ui/attributes/issue-115264-expr-field.rs b/tests/ui/attributes/issue-115264-expr-field.rs index d8189626fb0f..8adb68deb5b4 100644 --- a/tests/ui/attributes/issue-115264-expr-field.rs +++ b/tests/ui/attributes/issue-115264-expr-field.rs @@ -12,8 +12,6 @@ struct X { fn main() { let _ = X { #[doc(alias = "StructItem")] - //~^ WARN: attribute cannot be used on struct fields - //~| WARN: this was previously accepted by the compiler but is being phased out foo: 123, }; } diff --git a/tests/ui/attributes/issue-115264-expr-field.stderr b/tests/ui/attributes/issue-115264-expr-field.stderr deleted file mode 100644 index 6bb9dfc90c93..000000000000 --- a/tests/ui/attributes/issue-115264-expr-field.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: `#[doc]` attribute cannot be used on struct fields - --> $DIR/issue-115264-expr-field.rs:14:9 - | -LL | #[doc(alias = "StructItem")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - = note: requested on the command line with `-W unused-attributes` - -warning: 1 warning emitted - diff --git a/tests/ui/attributes/issue-115264-pat-field.rs b/tests/ui/attributes/issue-115264-pat-field.rs index 0c8966b5893f..53e3b4524d60 100644 --- a/tests/ui/attributes/issue-115264-pat-field.rs +++ b/tests/ui/attributes/issue-115264-pat-field.rs @@ -12,8 +12,6 @@ struct X { fn main() { let X { #[doc(alias = "StructItem")] - //~^ WARN: attribute cannot be used on pattern fields - //~| WARN: this was previously accepted by the compiler but is being phased out foo } = X { foo: 123 diff --git a/tests/ui/attributes/issue-115264-pat-field.stderr b/tests/ui/attributes/issue-115264-pat-field.stderr deleted file mode 100644 index a5b221110789..000000000000 --- a/tests/ui/attributes/issue-115264-pat-field.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: `#[doc]` attribute cannot be used on pattern fields - --> $DIR/issue-115264-pat-field.rs:14:9 - | -LL | #[doc(alias = "StructItem")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - = note: requested on the command line with `-W unused-attributes` - -warning: 1 warning emitted - diff --git a/tests/ui/lint/unused/useless-comment.rs b/tests/ui/lint/unused/useless-comment.rs index fee6cff640f6..24ff91752081 100644 --- a/tests/ui/lint/unused/useless-comment.rs +++ b/tests/ui/lint/unused/useless-comment.rs @@ -18,8 +18,6 @@ fn foo() { /// a //~ ERROR unused doc comment #[doc(test(attr(allow(dead_code))))] //~^ ERROR unused doc comment - //~| ERROR `#[doc]` attribute cannot be used on statements - //~| WARN this was previously accepted by the compiler let x = 12; /// multi-line //~ ERROR unused doc comment @@ -30,8 +28,6 @@ fn foo() { 1 => {}, #[doc(test(attr(allow(dead_code))))] //~^ ERROR unused doc comment - //~| ERROR `#[doc]` attribute cannot be used on match arms [unused_attributes] - //~| WARN this was previously accepted by the compiler _ => {} } @@ -47,8 +43,6 @@ fn foo() { #[doc(test(attr(allow(dead_code))))] //~^ ERROR unused doc comment - //~| ERROR `#[doc]` attribute cannot be used on statements - //~| WARN this was previously accepted by the compiler let x = /** comment */ 47; //~ ERROR unused doc comment /// dox //~ ERROR unused doc comment diff --git a/tests/ui/lint/unused/useless-comment.stderr b/tests/ui/lint/unused/useless-comment.stderr index 3d3937e7a402..22e63caf607a 100644 --- a/tests/ui/lint/unused/useless-comment.stderr +++ b/tests/ui/lint/unused/useless-comment.stderr @@ -33,7 +33,7 @@ LL | unsafe extern "C" { } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:45:5 + --> $DIR/useless-comment.rs:41:5 | LL | /// bar | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macro invocations @@ -56,14 +56,14 @@ error: unused doc comment | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | let x = 12; | ----------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:25:5 + --> $DIR/useless-comment.rs:23:5 | LL | / /// multi-line LL | | /// doc comment @@ -73,7 +73,7 @@ LL | / match x { LL | | /// c LL | | 1 => {}, LL | | #[doc(test(attr(allow(dead_code))))] -... | +LL | | LL | | _ => {} LL | | } | |_____- rustdoc does not generate documentation for expressions @@ -81,7 +81,7 @@ LL | | } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:29:9 + --> $DIR/useless-comment.rs:27:9 | LL | /// c | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -91,18 +91,18 @@ LL | 1 => {}, = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:31:9 + --> $DIR/useless-comment.rs:29:9 | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | _ => {} | ------- rustdoc does not generate documentation for match arms | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:38:5 + --> $DIR/useless-comment.rs:34:5 | LL | /// foo | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | unsafe {} = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:41:5 + --> $DIR/useless-comment.rs:37:5 | LL | #[doc = "foo"] | ^^^^^^^^^^^^^^ @@ -123,7 +123,7 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:42:5 + --> $DIR/useless-comment.rs:38:5 | LL | #[doc = "bar"] | ^^^^^^^^^^^^^^ @@ -133,18 +133,18 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:48:5 + --> $DIR/useless-comment.rs:44:5 | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | let x = /** comment */ 47; | -------------------------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:52:13 + --> $DIR/useless-comment.rs:46:13 | LL | let x = /** comment */ 47; | ^^^^^^^^^^^^^^ -- rustdoc does not generate documentation for expressions @@ -152,7 +152,7 @@ LL | let x = /** comment */ 47; = help: use `/* */` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:54:5 + --> $DIR/useless-comment.rs:48:5 | LL | /// dox | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,37 +163,5 @@ LL | | } | = help: use `//` for a plain comment -error: `#[doc]` attribute cannot be used on statements - --> $DIR/useless-comment.rs:19:5 - | -LL | #[doc(test(attr(allow(dead_code))))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements -note: the lint level is defined here - --> $DIR/useless-comment.rs:4:9 - | -LL | #![deny(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ - -error: `#[doc]` attribute cannot be used on match arms - --> $DIR/useless-comment.rs:31:9 - | -LL | #[doc(test(attr(allow(dead_code))))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - -error: `#[doc]` attribute cannot be used on statements - --> $DIR/useless-comment.rs:48:5 - | -LL | #[doc(test(attr(allow(dead_code))))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - -error: aborting due to 18 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/rustdoc/check-doc-alias-attr-location.rs b/tests/ui/rustdoc/check-doc-alias-attr-location.rs index 8ba6cfde2d6d..45777c5edf4d 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr-location.rs +++ b/tests/ui/rustdoc/check-doc-alias-attr-location.rs @@ -21,22 +21,14 @@ impl Foo for Bar { type X = i32; fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X { //~^ ERROR - //~| WARN `#[doc]` attribute cannot be used on function params - //~| WARN: this was previously accepted by the compiler #[doc(alias = "stmt")] //~^ ERROR - //~| WARN `#[doc]` attribute cannot be used on statements - //~| WARN: this was previously accepted by the compiler let x = 0; #[doc(alias = "expr")] //~^ ERROR - //~| WARN `#[doc]` attribute cannot be used on expressions - //~| WARN: this was previously accepted by the compiler match x { #[doc(alias = "arm")] //~^ ERROR - //~| WARN `#[doc]` attribute cannot be used on match arms - //~| WARN: this was previously accepted by the compiler _ => 0 } } diff --git a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr index 24be42036f6f..f587c17c1f3e 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr +++ b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr @@ -29,59 +29,22 @@ LL | #[doc(alias = "assoc")] | ^^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on statement - --> $DIR/check-doc-alias-attr-location.rs:26:23 + --> $DIR/check-doc-alias-attr-location.rs:24:23 | LL | #[doc(alias = "stmt")] | ^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on expression - --> $DIR/check-doc-alias-attr-location.rs:31:23 + --> $DIR/check-doc-alias-attr-location.rs:27:23 | LL | #[doc(alias = "expr")] | ^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on match arm - --> $DIR/check-doc-alias-attr-location.rs:36:27 + --> $DIR/check-doc-alias-attr-location.rs:30:27 | LL | #[doc(alias = "arm")] | ^^^^^ -warning: `#[doc]` attribute cannot be used on function params - --> $DIR/check-doc-alias-attr-location.rs:22:12 - | -LL | fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - = note: requested on the command line with `-W unused-attributes` - -warning: `#[doc]` attribute cannot be used on statements - --> $DIR/check-doc-alias-attr-location.rs:26:9 - | -LL | #[doc(alias = "stmt")] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - -warning: `#[doc]` attribute cannot be used on expressions - --> $DIR/check-doc-alias-attr-location.rs:31:9 - | -LL | #[doc(alias = "expr")] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - -warning: `#[doc]` attribute cannot be used on match arms - --> $DIR/check-doc-alias-attr-location.rs:36:13 - | -LL | #[doc(alias = "arm")] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - -error: aborting due to 8 previous errors; 4 warnings emitted +error: aborting due to 8 previous errors From 507b67f45745194e151e373325e7ec2154589484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 8 Nov 2025 22:26:43 +0000 Subject: [PATCH 499/585] Add test for incorrect macro span replacement --- .../ui/span/macro-span-caller-replacement.rs | 16 ++++++++++ .../span/macro-span-caller-replacement.stderr | 29 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/ui/span/macro-span-caller-replacement.rs create mode 100644 tests/ui/span/macro-span-caller-replacement.stderr diff --git a/tests/ui/span/macro-span-caller-replacement.rs b/tests/ui/span/macro-span-caller-replacement.rs new file mode 100644 index 000000000000..45af729beb1a --- /dev/null +++ b/tests/ui/span/macro-span-caller-replacement.rs @@ -0,0 +1,16 @@ +macro_rules! macro_with_format { () => { + fn check_5(arg : usize) -> String { + let s : &str; + if arg < 5 { + s = format!("{arg}"); + } else { + s = String::new(); //~ ERROR mismatched types + } + String::from(s) + } +}} + +fn main() { + macro_with_format!(); //~ ERROR mismatched types + println!( "{}", check_5(6) ); +} diff --git a/tests/ui/span/macro-span-caller-replacement.stderr b/tests/ui/span/macro-span-caller-replacement.stderr new file mode 100644 index 000000000000..1c831f96ec0c --- /dev/null +++ b/tests/ui/span/macro-span-caller-replacement.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> $DIR/macro-span-caller-replacement.rs:5:17 + | +LL | macro_with_format!(); + | ^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `String` + | + = note: this error originates in the macro `format` which comes from the expansion of the macro `macro_with_format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/macro-span-caller-replacement.rs:7:17 + | +LL | let s : &str; + | ---- expected due to this type +... +LL | s = String::new(); + | ^^^^^^^^^^^^^ expected `&str`, found `String` +... +LL | macro_with_format!(); + | -------------------- in this macro invocation + | + = note: this error originates in the macro `macro_with_format` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing here + | +LL | s = &String::new(); + | + + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 1bd7934d891cee73664367cfff8f914edda3d9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 8 Nov 2025 23:35:55 +0000 Subject: [PATCH 500/585] Point at span within local macros even when error happens in nested external macro ``` error[E0308]: mismatched types --> $DIR/macro-span-caller-replacement.rs:5:17 | LL | s = format!("{arg}"); | ^^^^^^^^^^^^^^^^ expected `&str`, found `String` ... LL | macro_with_format!(); | -------------------- in this macro invocation | = note: this error originates in the macro `format` which comes from the expansion of the macro `macro_with_format` (in Nightly builds, run with -Z macro-backtrace for more info) ``` --- compiler/rustc_errors/src/emitter.rs | 9 +- .../tests/fail/panic/tls_macro_drop_panic.rs | 2 +- .../rustc-dev-remap.only-remap.stderr | 3 + .../rustc-dev-remap.remap-unremap.stderr | 5 +- ...diagnostic-derive-doc-comment-field.stderr | 6 + .../diagnostic-derive.stderr | 3 + tests/ui/binop/binary-op-suggest-deref.stderr | 12 +- tests/ui/binop/binop-mul-i32-f32.stderr | 12 +- .../const_param_ty_bad.stderr | 6 + .../const-eval/const-eval-overflow-3b.stderr | 12 +- .../const-eval/const-eval-overflow-4b.stderr | 12 +- tests/ui/consts/const-eval/issue-85155.stderr | 7 +- tests/ui/consts/const-eval/parse_ints.stderr | 12 ++ tests/ui/consts/const-ptr-is-null.stderr | 7 + .../ui/consts/const_transmute_type_id2.stderr | 4 + .../ui/consts/const_transmute_type_id3.stderr | 4 + .../ui/consts/const_transmute_type_id4.stderr | 4 + .../ui/consts/const_transmute_type_id5.stderr | 4 + .../ui/consts/const_transmute_type_id6.stderr | 4 + tests/ui/consts/timeout.stderr | 5 + .../hygiene/cross-crate-name-hiding-2.stderr | 6 +- tests/ui/impl-trait/equality.stderr | 12 +- .../ambiguous-glob-vs-expanded-extern.stderr | 14 +- .../issue-41731-infinite-macro-print.stderr | 14 +- .../issue-41731-infinite-macro-println.stderr | 14 +- .../invalid-iterator-chain-fixable.stderr | 24 +++- ...valid-iterator-chain-with-int-infer.stderr | 8 +- .../iterators/invalid-iterator-chain.stderr | 40 ++++-- tests/ui/mismatched_types/binops.stderr | 12 +- ...oat-integer-subtraction-error-24352.stderr | 12 +- tests/ui/never_type/issue-13352.stderr | 12 +- .../not-suggest-float-literal.stderr | 132 +++++++++++++----- .../suggest-float-literal.stderr | 96 +++++++++---- tests/ui/on-unimplemented/slice-index.stderr | 3 + tests/ui/on-unimplemented/sum.stderr | 16 ++- tests/ui/proc-macro/mixed-site-span.stderr | 28 ++-- .../ui/span/macro-span-caller-replacement.rs | 6 +- .../span/macro-span-caller-replacement.stderr | 5 +- tests/ui/span/multiline-span-simple.stderr | 12 +- ...ut-not-available.alignment_mismatch.stderr | 3 + ...gest-deref-inside-macro-issue-58298.stderr | 7 +- .../invalid-suggest-deref-issue-127590.stderr | 16 +++ tests/ui/try-trait/bad-interconversion.stderr | 6 + .../self-referential-2.current.stderr | 3 + .../self-referential-3.stderr | 3 + .../self-referential-4.stderr | 9 ++ .../self-referential.stderr | 9 ++ tests/ui/type/type-check-defaults.stderr | 12 +- ...0017-format-into-help-deletes-macro.stderr | 21 ++- ...2007-leaked-writeln-macro-internals.stderr | 7 +- tests/ui/typeck/issue-81293.stderr | 12 +- tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr | 24 +++- 52 files changed, 569 insertions(+), 162 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index d08d5a5a1ea2..78feb60261bd 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -474,9 +474,12 @@ fn fix_multispan_in_extern_macros(&self, span: &mut MultiSpan) { .chain(span.span_labels().iter().map(|sp_label| sp_label.span)) .filter_map(|sp| { if !sp.is_dummy() && source_map.is_imported(sp) { - let maybe_callsite = sp.source_callsite(); - if sp != maybe_callsite { - return Some((sp, maybe_callsite)); + let mut span = sp; + while let Some(callsite) = span.parent_callsite() { + span = callsite; + if !source_map.is_imported(span) { + return Some((sp, span)); + } } } None diff --git a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.rs b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.rs index 107d70a3b3c7..a207d3923124 100644 --- a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.rs +++ b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.rs @@ -1,7 +1,7 @@ //@error-in-other-file: aborted execution // Backtraces vary wildly between platforms, we have to normalize away almost the entire thing //@normalize-stderr-test: "'main'|''" -> "$$NAME" -//@normalize-stderr-test: ".*(note|-->|\|).*\n" -> "" +//@normalize-stderr-test: ".*(note|-->|:::|\|).*\n" -> "" pub struct NoisyDrop {} diff --git a/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr index 15e2cf66f8f8..d2303ef4bbb5 100644 --- a/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr +++ b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr @@ -18,6 +18,9 @@ help: the following other types implement trait `VisitorResult` = note: `ControlFlow` note: required by a bound in `rustc_ast::visit::Visitor::Result` --> /rustc-dev/xyz/compiler/rustc_ast/src/visit.rs:LL:COL + ::: /rustc-dev/xyz/compiler/rustc_ast/src/visit.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `common_visitor_and_walkers` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr index b9276974c465..50bb60e78d68 100644 --- a/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr +++ b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr @@ -20,8 +20,11 @@ LL | impl VisitorResult for ControlFlow { note: required by a bound in `rustc_ast::visit::Visitor::Result` --> $COMPILER_DIR_REAL/rustc_ast/src/visit.rs:LL:COL | +LL | type Result: VisitorResult = (); + | ^^^^^^^^^^^^^ required by this bound in `Visitor::Result` +... LL | common_visitor_and_walkers!(Visitor<'a>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Visitor::Result` + | ---------------------------------------- in this macro invocation = note: this error originates in the macro `common_visitor_and_walkers` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr index 8b6c4b181c0f..72e150dd5178 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr @@ -15,6 +15,9 @@ LL | struct NotIntoDiagArg; = help: normalized in stderr note: required by a bound in `Diag::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + ::: $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + | + = note: in this macro invocation = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotIntoDiagArg: IntoDiagArg` is not satisfied @@ -34,6 +37,9 @@ LL | struct NotIntoDiagArg; = help: normalized in stderr note: required by a bound in `Diag::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + ::: $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + | + = note: in this macro invocation = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 8a0e753a9c52..f2244a968769 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -665,6 +665,9 @@ LL | struct Hello {} = help: normalized in stderr note: required by a bound in `Diag::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + ::: $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + | + = note: in this macro invocation = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 85 previous errors diff --git a/tests/ui/binop/binary-op-suggest-deref.stderr b/tests/ui/binop/binary-op-suggest-deref.stderr index 0c9b1d9bd938..eb17c6cbbc66 100644 --- a/tests/ui/binop/binary-op-suggest-deref.stderr +++ b/tests/ui/binop/binary-op-suggest-deref.stderr @@ -305,13 +305,19 @@ LL | let _ = FOO & (*"Sized".to_string().into_boxed_str()); help: the following other types implement trait `BitAnd` --> $SRC_DIR/core/src/ops/bit.rs:LL:COL | - = note: `&i32` implements `BitAnd` + = note: `i32` implements `BitAnd` + ::: $SRC_DIR/core/src/ops/bit.rs:LL:COL | - = note: `&i32` implements `BitAnd` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i32` implements `BitAnd` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i32` implements `BitAnd<&i32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i32` implements `BitAnd` + = note: `&i32` implements `BitAnd` = note: this error originates in the macro `bitand_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `str` cannot be known at compilation time diff --git a/tests/ui/binop/binop-mul-i32-f32.stderr b/tests/ui/binop/binop-mul-i32-f32.stderr index dc4e7fdf6c14..a8893700b1be 100644 --- a/tests/ui/binop/binop-mul-i32-f32.stderr +++ b/tests/ui/binop/binop-mul-i32-f32.stderr @@ -8,13 +8,19 @@ LL | x * y help: the following other types implement trait `Mul` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Mul` + = note: `i32` implements `Mul` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Mul` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i32` implements `Mul` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i32` implements `Mul<&i32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i32` implements `Mul` + = note: `&i32` implements `Mul` = note: this error originates in the macro `mul_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr index 75718fbbba0a..5109dccd96a1 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr @@ -84,6 +84,9 @@ LL | check(&mut () as *mut ()); | help: the trait `ConstParamTy_` is implemented for `()` --> $SRC_DIR/core/src/marker.rs:LL:COL + ::: $SRC_DIR/core/src/marker.rs:LL:COL + | + = note: in this macro invocation note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | @@ -101,6 +104,9 @@ LL | check(&() as *const ()); | help: the trait `ConstParamTy_` is implemented for `()` --> $SRC_DIR/core/src/marker.rs:LL:COL + ::: $SRC_DIR/core/src/marker.rs:LL:COL + | + = note: in this macro invocation note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr index 4209e4bcee52..54d77b1bf3e9 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -14,13 +14,19 @@ LL | = [0; (i8::MAX + 1u8) as usize]; help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i8` implements `Add` + = note: `i8` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i8` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i8` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i8` implements `Add<&i8>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i8` implements `Add` + = note: `&i8` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr index 2677d7956cc9..6c6472610b72 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -14,13 +14,19 @@ LL | : [u32; (i8::MAX as i8 + 1u8) as usize] help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i8` implements `Add` + = note: `i8` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i8` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i8` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i8` implements `Add<&i8>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i8` implements `Add` + = note: `&i8` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0604]: only `u8` can be cast as `char`, not `i8` diff --git a/tests/ui/consts/const-eval/issue-85155.stderr b/tests/ui/consts/const-eval/issue-85155.stderr index 486d2adaf8cd..dfc784bc7a4f 100644 --- a/tests/ui/consts/const-eval/issue-85155.stderr +++ b/tests/ui/consts/const-eval/issue-85155.stderr @@ -5,10 +5,13 @@ LL | let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `post_monomorphization_error::ValidateConstImm::<2, 0, 1>::VALID` failed here note: erroneous constant encountered - --> $DIR/auxiliary/post_monomorphization_error.rs:19:5 + --> $DIR/auxiliary/post_monomorphization_error.rs:13:17 | +LL | let _ = $crate::ValidateConstImm::<$imm, 0, { (1 << 1) - 1 }>::VALID; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | static_assert_imm1!(IMM1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------- in this macro invocation | = note: this note originates in the macro `static_assert_imm1` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const-eval/parse_ints.stderr b/tests/ui/consts/const-eval/parse_ints.stderr index 9c9d083e7ca2..7f42e20cf8e8 100644 --- a/tests/ui/consts/const-eval/parse_ints.stderr +++ b/tests/ui/consts/const-eval/parse_ints.stderr @@ -6,8 +6,14 @@ LL | const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); }; | note: inside `core::num::::from_str_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL + ::: $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: in this macro invocation note: inside `core::num::::from_ascii_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL + ::: $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `from_str_int_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation panicked: from_ascii_radix: radix must lie in the range `[2, 36]` @@ -18,8 +24,14 @@ LL | const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); }; | note: inside `core::num::::from_str_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL + ::: $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: in this macro invocation note: inside `core::num::::from_ascii_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL + ::: $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `from_str_int_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-ptr-is-null.stderr b/tests/ui/consts/const-ptr-is-null.stderr index be0a1346c647..b532ed9d4c5f 100644 --- a/tests/ui/consts/const-ptr-is-null.stderr +++ b/tests/ui/consts/const-ptr-is-null.stderr @@ -5,9 +5,16 @@ LL | assert!(!ptr.wrapping_sub(512).is_null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `MAYBE_NULL` failed inside this call | note: inside `std::ptr::const_ptr::::is_null` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + ::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: in this macro invocation note: inside `std::ptr::const_ptr::::is_null::compiletime` + --> $SRC_DIR/core/src/panic.rs:LL:COL --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: in this macro invocation error: aborting due to 1 previous error diff --git a/tests/ui/consts/const_transmute_type_id2.stderr b/tests/ui/consts/const_transmute_type_id2.stderr index 5646eb1257d1..b420deaa49ce 100644 --- a/tests/ui/consts/const_transmute_type_id2.stderr +++ b/tests/ui/consts/const_transmute_type_id2.stderr @@ -5,7 +5,11 @@ LL | assert!(a == b); | ^^^^^^ evaluation of `_` failed inside this call | note: inside `::eq` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL --> $SRC_DIR/core/src/any.rs:LL:COL + ::: $SRC_DIR/core/src/any.rs:LL:COL + | + = note: in this macro invocation 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) diff --git a/tests/ui/consts/const_transmute_type_id3.stderr b/tests/ui/consts/const_transmute_type_id3.stderr index e731f496652e..9f796cda6145 100644 --- a/tests/ui/consts/const_transmute_type_id3.stderr +++ b/tests/ui/consts/const_transmute_type_id3.stderr @@ -5,7 +5,11 @@ LL | assert!(a == b); | ^^^^^^ evaluation of `_` failed inside this call | note: inside `::eq` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL --> $SRC_DIR/core/src/any.rs:LL:COL + ::: $SRC_DIR/core/src/any.rs:LL:COL + | + = note: in this macro invocation 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) diff --git a/tests/ui/consts/const_transmute_type_id4.stderr b/tests/ui/consts/const_transmute_type_id4.stderr index b224227cf352..c844b10d78cf 100644 --- a/tests/ui/consts/const_transmute_type_id4.stderr +++ b/tests/ui/consts/const_transmute_type_id4.stderr @@ -5,7 +5,11 @@ LL | assert!(a == b); | ^^^^^^ evaluation of `_` failed inside this call | note: inside `::eq` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL --> $SRC_DIR/core/src/any.rs:LL:COL + ::: $SRC_DIR/core/src/any.rs:LL:COL + | + = note: in this macro invocation 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) diff --git a/tests/ui/consts/const_transmute_type_id5.stderr b/tests/ui/consts/const_transmute_type_id5.stderr index 6205679ebb64..9a7384eb95b4 100644 --- a/tests/ui/consts/const_transmute_type_id5.stderr +++ b/tests/ui/consts/const_transmute_type_id5.stderr @@ -5,7 +5,11 @@ LL | assert!(b == b); | ^^^^^^ evaluation of `_` failed inside this call | note: inside `::eq` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL --> $SRC_DIR/core/src/any.rs:LL:COL + ::: $SRC_DIR/core/src/any.rs:LL:COL + | + = note: in this macro invocation 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) diff --git a/tests/ui/consts/const_transmute_type_id6.stderr b/tests/ui/consts/const_transmute_type_id6.stderr index f5d90256e7c6..c0b35f3d1081 100644 --- a/tests/ui/consts/const_transmute_type_id6.stderr +++ b/tests/ui/consts/const_transmute_type_id6.stderr @@ -5,7 +5,11 @@ LL | id == id | ^^^^^^^^ evaluation of `X` failed inside this call | note: inside `::eq` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL --> $SRC_DIR/core/src/any.rs:LL:COL + ::: $SRC_DIR/core/src/any.rs:LL:COL + | + = note: in this macro invocation 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) diff --git a/tests/ui/consts/timeout.stderr b/tests/ui/consts/timeout.stderr index ecefeff76e96..6afb317c3aff 100644 --- a/tests/ui/consts/timeout.stderr +++ b/tests/ui/consts/timeout.stderr @@ -1,5 +1,10 @@ error: constant evaluation is taking a long time + --> $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + | --> $SRC_DIR/core/src/num/mod.rs:LL:COL + ::: $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: in this macro invocation | = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. If your compilation actually takes a long time, you can safely allow the lint. diff --git a/tests/ui/hygiene/cross-crate-name-hiding-2.stderr b/tests/ui/hygiene/cross-crate-name-hiding-2.stderr index fe3a12e93a7e..336d35099c80 100644 --- a/tests/ui/hygiene/cross-crate-name-hiding-2.stderr +++ b/tests/ui/hygiene/cross-crate-name-hiding-2.stderr @@ -4,10 +4,10 @@ error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope LL | let x = MyStruct {}; | ^^^^^^^^ not found in this scope | - ::: $DIR/auxiliary/use_by_macro.rs:15:1 + ::: $DIR/auxiliary/use_by_macro.rs:7:24 | -LL | x!(my_struct); - | ------------- you might have meant to refer to this struct +LL | pub struct MyStruct; + | -------- you might have meant to refer to this struct error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/equality.stderr b/tests/ui/impl-trait/equality.stderr index c2b889138c89..7f965b9609a9 100644 --- a/tests/ui/impl-trait/equality.stderr +++ b/tests/ui/impl-trait/equality.stderr @@ -33,13 +33,19 @@ LL | n + sum_to(n - 1) help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u32` implements `Add` + = note: `u32` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u32` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&u32` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `u32` implements `Add<&u32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `u32` implements `Add` + = note: `&u32` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr index c2e775e6c862..4a9a6c99819b 100644 --- a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr +++ b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr @@ -8,10 +8,13 @@ LL | glob_vs_expanded::mac!(); = note: for more information, see issue #114095 = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution note: `mac` could refer to the macro defined here - --> $DIR/auxiliary/glob-vs-expanded.rs:11:1 + --> $DIR/auxiliary/glob-vs-expanded.rs:9:13 | +LL | () => { pub macro mac() {} } + | ^^^^^^^^^^^^^ +LL | } LL | define_mac!(); - | ^^^^^^^^^^^^^ + | ------------- in this macro invocation note: `mac` could also refer to the macro defined here --> $DIR/auxiliary/glob-vs-expanded.rs:5:9 | @@ -33,10 +36,13 @@ LL | glob_vs_expanded::mac!(); = note: for more information, see issue #114095 = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution note: `mac` could refer to the macro defined here - --> $DIR/auxiliary/glob-vs-expanded.rs:11:1 + --> $DIR/auxiliary/glob-vs-expanded.rs:9:13 | +LL | () => { pub macro mac() {} } + | ^^^^^^^^^^^^^ +LL | } LL | define_mac!(); - | ^^^^^^^^^^^^^ + | ------------- in this macro invocation note: `mac` could also refer to the macro defined here --> $DIR/auxiliary/glob-vs-expanded.rs:5:9 | diff --git a/tests/ui/infinite/issue-41731-infinite-macro-print.stderr b/tests/ui/infinite/issue-41731-infinite-macro-print.stderr index 84436de9aa37..5f5d2c75525d 100644 --- a/tests/ui/infinite/issue-41731-infinite-macro-print.stderr +++ b/tests/ui/infinite/issue-41731-infinite-macro-print.stderr @@ -1,8 +1,11 @@ error: recursion limit reached while expanding `$crate::format_args!` - --> $DIR/issue-41731-infinite-macro-print.rs:14:5 + --> $DIR/issue-41731-infinite-macro-print.rs:8:13 | +LL | print!(stack!($overflow)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | stack!("overflow"); - | ^^^^^^^^^^^^^^^^^^ + | ------------------ in this macro invocation | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "10"]` attribute to your crate (`issue_41731_infinite_macro_print`) = note: this error originates in the macro `print` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -23,10 +26,13 @@ LL | stack!("overflow"); = note: to `{ $crate :: io :: _print($crate :: format_args! (stack! ("overflow"))); }` error: format argument must be a string literal - --> $DIR/issue-41731-infinite-macro-print.rs:14:5 + --> $DIR/issue-41731-infinite-macro-print.rs:8:13 | +LL | print!(stack!($overflow)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | stack!("overflow"); - | ^^^^^^^^^^^^^^^^^^ + | ------------------ in this macro invocation | = note: this error originates in the macro `print` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) help: you might be missing a string literal to format with diff --git a/tests/ui/infinite/issue-41731-infinite-macro-println.stderr b/tests/ui/infinite/issue-41731-infinite-macro-println.stderr index 6d0432abe4c5..c19039e305e2 100644 --- a/tests/ui/infinite/issue-41731-infinite-macro-println.stderr +++ b/tests/ui/infinite/issue-41731-infinite-macro-println.stderr @@ -1,8 +1,11 @@ error: recursion limit reached while expanding `$crate::format_args_nl!` - --> $DIR/issue-41731-infinite-macro-println.rs:14:5 + --> $DIR/issue-41731-infinite-macro-println.rs:8:13 | +LL | println!(stack!($overflow)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | stack!("overflow"); - | ^^^^^^^^^^^^^^^^^^ + | ------------------ in this macro invocation | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "10"]` attribute to your crate (`issue_41731_infinite_macro_println`) = note: this error originates in the macro `println` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -23,10 +26,13 @@ LL | stack!("overflow"); = note: to `{ $crate :: io :: _print($crate :: format_args_nl! (stack! ("overflow"))); }` error: format argument must be a string literal - --> $DIR/issue-41731-infinite-macro-println.rs:14:5 + --> $DIR/issue-41731-infinite-macro-println.rs:8:13 | +LL | println!(stack!($overflow)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | stack!("overflow"); - | ^^^^^^^^^^^^^^^^^^ + | ------------------ in this macro invocation | = note: this error originates in the macro `println` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) help: you might be missing a string literal to format with diff --git a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr index bef4cb6b0a1b..99bff6b450b5 100644 --- a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr @@ -35,10 +35,14 @@ LL | println!("{}", scores.sum::()); = help: the trait `Sum<()>` is not implemented for `i32` help: the following other types implement trait `Sum
` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:14:10 | @@ -72,10 +76,14 @@ LL | .sum::(), = help: the trait `Sum<()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:23:14 | @@ -109,10 +117,14 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); = help: the trait `Sum<()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:27:38 | diff --git a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr index 638287ed1c64..c94b716e3131 100644 --- a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr @@ -9,10 +9,14 @@ LL | let x = Some(()).iter().map(|()| 1).sum::(); = help: the trait `Sum<{integer}>` is not implemented for `f32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `f32` implements `Sum<&f32>` | = note: `f32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `f32` implements `Sum<&f32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-with-int-infer.rs:2:29 | diff --git a/tests/ui/iterators/invalid-iterator-chain.stderr b/tests/ui/iterators/invalid-iterator-chain.stderr index 0fd9d3999966..7f0c154e255a 100644 --- a/tests/ui/iterators/invalid-iterator-chain.stderr +++ b/tests/ui/iterators/invalid-iterator-chain.stderr @@ -35,10 +35,14 @@ LL | println!("{}", scores.sum::()); = help: the trait `Sum<()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:12:10 | @@ -71,10 +75,14 @@ LL | .sum::(), = help: the trait `Sum<()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:25:14 | @@ -114,10 +122,14 @@ LL | .sum::(), = help: the trait `Sum` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:33:14 | @@ -148,10 +160,14 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); = help: the trait `Sum<()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:38:38 | @@ -180,10 +196,14 @@ LL | println!("{}", vec![(), ()].iter().sum::()); = help: the trait `Sum<&()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:39:33 | diff --git a/tests/ui/mismatched_types/binops.stderr b/tests/ui/mismatched_types/binops.stderr index 504b44dfb7f6..ec2a951aac9a 100644 --- a/tests/ui/mismatched_types/binops.stderr +++ b/tests/ui/mismatched_types/binops.stderr @@ -26,13 +26,19 @@ LL | 2 as usize - Some(1); help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&usize` implements `Sub` + = note: `usize` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&usize` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&usize` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `usize` implements `Sub<&usize>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `usize` implements `Sub` + = note: `&usize` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot multiply `{integer}` by `()` diff --git a/tests/ui/mismatched_types/float-integer-subtraction-error-24352.stderr b/tests/ui/mismatched_types/float-integer-subtraction-error-24352.stderr index b2d0ffc4710e..54b536744f75 100644 --- a/tests/ui/mismatched_types/float-integer-subtraction-error-24352.stderr +++ b/tests/ui/mismatched_types/float-integer-subtraction-error-24352.stderr @@ -8,13 +8,19 @@ LL | 1.0f64 - 1 help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: `f64` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Sub<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Sub` + = note: `&f64` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | diff --git a/tests/ui/never_type/issue-13352.stderr b/tests/ui/never_type/issue-13352.stderr index 344625af683a..5fcbb4aab993 100644 --- a/tests/ui/never_type/issue-13352.stderr +++ b/tests/ui/never_type/issue-13352.stderr @@ -8,13 +8,19 @@ LL | 2_usize + (loop {}); help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&usize` implements `Add` + = note: `usize` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&usize` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&usize` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `usize` implements `Add<&usize>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `usize` implements `Add` + = note: `&usize` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr index 3f5297be3719..a62bf5b6a04d 100644 --- a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr @@ -8,13 +8,19 @@ LL | x + 100.0 help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u8` implements `Add` + = note: `u8` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u8` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&u8` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `u8` implements `Add<&u8>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `u8` implements `Add` + = note: `&u8` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot add `&str` to `f64` @@ -27,13 +33,19 @@ LL | x + "foo" help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Add` + = note: `f64` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Add<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Add` + = note: `&f64` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot add `{integer}` to `f64` @@ -46,13 +58,19 @@ LL | x + y help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Add` + = note: `f64` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Add<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Add` + = note: `&f64` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot subtract `{float}` from `u8` @@ -65,13 +83,19 @@ LL | x - 100.0 help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u8` implements `Sub` + = note: `u8` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u8` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&u8` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `u8` implements `Sub<&u8>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `u8` implements `Sub` + = note: `&u8` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot subtract `&str` from `f64` @@ -84,13 +108,19 @@ LL | x - "foo" help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: `f64` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Sub<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Sub` + = note: `&f64` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot subtract `{integer}` from `f64` @@ -103,13 +133,19 @@ LL | x - y help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: `f64` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Sub<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Sub` + = note: `&f64` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot multiply `u8` by `{float}` @@ -122,13 +158,19 @@ LL | x * 100.0 help: the following other types implement trait `Mul` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u8` implements `Mul` + = note: `u8` implements `Mul` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u8` implements `Mul` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&u8` implements `Mul` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `u8` implements `Mul<&u8>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `u8` implements `Mul` + = note: `&u8` implements `Mul` = note: this error originates in the macro `mul_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot multiply `f64` by `&str` @@ -141,13 +183,19 @@ LL | x * "foo" help: the following other types implement trait `Mul` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Mul` + = note: `f64` implements `Mul` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Mul` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Mul` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Mul<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Mul` + = note: `&f64` implements `Mul` = note: this error originates in the macro `mul_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot multiply `f64` by `{integer}` @@ -160,13 +208,19 @@ LL | x * y help: the following other types implement trait `Mul` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Mul` + = note: `f64` implements `Mul` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Mul` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Mul` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Mul<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Mul` + = note: `&f64` implements `Mul` = note: this error originates in the macro `mul_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot divide `u8` by `{float}` @@ -193,13 +247,19 @@ LL | x / "foo" help: the following other types implement trait `Div` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Div` + = note: `f64` implements `Div` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Div` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Div` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Div<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Div` + = note: `&f64` implements `Div` = note: this error originates in the macro `div_impl_float` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot divide `f64` by `{integer}` @@ -212,13 +272,19 @@ LL | x / y help: the following other types implement trait `Div` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Div` + = note: `f64` implements `Div` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Div` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Div` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Div<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Div` + = note: `&f64` implements `Div` = note: this error originates in the macro `div_impl_float` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 12 previous errors diff --git a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr index a31ed6154746..65881ca7a82f 100644 --- a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr @@ -8,13 +8,19 @@ LL | x + 100 help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Add` + = note: `f32` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f32` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f32` implements `Add<&f32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f32` implements `Add` + = note: `&f32` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -31,13 +37,19 @@ LL | x + 100 help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Add` + = note: `f64` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Add<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Add` + = note: `&f64` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -54,13 +66,19 @@ LL | x - 100 help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Sub` + = note: `f32` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f32` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f32` implements `Sub<&f32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f32` implements `Sub` + = note: `&f32` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -77,13 +95,19 @@ LL | x - 100 help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: `f64` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Sub<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Sub` + = note: `&f64` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -100,13 +124,19 @@ LL | x * 100 help: the following other types implement trait `Mul` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Mul` + = note: `f32` implements `Mul` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Mul` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f32` implements `Mul` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f32` implements `Mul<&f32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f32` implements `Mul` + = note: `&f32` implements `Mul` = note: this error originates in the macro `mul_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -123,13 +153,19 @@ LL | x * 100 help: the following other types implement trait `Mul` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Mul` + = note: `f64` implements `Mul` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Mul` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Mul` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Mul<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Mul` + = note: `&f64` implements `Mul` = note: this error originates in the macro `mul_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -146,13 +182,19 @@ LL | x / 100 help: the following other types implement trait `Div` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Div` + = note: `f32` implements `Div` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Div` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f32` implements `Div` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f32` implements `Div<&f32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f32` implements `Div` + = note: `&f32` implements `Div` = note: this error originates in the macro `div_impl_float` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -169,13 +211,19 @@ LL | x / 100 help: the following other types implement trait `Div` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Div` + = note: `f64` implements `Div` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Div` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Div` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Div<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Div` + = note: `&f64` implements `Div` = note: this error originates in the macro `div_impl_float` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | diff --git a/tests/ui/on-unimplemented/slice-index.stderr b/tests/ui/on-unimplemented/slice-index.stderr index baf821c45c5e..67b72bd038d8 100644 --- a/tests/ui/on-unimplemented/slice-index.stderr +++ b/tests/ui/on-unimplemented/slice-index.stderr @@ -28,6 +28,9 @@ help: the following other types implement trait `SliceIndex` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | = note: `RangeTo` implements `SliceIndex` + ::: $SRC_DIR/core/src/bstr/traits.rs:LL:COL + | + = note: in this macro invocation --> $SRC_DIR/core/src/str/traits.rs:LL:COL | = note: `RangeTo` implements `SliceIndex` diff --git a/tests/ui/on-unimplemented/sum.stderr b/tests/ui/on-unimplemented/sum.stderr index c4650e9f5278..5e82948352f7 100644 --- a/tests/ui/on-unimplemented/sum.stderr +++ b/tests/ui/on-unimplemented/sum.stderr @@ -9,10 +9,14 @@ LL | vec![(), ()].iter().sum::(); = help: the trait `Sum<&()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:4:18 | @@ -35,10 +39,14 @@ LL | vec![(), ()].iter().product::(); = help: the trait `Product<&()>` is not implemented for `i32` help: the following other types implement trait `Product` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Product<&i32>` | = note: `i32` implements `Product` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Product<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:7:18 | diff --git a/tests/ui/proc-macro/mixed-site-span.stderr b/tests/ui/proc-macro/mixed-site-span.stderr index 2cc7ff8a8867..fd941f65b788 100644 --- a/tests/ui/proc-macro/mixed-site-span.stderr +++ b/tests/ui/proc-macro/mixed-site-span.stderr @@ -112,10 +112,13 @@ LL | test!(); = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:69:5 + --> $DIR/mixed-site-span.rs:67:9 | +LL | invoke_with_ident!{$crate call proc_macro_item} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `proc_macro_item` in the root +LL | }} LL | test!(); - | ^^^^^^^ no `proc_macro_item` in the root + | ------- in this macro invocation | = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -262,10 +265,13 @@ LL + token_site_span::TokenItem as _ | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:110:5 + --> $DIR/mixed-site-span.rs:106:9 | +LL | invoke_with_ident!{$crate mixed TokenItem} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root +... LL | test!(); - | ^^^^^^^ no `TokenItem` in the root + | ------- in this macro invocation | = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this struct instead @@ -417,10 +423,13 @@ LL + ($m:ident $s:ident $i:ident) => { ItemUse as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:150:5 + --> $DIR/mixed-site-span.rs:145:9 | +LL | invoke_with_ident!{$crate mixed ItemUse} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root +... LL | test!(); - | ^^^^^^^ no `ItemUse` in the root + | ------- in this macro invocation | = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this struct instead @@ -447,10 +456,13 @@ LL + ItemUse as _ | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:150:5 + --> $DIR/mixed-site-span.rs:148:9 | +LL | invoke_with_ident!{$crate call ItemUse} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root +LL | }} LL | test!(); - | ^^^^^^^ no `ItemUse` in the root + | ------- in this macro invocation | = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this struct instead diff --git a/tests/ui/span/macro-span-caller-replacement.rs b/tests/ui/span/macro-span-caller-replacement.rs index 45af729beb1a..8e7239699cd1 100644 --- a/tests/ui/span/macro-span-caller-replacement.rs +++ b/tests/ui/span/macro-span-caller-replacement.rs @@ -2,7 +2,7 @@ macro_rules! macro_with_format { () => { fn check_5(arg : usize) -> String { let s : &str; if arg < 5 { - s = format!("{arg}"); + s = format!("{arg}"); //~ ERROR mismatched types } else { s = String::new(); //~ ERROR mismatched types } @@ -11,6 +11,6 @@ fn check_5(arg : usize) -> String { }} fn main() { - macro_with_format!(); //~ ERROR mismatched types - println!( "{}", check_5(6) ); + macro_with_format!(); + println!( "{}", check_5(6) ); } diff --git a/tests/ui/span/macro-span-caller-replacement.stderr b/tests/ui/span/macro-span-caller-replacement.stderr index 1c831f96ec0c..43be48a9e362 100644 --- a/tests/ui/span/macro-span-caller-replacement.stderr +++ b/tests/ui/span/macro-span-caller-replacement.stderr @@ -1,8 +1,11 @@ error[E0308]: mismatched types --> $DIR/macro-span-caller-replacement.rs:5:17 | +LL | s = format!("{arg}"); + | ^^^^^^^^^^^^^^^^ expected `&str`, found `String` +... LL | macro_with_format!(); - | ^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `String` + | -------------------- in this macro invocation | = note: this error originates in the macro `format` which comes from the expansion of the macro `macro_with_format` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/span/multiline-span-simple.stderr b/tests/ui/span/multiline-span-simple.stderr index af04ceaf8097..e013b3c06bc1 100644 --- a/tests/ui/span/multiline-span-simple.stderr +++ b/tests/ui/span/multiline-span-simple.stderr @@ -8,13 +8,19 @@ LL | foo(1 as u32 + help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u32` implements `Add` + = note: `u32` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u32` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&u32` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `u32` implements `Add<&u32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `u32` implements `Add` + = note: `&u32` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr index 6a8a7b152c54..93e189ffa0d3 100644 --- a/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr +++ b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr @@ -6,6 +6,9 @@ LL | core::sync::atomic::AtomicU64::from_mut(&mut 0u64); | note: if you're trying to build a new `AtomicU64`, consider using `AtomicU64::new` which returns `AtomicU64` --> $SRC_DIR/core/src/sync/atomic.rs:LL:COL + ::: $SRC_DIR/core/src/sync/atomic.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `atomic_int` (in Nightly builds, run with -Z macro-backtrace for more info) help: there is an associated function `from` with a similar name | diff --git a/tests/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr b/tests/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr index 46613e8e1b48..0ed657c7fa99 100644 --- a/tests/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr +++ b/tests/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr @@ -1,10 +1,13 @@ error[E0308]: mismatched types - --> $DIR/dont-suggest-deref-inside-macro-issue-58298.rs:11:5 + --> $DIR/dont-suggest-deref-inside-macro-issue-58298.rs:5:14 | +LL | warn(format!("unsupported intrinsic {}", $intrinsic)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `String` +... LL | / intrinsic_match! { LL | | "abc" LL | | }; - | |_____^ expected `&str`, found `String` + | |_____- in this macro invocation | = note: this error originates in the macro `format` which comes from the expansion of the macro `intrinsic_match` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr index 07a54d574df4..3bae5798d047 100644 --- a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr +++ b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr @@ -24,7 +24,11 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { | = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>` help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>` + --> $SRC_DIR/core/src/slice/iter/macros.rs:LL:COL --> $SRC_DIR/core/src/slice/iter.rs:LL:COL + ::: $SRC_DIR/core/src/slice/iter.rs:LL:COL + | + = note: in this macro invocation = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `Iterator` = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` = note: this error originates in the macro `iterator` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -55,7 +59,11 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone( | = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>` help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>` + --> $SRC_DIR/core/src/slice/iter/macros.rs:LL:COL --> $SRC_DIR/core/src/slice/iter.rs:LL:COL + ::: $SRC_DIR/core/src/slice/iter.rs:LL:COL + | + = note: in this macro invocation = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `Iterator` = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` = note: this error originates in the macro `iterator` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -68,7 +76,11 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { | = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>` help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>` + --> $SRC_DIR/core/src/slice/iter/macros.rs:LL:COL --> $SRC_DIR/core/src/slice/iter.rs:LL:COL + ::: $SRC_DIR/core/src/slice/iter.rs:LL:COL + | + = note: in this macro invocation = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` = note: this error originates in the macro `iterator` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -80,7 +92,11 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone( | = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>` help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>` + --> $SRC_DIR/core/src/slice/iter/macros.rs:LL:COL --> $SRC_DIR/core/src/slice/iter.rs:LL:COL + ::: $SRC_DIR/core/src/slice/iter.rs:LL:COL + | + = note: in this macro invocation = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` = note: this error originates in the macro `iterator` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index da5c4d03dccb..61fecaf89917 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -13,9 +13,15 @@ help: the following other types implement trait `From` --> $SRC_DIR/core/src/convert/num.rs:LL:COL | = note: `u8` implements `From` + ::: $SRC_DIR/core/src/convert/num.rs:LL:COL + | + = note: in this macro invocation --> $SRC_DIR/core/src/ascii/ascii_char.rs:LL:COL | = note: `u8` implements `From` + ::: $SRC_DIR/core/src/ascii/ascii_char.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `impl_from` which comes from the expansion of the macro `into_int_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` diff --git a/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr b/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr index 2855c90234d2..ca26e3dd03f3 100644 --- a/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr @@ -9,6 +9,9 @@ LL | 42_i32 help: the trait `PartialEq` is not implemented for `i32` but trait `PartialEq` is implemented for it --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/self-referential-3.stderr b/tests/ui/type-alias-impl-trait/self-referential-3.stderr index 83fed16c0a17..8592de243ada 100644 --- a/tests/ui/type-alias-impl-trait/self-referential-3.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential-3.stderr @@ -10,6 +10,9 @@ LL | i = help: the trait `PartialEq>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/self-referential-4.stderr b/tests/ui/type-alias-impl-trait/self-referential-4.stderr index 4176bf780294..c6bf1973fcbb 100644 --- a/tests/ui/type-alias-impl-trait/self-referential-4.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential-4.stderr @@ -9,6 +9,9 @@ LL | i = help: the trait `PartialEq>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `Foo<'static, 'b>` @@ -22,6 +25,9 @@ LL | i = help: the trait `PartialEq>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `Moo<'static, 'a>` @@ -35,6 +41,9 @@ LL | i = help: the trait `PartialEq>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/type-alias-impl-trait/self-referential.stderr b/tests/ui/type-alias-impl-trait/self-referential.stderr index dc5b9ba7b442..7b4e6e9cac52 100644 --- a/tests/ui/type-alias-impl-trait/self-referential.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential.stderr @@ -10,6 +10,9 @@ LL | i = help: the trait `PartialEq>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)` @@ -24,6 +27,9 @@ LL | (42, i) = help: the trait `PartialEq<(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)` @@ -38,6 +44,9 @@ LL | (42, i) = help: the trait `PartialEq<(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/type/type-check-defaults.stderr b/tests/ui/type/type-check-defaults.stderr index 4eab611244a6..a3a2ed5aa725 100644 --- a/tests/ui/type/type-check-defaults.stderr +++ b/tests/ui/type/type-check-defaults.stderr @@ -86,13 +86,19 @@ LL | trait ProjectionPred> where T::Item : Add {} help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Add` + = note: `i32` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i32` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i32` implements `Add<&i32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i32` implements `Add` + = note: `&i32` implements `Add` note: required by a bound in `ProjectionPred` --> $DIR/type-check-defaults.rs:24:66 | diff --git a/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr index e4834c0308bc..bc722cdd57a5 100644 --- a/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr +++ b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr @@ -13,10 +13,13 @@ LL | Err(format!("error: {x}").into()) | +++++++ error[E0308]: mismatched types - --> $DIR/issue-110017-format-into-help-deletes-macro.rs:23:10 + --> $DIR/issue-110017-format-into-help-deletes-macro.rs:17:10 | +LL | format!("error: {}", $x) + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `Box`, found `String` +... LL | Err(outer!(x)) - | ^^^^^^^^^ expected `Box`, found `String` + | --------- in this macro invocation | = note: expected struct `Box` found struct `String` @@ -27,10 +30,13 @@ LL | format!("error: {}", $x).into() | +++++++ error[E0308]: mismatched types - --> $DIR/issue-110017-format-into-help-deletes-macro.rs:41:2 + --> $DIR/issue-110017-format-into-help-deletes-macro.rs:35:18 | +LL | Err(format!("error: {x}")) + | ^^^^^^^^^^^^^^^^^^^^^ expected `Box`, found `String` +... LL | entire_fn_outer!(); - | ^^^^^^^^^^^^^^^^^^ expected `Box`, found `String` + | ------------------ in this macro invocation | = note: expected struct `Box` found struct `String` @@ -41,10 +47,13 @@ LL | Err(format!("error: {x}").into()) | +++++++ error[E0308]: mismatched types - --> $DIR/issue-110017-format-into-help-deletes-macro.rs:51:5 + --> $DIR/issue-110017-format-into-help-deletes-macro.rs:45:13 | +LL | Err(format!("error: {}", $x)) + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `Box`, found `String` +... LL | nontrivial!(x) - | ^^^^^^^^^^^^^^ expected `Box`, found `String` + | -------------- in this macro invocation | = note: expected struct `Box` found struct `String` diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr index 889d2c94d0cf..30d51420b7cb 100644 --- a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr +++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr @@ -27,13 +27,16 @@ LL | writeln!(w, "but not here")? | + error[E0308]: mismatched types - --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:40:9 + --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:31:9 | +LL | writeln!($w, "but not here") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Result<(), Error>` +... LL | / if true { LL | | writeln!(w, "`;?` here ->")?; LL | | } else { LL | | baz!(w) - | | ^^^^^^^ expected `()`, found `Result<(), Error>` + | | ------- in this macro invocation LL | | } | |_____- expected this to be `()` | diff --git a/tests/ui/typeck/issue-81293.stderr b/tests/ui/typeck/issue-81293.stderr index 8318d31f0946..604f3cca5486 100644 --- a/tests/ui/typeck/issue-81293.stderr +++ b/tests/ui/typeck/issue-81293.stderr @@ -23,13 +23,19 @@ LL | a = c + b * 5; help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&usize` implements `Add` + = note: `usize` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&usize` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&usize` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `usize` implements `Add<&usize>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `usize` implements `Add` + = note: `&usize` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr index 352638dd0118..dbbee54c185b 100644 --- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -8,13 +8,19 @@ LL | >::add(1, 2); help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Add` + = note: `i32` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i32` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i32` implements `Add<&i32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i32` implements `Add` + = note: `&i32` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types @@ -73,13 +79,19 @@ LL | >::add(1, 2); help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Add` + = note: `i32` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i32` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i32` implements `Add<&i32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i32` implements `Add` + = note: `&i32` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors From c27bcef6f8ca820f9b22a707149485388281a8a8 Mon Sep 17 00:00:00 2001 From: 21aslade Date: Wed, 3 Dec 2025 20:43:27 -0700 Subject: [PATCH 501/585] don't resolve main in lib crates --- compiler/rustc_resolve/src/lib.rs | 7 +++++++ tests/ui/entry-point/imported_main_conflict_lib.rs | 10 ++++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/ui/entry-point/imported_main_conflict_lib.rs diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8132bf577d88..0b4ec6956bd1 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -73,6 +73,7 @@ ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility, }; use rustc_query_system::ich::StableHashingContext; +use rustc_session::config::CrateType; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; @@ -2430,6 +2431,12 @@ fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option> { } fn resolve_main(&mut self) { + let any_exe = self.tcx.crate_types().contains(&CrateType::Executable); + // Don't try to resolve main unless it's an executable + if !any_exe { + return; + } + let module = self.graph_root; let ident = Ident::with_dummy_span(sym::main); let parent_scope = &ParentScope::module(module, self.arenas); diff --git a/tests/ui/entry-point/imported_main_conflict_lib.rs b/tests/ui/entry-point/imported_main_conflict_lib.rs new file mode 100644 index 000000000000..b50e37951ede --- /dev/null +++ b/tests/ui/entry-point/imported_main_conflict_lib.rs @@ -0,0 +1,10 @@ +// Tests that ambiguously glob importing main doesn't fail to compile in non-executable crates +// Regression test for #149412 +//@ check-pass +#![crate_type = "lib"] + +mod m1 { pub(crate) fn main() {} } +mod m2 { pub(crate) fn main() {} } + +use m1::*; +use m2::*; From 4e51a8dbc0dfe25791375fe94a395d7cb200ef8a Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Fri, 28 Nov 2025 11:47:27 +0000 Subject: [PATCH 502/585] tidy: Detect outdated workspaces in workspace list --- src/tools/tidy/src/deps.rs | 42 ++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 592ba9c5c794..5dbb7a4e71b0 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -1,6 +1,7 @@ //! Checks the licenses of third-party dependencies. use std::collections::{HashMap, HashSet}; +use std::fmt::{Display, Formatter}; use std::fs::{File, read_dir}; use std::io::Write; use std::path::Path; @@ -14,6 +15,25 @@ #[path = "../../../bootstrap/src/utils/proc_macro_deps.rs"] mod proc_macro_deps; +#[derive(Clone, Copy)] +struct ListLocation { + path: &'static str, + line: u32, +} + +impl Display for ListLocation { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:{}", self.path, self.line) + } +} + +/// Creates a [`ListLocation`] for the current location (with an additional offset to the actual list start); +macro_rules! location { + (+ $offset:literal) => { + ListLocation { path: file!(), line: line!() + $offset } + }; +} + /// These are licenses that are allowed for all crates, including the runtime, /// rustc, tools, etc. #[rustfmt::skip] @@ -87,6 +107,8 @@ pub(crate) struct WorkspaceInfo<'a> { pub(crate) submodules: &'a [&'a str], } +const WORKSPACE_LOCATION: ListLocation = location!(+4); + /// The workspaces to check for licensing and optionally permitted dependencies. // FIXME auto detect all cargo workspaces pub(crate) const WORKSPACES: &[WorkspaceInfo<'static>] = &[ @@ -242,19 +264,6 @@ pub(crate) struct WorkspaceInfo<'a> { const EXCEPTIONS_UEFI_QEMU_TEST: ExceptionList = &[]; -#[derive(Clone, Copy)] -struct ListLocation { - path: &'static str, - line: u32, -} - -/// Creates a [`ListLocation`] for the current location (with an additional offset to the actual list start); -macro_rules! location { - (+ $offset:literal) => { - ListLocation { path: file!(), line: line!() + $offset } - }; -} - const PERMITTED_RUSTC_DEPS_LOCATION: ListLocation = location!(+6); /// Crates rustc is allowed to depend on. Avoid adding to the list if possible. @@ -641,6 +650,13 @@ pub fn check(root: &Path, cargo: &Path, tidy_ctx: TidyCtx) { .other_options(vec!["--locked".to_owned()]); let metadata = t!(cmd.exec()); + // Check for packages which have been moved into a different workspace and not updated + let absolute_root = + if path == "." { root.to_path_buf() } else { t!(std::path::absolute(root.join(path))) }; + let absolute_root_real = t!(std::path::absolute(&metadata.workspace_root)); + if absolute_root_real != absolute_root { + check.error(format!("{path} is part of another workspace ({} != {}), remove from `WORKSPACES` ({WORKSPACE_LOCATION})", absolute_root.display(), absolute_root_real.display())); + } check_license_exceptions(&metadata, path, exceptions, &mut check); if let Some((crates, permitted_deps, location)) = crates_and_deps { let descr = crates.get(0).unwrap_or(&path); From c96ff2d42944a2df715115ddeaa6b260695dcca9 Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Wed, 10 Dec 2025 23:41:19 +0000 Subject: [PATCH 503/585] Remove uses of `cfg(any()/all())` --- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- library/core/src/primitive_docs.rs | 2 +- tests/ui/asm/naked-functions-inline.rs | 2 +- tests/ui/asm/naked-functions-inline.stderr | 6 +- .../unsafe/cfg-unsafe-attributes.rs | 2 +- .../unsafe/extraneous-unsafe-attributes.rs | 4 +- .../extraneous-unsafe-attributes.stderr | 4 +- .../ui/attributes/unsafe/unsafe-attributes.rs | 2 +- .../conditional-compilation-struct-11085.rs | 2 +- tests/ui/cfg/conditional-compile.rs | 2 +- ...nested-cfg-attr-conditional-compilation.rs | 6 +- ...ed-cfg-attr-conditional-compilation.stderr | 4 +- tests/ui/coherence/coherence-cow.rs | 2 +- .../cfg-attr-multi-false.rs | 2 +- .../cfg-attr-multi-true.rs | 2 +- .../conditional-compilation/cfg-attr-parse.rs | 22 +-- .../cfg-attr-parse.stderr | 90 ++++++------ ...-attr-unknown-attribute-macro-expansion.rs | 2 +- ...r-unknown-attribute-macro-expansion.stderr | 6 +- .../cfg-empty-any-all.rs | 12 ++ .../cfg-empty-any-all.stderr | 21 +++ .../conditional-compilation/cfg_attr_path.rs | 4 +- .../ui/conditional-compilation/issue-34028.rs | 2 +- .../module_with_cfg.rs | 2 +- .../ui/coroutine/static-closure-unexpanded.rs | 2 +- .../feature-gate-pin_ergonomics.rs | 2 +- .../feature-gates/feature-gate-super-let.rs | 2 +- .../feature-gate-unsafe-binders.rs | 2 +- .../feature-gate-unsafe_fields.rs | 6 +- .../feature-gate-where_clause_attrs.a.stderr | 132 +++++++++--------- .../feature-gate-where_clause_attrs.b.stderr | 132 +++++++++--------- .../feature-gate-where_clause_attrs.rs | 96 ++++++------- tests/ui/issues/issue-24434.rs | 2 +- tests/ui/lint/issue-97094.rs | 18 +-- tests/ui/lint/issue-97094.stderr | 36 ++--- tests/ui/macros/issue-34171.rs | 2 +- tests/ui/parser/attribute-on-empty.rs | 2 +- tests/ui/parser/attribute-on-empty.stderr | 2 +- tests/ui/parser/attribute-on-type.rs | 6 +- tests/ui/parser/attribute-on-type.stderr | 6 +- .../parser/attribute/attr-pat-struct-rest.rs | 2 +- .../attribute/attr-pat-struct-rest.stderr | 2 +- tests/ui/parser/cfg-keyword-lifetime.rs | 2 +- tests/ui/parser/issue-116781.rs | 2 +- tests/ui/parser/raw/raw-idents.rs | 2 +- .../ty-path-followed-by-single-colon.rs | 2 +- .../ui/proc-macro/ambiguous-builtin-attrs.rs | 2 +- .../proc-macro/ambiguous-builtin-attrs.stderr | 6 +- .../proc-macro/auxiliary/derive-attr-cfg.rs | 2 +- tests/ui/proc-macro/cfg-eval.rs | 8 +- tests/ui/proc-macro/cfg-eval.stderr | 4 +- tests/ui/proc-macro/cfg-eval.stdout | 44 +++--- tests/ui/proc-macro/derive-attr-cfg.rs | 2 +- tests/ui/proc-macro/derive-b.rs | 2 +- .../ui/proc-macro/derive-helper-configured.rs | 4 +- ...gest-import-without-clobbering-attrs.fixed | 2 +- ...suggest-import-without-clobbering-attrs.rs | 2 +- .../unsafe-attributes-fix.fixed | 2 +- .../unsafe-attributes-fix.rs | 2 +- .../unsafe-attributes-fix.stderr | 10 +- tests/ui/static/static-align.rs | 2 +- tests/ui/structs/struct-field-cfg.rs | 16 +-- tests/ui/structs/struct-field-cfg.stderr | 22 +-- tests/ui/test-attrs/issue-34932.rs | 2 +- .../ui/typeck/issue-86721-return-expr-ice.rs | 2 +- 65 files changed, 412 insertions(+), 389 deletions(-) create mode 100644 tests/ui/conditional-compilation/cfg-empty-any-all.rs create mode 100644 tests/ui/conditional-compilation/cfg-empty-any-all.stderr diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index a0bee4e18214..ac5b3c240785 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -167,7 +167,7 @@ pub(crate) fn compile_fn( context.clear(); context.func = codegened_func.func; - #[cfg(any())] // This is never true + #[cfg(false)] let _clif_guard = { use std::fmt::Write; diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 15ba72bccaa9..3a4e1e657a3d 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -591,7 +591,7 @@ impl () {} /// # pub unsafe fn malloc(_size: usize) -> *mut core::ffi::c_void { core::ptr::NonNull::dangling().as_ptr() } /// # pub unsafe fn free(_ptr: *mut core::ffi::c_void) {} /// # } -/// # #[cfg(any())] +/// # #[cfg(false)] /// #[allow(unused_extern_crates)] /// extern crate libc; /// diff --git a/tests/ui/asm/naked-functions-inline.rs b/tests/ui/asm/naked-functions-inline.rs index 93741f26275b..b6fddc88e19b 100644 --- a/tests/ui/asm/naked-functions-inline.rs +++ b/tests/ui/asm/naked-functions-inline.rs @@ -30,7 +30,7 @@ pub extern "C" fn inline_never() { } #[unsafe(naked)] -#[cfg_attr(all(), inline(never))] +#[cfg_attr(true, inline(never))] //~^ ERROR [E0736] pub extern "C" fn conditional_inline_never() { naked_asm!(""); diff --git a/tests/ui/asm/naked-functions-inline.stderr b/tests/ui/asm/naked-functions-inline.stderr index 91140a301edc..785ecf734b9d 100644 --- a/tests/ui/asm/naked-functions-inline.stderr +++ b/tests/ui/asm/naked-functions-inline.stderr @@ -23,12 +23,12 @@ LL | #[inline(never)] | ^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/naked-functions-inline.rs:33:19 + --> $DIR/naked-functions-inline.rs:33:18 | LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here -LL | #[cfg_attr(all(), inline(never))] - | ^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` +LL | #[cfg_attr(true, inline(never))] + | ^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error: aborting due to 4 previous errors diff --git a/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs b/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs index 6a9853b2f6fc..7d05e08b2623 100644 --- a/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs @@ -1,6 +1,6 @@ //@ build-pass -#[cfg_attr(all(), unsafe(no_mangle))] +#[cfg_attr(true, unsafe(no_mangle))] fn a() {} fn main() {} diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs index 19046c08ca8b..a034b7246a34 100644 --- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs @@ -1,9 +1,9 @@ //@ edition: 2024 -#[unsafe(cfg(any()))] //~ ERROR: is not an unsafe attribute +#[unsafe(cfg(false))] //~ ERROR: is not an unsafe attribute fn a() {} -#[unsafe(cfg_attr(any(), allow(dead_code)))] //~ ERROR: is not an unsafe attribute +#[unsafe(cfg_attr(false, allow(dead_code)))] //~ ERROR: is not an unsafe attribute fn b() {} #[unsafe(test)] //~ ERROR: is not an unsafe attribute diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr index b549a638d5ea..dec8c4d3542b 100644 --- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr @@ -1,7 +1,7 @@ error: `cfg` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:3:3 | -LL | #[unsafe(cfg(any()))] +LL | #[unsafe(cfg(false))] | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes @@ -9,7 +9,7 @@ LL | #[unsafe(cfg(any()))] error: `cfg_attr` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:6:3 | -LL | #[unsafe(cfg_attr(any(), allow(dead_code)))] +LL | #[unsafe(cfg_attr(false, allow(dead_code)))] | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes diff --git a/tests/ui/attributes/unsafe/unsafe-attributes.rs b/tests/ui/attributes/unsafe/unsafe-attributes.rs index 5c57767b3b96..c08b0ed995e5 100644 --- a/tests/ui/attributes/unsafe/unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/unsafe-attributes.rs @@ -6,7 +6,7 @@ fn a() {} #[unsafe(export_name = "foo")] fn b() {} -#[cfg_attr(any(), unsafe(no_mangle))] +#[cfg_attr(false, unsafe(no_mangle))] static VAR2: u32 = 1; fn main() {} diff --git a/tests/ui/cfg/conditional-compilation-struct-11085.rs b/tests/ui/cfg/conditional-compilation-struct-11085.rs index cd6dded54d30..8fdc88be37d2 100644 --- a/tests/ui/cfg/conditional-compilation-struct-11085.rs +++ b/tests/ui/cfg/conditional-compilation-struct-11085.rs @@ -11,7 +11,7 @@ struct Foo { } struct Foo2 { - #[cfg(all())] + #[cfg(true)] foo: isize, } diff --git a/tests/ui/cfg/conditional-compile.rs b/tests/ui/cfg/conditional-compile.rs index 0739e877bfd1..8761197891f5 100644 --- a/tests/ui/cfg/conditional-compile.rs +++ b/tests/ui/cfg/conditional-compile.rs @@ -151,5 +151,5 @@ trait Fooable { } } -#[cfg(any())] +#[cfg(false)] mod nonexistent_file; // Check that unconfigured non-inline modules are not loaded or parsed. diff --git a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs index c5d86a27d522..8e79ce8d1546 100644 --- a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs +++ b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs @@ -3,14 +3,14 @@ //! expansion works from outside to inside, eventually applying the innermost //! conditional compilation directive. //! -//! In this test, `cfg_attr(all(), cfg_attr(all(), cfg(false)))` should expand to: -//! 1. `cfg_attr(all(), cfg(false))` (outer cfg_attr applied) +//! In this test, `cfg_attr(true, cfg_attr(true, cfg(false)))` should expand to: +//! 1. `cfg_attr(true, cfg(false))` (outer cfg_attr applied) //! 2. `cfg(false)` (inner cfg_attr applied) //! 3. Function `f` is excluded from compilation //! //! Added in . -#[cfg_attr(all(), cfg_attr(all(), cfg(false)))] //~ NOTE the item is gated here +#[cfg_attr(true, cfg_attr(true, cfg(false)))] //~ NOTE the item is gated here fn f() {} //~ NOTE found an item that was configured out fn main() { diff --git a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr index 3f833bd558b8..e93a5433d979 100644 --- a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr +++ b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr @@ -7,8 +7,8 @@ LL | f() note: found an item that was configured out --> $DIR/nested-cfg-attr-conditional-compilation.rs:14:4 | -LL | #[cfg_attr(all(), cfg_attr(all(), cfg(false)))] - | ----- the item is gated here +LL | #[cfg_attr(true, cfg_attr(true, cfg(false)))] + | ----- the item is gated here LL | fn f() {} | ^ diff --git a/tests/ui/coherence/coherence-cow.rs b/tests/ui/coherence/coherence-cow.rs index af94964762a9..2fc33e3a3e8f 100644 --- a/tests/ui/coherence/coherence-cow.rs +++ b/tests/ui/coherence/coherence-cow.rs @@ -1,6 +1,6 @@ //@ revisions: re_a re_b re_c -#![cfg_attr(any(), re_a, re_b, re_c)] +#![cfg_attr(false, re_a, re_b, re_c)] //@ aux-build:coherence_lib.rs diff --git a/tests/ui/conditional-compilation/cfg-attr-multi-false.rs b/tests/ui/conditional-compilation/cfg-attr-multi-false.rs index cfb430ec5b23..871c1b81acd2 100644 --- a/tests/ui/conditional-compilation/cfg-attr-multi-false.rs +++ b/tests/ui/conditional-compilation/cfg-attr-multi-false.rs @@ -5,7 +5,7 @@ #![warn(unused_must_use)] -#[cfg_attr(any(), deprecated, must_use)] +#[cfg_attr(false, deprecated, must_use)] struct Struct {} impl Struct { diff --git a/tests/ui/conditional-compilation/cfg-attr-multi-true.rs b/tests/ui/conditional-compilation/cfg-attr-multi-true.rs index 424760c2e663..24950c8d4234 100644 --- a/tests/ui/conditional-compilation/cfg-attr-multi-true.rs +++ b/tests/ui/conditional-compilation/cfg-attr-multi-true.rs @@ -6,7 +6,7 @@ #![warn(unused_must_use)] -#[cfg_attr(all(), deprecated, must_use)] +#[cfg_attr(true, deprecated, must_use)] struct MustUseDeprecated {} impl MustUseDeprecated { //~ warning: use of deprecated diff --git a/tests/ui/conditional-compilation/cfg-attr-parse.rs b/tests/ui/conditional-compilation/cfg-attr-parse.rs index b8aaad2685ef..21df51264e2d 100644 --- a/tests/ui/conditional-compilation/cfg-attr-parse.rs +++ b/tests/ui/conditional-compilation/cfg-attr-parse.rs @@ -5,50 +5,50 @@ struct NoConfigurationPredicate; // Zero attributes, zero trailing comma (comma manatory here) -#[cfg_attr(all())] //~ error: expected `,`, found end of `cfg_attr` +#[cfg_attr(true)] //~ error: expected `,`, found end of `cfg_attr` struct A0C0; // Zero attributes, one trailing comma -#[cfg_attr(all(),)] +#[cfg_attr(true,)] //~^ WARN `#[cfg_attr]` does not expand to any attributes struct A0C1; // Zero attributes, two trailing commas -#[cfg_attr(all(),,)] //~ ERROR expected identifier +#[cfg_attr(true,,)] //~ ERROR expected identifier struct A0C2; // One attribute, no trailing comma -#[cfg_attr(all(), must_use)] // Ok +#[cfg_attr(true, must_use)] // Ok struct A1C0; // One attribute, one trailing comma -#[cfg_attr(all(), must_use,)] // Ok +#[cfg_attr(true, must_use,)] // Ok struct A1C1; // One attribute, two trailing commas -#[cfg_attr(all(), must_use,,)] //~ ERROR expected identifier +#[cfg_attr(true, must_use,,)] //~ ERROR expected identifier struct A1C2; // Two attributes, no trailing comma -#[cfg_attr(all(), must_use, deprecated)] // Ok +#[cfg_attr(true, must_use, deprecated)] // Ok struct A2C0; // Two attributes, one trailing comma -#[cfg_attr(all(), must_use, deprecated,)] // Ok +#[cfg_attr(true, must_use, deprecated,)] // Ok struct A2C1; // Two attributes, two trailing commas -#[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier +#[cfg_attr(true, must_use, deprecated,,)] //~ ERROR expected identifier struct A2C2; // Wrong delimiter `[` -#[cfg_attr[all(),,]] +#[cfg_attr[true,,]] //~^ ERROR wrong `cfg_attr` delimiters //~| ERROR expected identifier, found `,` struct BracketZero; // Wrong delimiter `{` -#[cfg_attr{all(),,}] +#[cfg_attr{true,,}] //~^ ERROR wrong `cfg_attr` delimiters //~| ERROR expected identifier, found `,` struct BraceZero; diff --git a/tests/ui/conditional-compilation/cfg-attr-parse.stderr b/tests/ui/conditional-compilation/cfg-attr-parse.stderr index 4d4769b05cda..8dbe8969fd1c 100644 --- a/tests/ui/conditional-compilation/cfg-attr-parse.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-parse.stderr @@ -10,45 +10,45 @@ LL | #[cfg_attr()] = note: for more information, visit error: expected `,`, found end of `cfg_attr` input - --> $DIR/cfg-attr-parse.rs:8:17 + --> $DIR/cfg-attr-parse.rs:8:16 | -LL | #[cfg_attr(all())] - | ----------------^- +LL | #[cfg_attr(true)] + | ---------------^- + | | | + | | expected `,` + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` + | + = note: for more information, visit + +error: expected identifier, found `,` + --> $DIR/cfg-attr-parse.rs:17:17 + | +LL | #[cfg_attr(true,,)] + | ----------------^-- | | | - | | expected `,` + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:17:18 + --> $DIR/cfg-attr-parse.rs:29:27 | -LL | #[cfg_attr(all(),,)] - | -----------------^-- - | | | - | | expected identifier +LL | #[cfg_attr(true, must_use,,)] + | --------------------------^-- + | | | + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:29:28 + --> $DIR/cfg-attr-parse.rs:41:39 | -LL | #[cfg_attr(all(), must_use,,)] - | ---------------------------^-- - | | | - | | expected identifier - | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` - | - = note: for more information, visit - -error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:41:40 - | -LL | #[cfg_attr(all(), must_use, deprecated,,)] - | ---------------------------------------^-- - | | | - | | expected identifier +LL | #[cfg_attr(true, must_use, deprecated,,)] + | --------------------------------------^-- + | | | + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit @@ -56,22 +56,22 @@ LL | #[cfg_attr(all(), must_use, deprecated,,)] error: wrong `cfg_attr` delimiters --> $DIR/cfg-attr-parse.rs:45:11 | -LL | #[cfg_attr[all(),,]] - | ^^^^^^^^^ +LL | #[cfg_attr[true,,]] + | ^^^^^^^^ | help: the delimiters should be `(` and `)` | -LL - #[cfg_attr[all(),,]] -LL + #[cfg_attr(all(),,)] +LL - #[cfg_attr[true,,]] +LL + #[cfg_attr(true,,)] | error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:45:18 + --> $DIR/cfg-attr-parse.rs:45:17 | -LL | #[cfg_attr[all(),,]] - | -----------------^-- - | | | - | | expected identifier +LL | #[cfg_attr[true,,]] + | ----------------^-- + | | | + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit @@ -79,22 +79,22 @@ LL | #[cfg_attr[all(),,]] error: wrong `cfg_attr` delimiters --> $DIR/cfg-attr-parse.rs:51:11 | -LL | #[cfg_attr{all(),,}] - | ^^^^^^^^^ +LL | #[cfg_attr{true,,}] + | ^^^^^^^^ | help: the delimiters should be `(` and `)` | -LL - #[cfg_attr{all(),,}] -LL + #[cfg_attr(all(),,)] +LL - #[cfg_attr{true,,}] +LL + #[cfg_attr(true,,)] | error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:51:18 + --> $DIR/cfg-attr-parse.rs:51:17 | -LL | #[cfg_attr{all(),,}] - | -----------------^-- - | | | - | | expected identifier +LL | #[cfg_attr{true,,}] + | ----------------^-- + | | | + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit @@ -102,8 +102,8 @@ LL | #[cfg_attr{all(),,}] warning: `#[cfg_attr]` does not expand to any attributes --> $DIR/cfg-attr-parse.rs:12:1 | -LL | #[cfg_attr(all(),)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true,)] + | ^^^^^^^^^^^^^^^^^^ | = note: requested on the command line with `-W unused-attributes` diff --git a/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs b/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs index 45b757e92830..0305be5d24e6 100644 --- a/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs +++ b/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs @@ -1,6 +1,6 @@ macro_rules! foo { () => { - #[cfg_attr(all(), unknown)] + #[cfg_attr(true, unknown)] //~^ ERROR cannot find attribute `unknown` in this scope fn foo() {} } diff --git a/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr b/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr index c91ad128d6e5..bdddbd68cdaf 100644 --- a/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr @@ -1,8 +1,8 @@ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:3:27 + --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:3:26 | -LL | #[cfg_attr(all(), unknown)] - | ^^^^^^^ +LL | #[cfg_attr(true, unknown)] + | ^^^^^^^ ... LL | foo!(); | ------ in this macro invocation diff --git a/tests/ui/conditional-compilation/cfg-empty-any-all.rs b/tests/ui/conditional-compilation/cfg-empty-any-all.rs new file mode 100644 index 000000000000..48ed4342235c --- /dev/null +++ b/tests/ui/conditional-compilation/cfg-empty-any-all.rs @@ -0,0 +1,12 @@ +//! Test the behaviour of `cfg(any())` and `cfg(all())` + +#[cfg(any())] // Equivalent to cfg(false) +struct Disabled; + +#[cfg(all())] // Equivalent to cfg(true) +struct Enabled; + +fn main() { + let _ = Disabled; //~ ERROR: cannot find value `Disabled` + let _ = Enabled; // ok +} diff --git a/tests/ui/conditional-compilation/cfg-empty-any-all.stderr b/tests/ui/conditional-compilation/cfg-empty-any-all.stderr new file mode 100644 index 000000000000..1674f2def23a --- /dev/null +++ b/tests/ui/conditional-compilation/cfg-empty-any-all.stderr @@ -0,0 +1,21 @@ +error[E0425]: cannot find value `Disabled` in this scope + --> $DIR/cfg-empty-any-all.rs:10:13 + | +LL | let _ = Disabled; + | ^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/cfg-empty-any-all.rs:4:8 + | +LL | #[cfg(any())] // Equivalent to cfg(false) + | -- the item is gated here +LL | struct Disabled; + | ^^^^^^^^ +help: consider importing this unit variant + | +LL + use std::backtrace::BacktraceStatus::Disabled; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/conditional-compilation/cfg_attr_path.rs b/tests/ui/conditional-compilation/cfg_attr_path.rs index 00e07761977a..f300e02932b7 100644 --- a/tests/ui/conditional-compilation/cfg_attr_path.rs +++ b/tests/ui/conditional-compilation/cfg_attr_path.rs @@ -3,8 +3,8 @@ #![deny(unused_attributes)] // c.f #35584 mod auxiliary { - #[cfg_attr(any(), path = "nonexistent_file.rs")] pub mod namespaced_enums; - #[cfg_attr(all(), path = "namespaced_enums.rs")] pub mod nonexistent_file; + #[cfg_attr(false, path = "nonexistent_file.rs")] pub mod namespaced_enums; + #[cfg_attr(true, path = "namespaced_enums.rs")] pub mod nonexistent_file; } fn main() { diff --git a/tests/ui/conditional-compilation/issue-34028.rs b/tests/ui/conditional-compilation/issue-34028.rs index 3ee43cb4b322..d6f3f7a9abce 100644 --- a/tests/ui/conditional-compilation/issue-34028.rs +++ b/tests/ui/conditional-compilation/issue-34028.rs @@ -1,7 +1,7 @@ //@ check-pass macro_rules! m { - () => { #[cfg(any())] fn f() {} } + () => { #[cfg(false)] fn f() {} } } trait T {} diff --git a/tests/ui/conditional-compilation/module_with_cfg.rs b/tests/ui/conditional-compilation/module_with_cfg.rs index a96f8a3e6e96..32486bdb43d6 100644 --- a/tests/ui/conditional-compilation/module_with_cfg.rs +++ b/tests/ui/conditional-compilation/module_with_cfg.rs @@ -1,3 +1,3 @@ //@ ignore-auxiliary (used by `./inner-cfg-non-inline-mod.rs`) -#![cfg_attr(all(), cfg(false))] +#![cfg_attr(true, cfg(false))] diff --git a/tests/ui/coroutine/static-closure-unexpanded.rs b/tests/ui/coroutine/static-closure-unexpanded.rs index 7cf24774deda..ac7c251c8348 100644 --- a/tests/ui/coroutine/static-closure-unexpanded.rs +++ b/tests/ui/coroutine/static-closure-unexpanded.rs @@ -1,7 +1,7 @@ // Tests that static closures are not stable in the parser grammar unless the // coroutine feature is enabled. -#[cfg(any())] +#[cfg(false)] fn foo() { let _ = static || {}; //~^ ERROR coroutine syntax is experimental diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs index 7f669d0b93e5..6cb4492c3754 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -58,7 +58,7 @@ fn patterns<'a>( ref pin const w: i32, //~ ERROR pinned reference syntax is experimental ) {} -#[cfg(any())] +#[cfg(false)] mod not_compiled { use std::pin::Pin; diff --git a/tests/ui/feature-gates/feature-gate-super-let.rs b/tests/ui/feature-gates/feature-gate-super-let.rs index 7be080039133..19da1c4aa39b 100644 --- a/tests/ui/feature-gates/feature-gate-super-let.rs +++ b/tests/ui/feature-gates/feature-gate-super-let.rs @@ -4,7 +4,7 @@ fn main() { } // Check that it also isn't accepted in cfg'd out code. -#[cfg(any())] +#[cfg(false)] fn a() { super let a = 1; //~^ ERROR `super let` is experimental diff --git a/tests/ui/feature-gates/feature-gate-unsafe-binders.rs b/tests/ui/feature-gates/feature-gate-unsafe-binders.rs index a2997ced4fa1..e1eda7def482 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe-binders.rs +++ b/tests/ui/feature-gates/feature-gate-unsafe-binders.rs @@ -1,4 +1,4 @@ -#[cfg(any())] +#[cfg(false)] fn test() { let x: unsafe<> (); //~^ ERROR unsafe binder types are experimental diff --git a/tests/ui/feature-gates/feature-gate-unsafe_fields.rs b/tests/ui/feature-gates/feature-gate-unsafe_fields.rs index 8f9b411df469..2b0bbaa08357 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe_fields.rs +++ b/tests/ui/feature-gates/feature-gate-unsafe_fields.rs @@ -4,7 +4,7 @@ #![cfg_attr(with_gate, feature(unsafe_fields))] //[with_gate]~ WARNING -#[cfg(any())] +#[cfg(false)] struct Foo { unsafe field: (), //[without_gate]~ ERROR } @@ -12,14 +12,14 @@ struct Foo { // This should not parse as an unsafe field definition. struct FooTuple(unsafe fn()); -#[cfg(any())] +#[cfg(false)] enum Bar { Variant { unsafe field: () }, //[without_gate]~ ERROR // This should not parse as an unsafe field definition. VariantTuple(unsafe fn()), } -#[cfg(any())] +#[cfg(false)] union Baz { unsafe field: (), //[without_gate]~ ERROR } diff --git a/tests/ui/feature-gates/feature-gate-where_clause_attrs.a.stderr b/tests/ui/feature-gates/feature-gate-where_clause_attrs.a.stderr index 6a8f01bbcce1..970763157d18 100644 --- a/tests/ui/feature-gates/feature-gate-where_clause_attrs.a.stderr +++ b/tests/ui/feature-gates/feature-gate-where_clause_attrs.a.stderr @@ -21,8 +21,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:35:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -31,7 +31,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:36:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -61,8 +61,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:39:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -71,7 +71,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:40:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -101,8 +101,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:46:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -111,7 +111,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:47:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -141,8 +141,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:50:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -151,7 +151,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:51:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -181,8 +181,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:57:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -191,7 +191,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:58:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -221,8 +221,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:61:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -231,7 +231,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:62:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -261,8 +261,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:69:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -271,7 +271,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:70:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -301,8 +301,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:73:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -311,7 +311,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:74:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -341,8 +341,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:79:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -351,7 +351,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:80:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -381,8 +381,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:83:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -391,7 +391,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:84:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -421,8 +421,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:90:9 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -431,7 +431,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:91:9 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -461,8 +461,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:94:9 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -471,7 +471,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:95:9 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -501,8 +501,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:103:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -511,7 +511,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:104:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -541,8 +541,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:107:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -551,7 +551,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:108:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -581,8 +581,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:117:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -591,7 +591,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:118:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -621,8 +621,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:121:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -631,7 +631,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:122:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -661,8 +661,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:132:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -671,7 +671,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:133:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -701,8 +701,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:136:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -711,7 +711,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:137:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -741,8 +741,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:145:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -751,7 +751,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:146:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -781,8 +781,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:149:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -791,7 +791,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:150:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -821,8 +821,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:155:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -831,7 +831,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:156:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -861,8 +861,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:159:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -871,7 +871,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:160:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information diff --git a/tests/ui/feature-gates/feature-gate-where_clause_attrs.b.stderr b/tests/ui/feature-gates/feature-gate-where_clause_attrs.b.stderr index 6a8f01bbcce1..970763157d18 100644 --- a/tests/ui/feature-gates/feature-gate-where_clause_attrs.b.stderr +++ b/tests/ui/feature-gates/feature-gate-where_clause_attrs.b.stderr @@ -21,8 +21,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:35:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -31,7 +31,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:36:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -61,8 +61,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:39:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -71,7 +71,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:40:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -101,8 +101,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:46:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -111,7 +111,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:47:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -141,8 +141,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:50:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -151,7 +151,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:51:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -181,8 +181,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:57:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -191,7 +191,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:58:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -221,8 +221,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:61:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -231,7 +231,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:62:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -261,8 +261,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:69:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -271,7 +271,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:70:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -301,8 +301,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:73:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -311,7 +311,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:74:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -341,8 +341,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:79:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -351,7 +351,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:80:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -381,8 +381,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:83:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -391,7 +391,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:84:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -421,8 +421,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:90:9 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -431,7 +431,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:91:9 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -461,8 +461,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:94:9 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -471,7 +471,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:95:9 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -501,8 +501,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:103:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -511,7 +511,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:104:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -541,8 +541,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:107:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -551,7 +551,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:108:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -581,8 +581,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:117:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -591,7 +591,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:118:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -621,8 +621,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:121:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -631,7 +631,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:122:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -661,8 +661,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:132:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -671,7 +671,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:133:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -701,8 +701,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:136:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -711,7 +711,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:137:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -741,8 +741,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:145:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -751,7 +751,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:146:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -781,8 +781,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:149:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -791,7 +791,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:150:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -821,8 +821,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:155:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -831,7 +831,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:156:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -861,8 +861,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:159:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -871,7 +871,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:160:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information diff --git a/tests/ui/feature-gates/feature-gate-where_clause_attrs.rs b/tests/ui/feature-gates/feature-gate-where_clause_attrs.rs index 09c734a52de0..b87a1d56ea06 100644 --- a/tests/ui/feature-gates/feature-gate-where_clause_attrs.rs +++ b/tests/ui/feature-gates/feature-gate-where_clause_attrs.rs @@ -15,16 +15,16 @@ trait TraitAA {} #[cfg_attr(b, cfg(b))] trait TraitBB {} -#[cfg(all())] +#[cfg(true)] trait TraitAll {} -#[cfg(any())] +#[cfg(false)] trait TraitAny {} -#[cfg_attr(all(), cfg(all()))] +#[cfg_attr(true, cfg(true))] trait TraitAllAll {} -#[cfg_attr(any(), cfg(any()))] +#[cfg_attr(false, cfg(false))] trait TraitAnyAny {} @@ -32,67 +32,67 @@ trait A where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { type B where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] U: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] U: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] U: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] U: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable fn foo(&self) where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] U: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] U: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] U: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] U: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable } impl A for T where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { type B = () where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] U: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] U: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] U: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] U: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable fn foo(&self) where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable {} } @@ -100,12 +100,12 @@ struct C where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { _t: PhantomData, } @@ -114,12 +114,12 @@ union D where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { _t: PhantomData, @@ -129,12 +129,12 @@ enum E where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { E(PhantomData), } @@ -142,21 +142,21 @@ enum E impl C where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { fn new() where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] U: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] U: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] U: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] U: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] U: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable {} } diff --git a/tests/ui/issues/issue-24434.rs b/tests/ui/issues/issue-24434.rs index 991084c27409..429bcf4a8d87 100644 --- a/tests/ui/issues/issue-24434.rs +++ b/tests/ui/issues/issue-24434.rs @@ -1,6 +1,6 @@ //@ check-pass -#![cfg_attr(all(), feature(rustc_attrs))] +#![cfg_attr(true, feature(rustc_attrs))] #![rustc_dummy] fn main() {} diff --git a/tests/ui/lint/issue-97094.rs b/tests/ui/lint/issue-97094.rs index 22525ca11ae0..737f2827b67a 100644 --- a/tests/ui/lint/issue-97094.rs +++ b/tests/ui/lint/issue-97094.rs @@ -2,19 +2,19 @@ // Ensure that unknown lints inside cfg-attr's are linted for -#![cfg_attr(all(), allow(nonex_lint_top_level))] +#![cfg_attr(true, allow(nonex_lint_top_level))] //~^ ERROR unknown lint -#![cfg_attr(all(), allow(bare_trait_object))] +#![cfg_attr(true, allow(bare_trait_object))] //~^ ERROR has been renamed -#[cfg_attr(all(), allow(nonex_lint_mod))] +#[cfg_attr(true, allow(nonex_lint_mod))] //~^ ERROR unknown lint mod baz { - #![cfg_attr(all(), allow(nonex_lint_mod_inner))] + #![cfg_attr(true, allow(nonex_lint_mod_inner))] //~^ ERROR unknown lint } -#[cfg_attr(all(), allow(nonex_lint_fn))] +#[cfg_attr(true, allow(nonex_lint_fn))] //~^ ERROR unknown lint pub fn main() {} @@ -25,24 +25,24 @@ macro_rules! bar { } bar!( - #[cfg_attr(all(), allow(nonex_lint_in_macro))] + #[cfg_attr(true, allow(nonex_lint_in_macro))] //~^ ERROR unknown lint pub fn _bar() {} ); // No warning for non-applying cfg -#[cfg_attr(any(), allow(nonex_lint_fn))] +#[cfg_attr(false, allow(nonex_lint_fn))] pub fn _foo() {} // Allowing unknown lints works if inside cfg_attr -#[cfg_attr(all(), allow(unknown_lints))] +#[cfg_attr(true, allow(unknown_lints))] mod bar_allowed { #[allow(nonex_lint_fn)] fn _foo() {} } // ... but not if the cfg_attr doesn't evaluate -#[cfg_attr(any(), allow(unknown_lints))] +#[cfg_attr(false, allow(unknown_lints))] mod bar_not_allowed { #[allow(nonex_lint_fn)] //~^ ERROR unknown lint diff --git a/tests/ui/lint/issue-97094.stderr b/tests/ui/lint/issue-97094.stderr index 1a0a3eaf2507..e12250aa7542 100644 --- a/tests/ui/lint/issue-97094.stderr +++ b/tests/ui/lint/issue-97094.stderr @@ -1,8 +1,8 @@ error: unknown lint: `nonex_lint_top_level` - --> $DIR/issue-97094.rs:5:26 + --> $DIR/issue-97094.rs:5:25 | -LL | #![cfg_attr(all(), allow(nonex_lint_top_level))] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![cfg_attr(true, allow(nonex_lint_top_level))] + | ^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/issue-97094.rs:1:9 @@ -12,36 +12,36 @@ LL | #![deny(warnings)] = note: `#[deny(unknown_lints)]` implied by `#[deny(warnings)]` error: lint `bare_trait_object` has been renamed to `bare_trait_objects` - --> $DIR/issue-97094.rs:7:26 + --> $DIR/issue-97094.rs:7:25 | -LL | #![cfg_attr(all(), allow(bare_trait_object))] - | ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects` +LL | #![cfg_attr(true, allow(bare_trait_object))] + | ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects` | = note: `#[deny(renamed_and_removed_lints)]` implied by `#[deny(warnings)]` error: unknown lint: `nonex_lint_mod` - --> $DIR/issue-97094.rs:10:25 + --> $DIR/issue-97094.rs:10:24 | -LL | #[cfg_attr(all(), allow(nonex_lint_mod))] - | ^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, allow(nonex_lint_mod))] + | ^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_mod_inner` - --> $DIR/issue-97094.rs:13:30 + --> $DIR/issue-97094.rs:13:29 | -LL | #![cfg_attr(all(), allow(nonex_lint_mod_inner))] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![cfg_attr(true, allow(nonex_lint_mod_inner))] + | ^^^^^^^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_fn` - --> $DIR/issue-97094.rs:17:25 + --> $DIR/issue-97094.rs:17:24 | -LL | #[cfg_attr(all(), allow(nonex_lint_fn))] - | ^^^^^^^^^^^^^ +LL | #[cfg_attr(true, allow(nonex_lint_fn))] + | ^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_in_macro` - --> $DIR/issue-97094.rs:28:29 + --> $DIR/issue-97094.rs:28:28 | -LL | #[cfg_attr(all(), allow(nonex_lint_in_macro))] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, allow(nonex_lint_in_macro))] + | ^^^^^^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_fn` --> $DIR/issue-97094.rs:47:13 diff --git a/tests/ui/macros/issue-34171.rs b/tests/ui/macros/issue-34171.rs index fbc2ea50097d..3f13341230fa 100644 --- a/tests/ui/macros/issue-34171.rs +++ b/tests/ui/macros/issue-34171.rs @@ -6,5 +6,5 @@ macro_rules! apply_null { } fn main() { - apply_null!(#[cfg(all())] fn f() {}); + apply_null!(#[cfg(true)] fn f() {}); } diff --git a/tests/ui/parser/attribute-on-empty.rs b/tests/ui/parser/attribute-on-empty.rs index 5932377f73ec..0177e6c1b59d 100644 --- a/tests/ui/parser/attribute-on-empty.rs +++ b/tests/ui/parser/attribute-on-empty.rs @@ -4,7 +4,7 @@ struct Baz(i32); fn main() { - let _: Baz<#[cfg(any())]> = todo!(); + let _: Baz<#[cfg(false)]> = todo!(); //~^ ERROR attributes cannot be applied here } diff --git a/tests/ui/parser/attribute-on-empty.stderr b/tests/ui/parser/attribute-on-empty.stderr index 7c4806c8704a..6bcbf1ceb8d1 100644 --- a/tests/ui/parser/attribute-on-empty.stderr +++ b/tests/ui/parser/attribute-on-empty.stderr @@ -1,7 +1,7 @@ error: attributes cannot be applied here --> $DIR/attribute-on-empty.rs:7:16 | -LL | let _: Baz<#[cfg(any())]> = todo!(); +LL | let _: Baz<#[cfg(false)]> = todo!(); | - ^^^^^^^^^^^^^ attributes are not allowed here | | | while parsing the type for `_` diff --git a/tests/ui/parser/attribute-on-type.rs b/tests/ui/parser/attribute-on-type.rs index 196d322bdf8f..b400bd1c173f 100644 --- a/tests/ui/parser/attribute-on-type.rs +++ b/tests/ui/parser/attribute-on-type.rs @@ -16,16 +16,16 @@ fn main() { let _: #[attr] &'static str = "123"; //~^ ERROR attributes cannot be applied to types - let _: Bar<#[cfg(any())] 'static> = Bar(&123); + let _: Bar<#[cfg(false)] 'static> = Bar(&123); //~^ ERROR attributes cannot be applied to generic arguments - let _: Baz<#[cfg(any())] 42> = Baz(42); + let _: Baz<#[cfg(false)] 42> = Baz(42); //~^ ERROR attributes cannot be applied to generic arguments let _: Foo<#[cfg(not(wrong))]String> = Foo(String::new()); //~^ ERROR attributes cannot be applied to generic arguments - let _: Bar<#[cfg(any())] 'static> = Bar(&456); + let _: Bar<#[cfg(false)] 'static> = Bar(&456); //~^ ERROR attributes cannot be applied to generic arguments let _generic: Box<#[attr] i32> = Box::new(1); diff --git a/tests/ui/parser/attribute-on-type.stderr b/tests/ui/parser/attribute-on-type.stderr index 603c7e2be51a..316620325c04 100644 --- a/tests/ui/parser/attribute-on-type.stderr +++ b/tests/ui/parser/attribute-on-type.stderr @@ -13,13 +13,13 @@ LL | let _: #[attr] &'static str = "123"; error: attributes cannot be applied to generic arguments --> $DIR/attribute-on-type.rs:19:16 | -LL | let _: Bar<#[cfg(any())] 'static> = Bar(&123); +LL | let _: Bar<#[cfg(false)] 'static> = Bar(&123); | ^^^^^^^^^^^^^ attributes are not allowed here error: attributes cannot be applied to generic arguments --> $DIR/attribute-on-type.rs:22:16 | -LL | let _: Baz<#[cfg(any())] 42> = Baz(42); +LL | let _: Baz<#[cfg(false)] 42> = Baz(42); | ^^^^^^^^^^^^^ attributes are not allowed here error: attributes cannot be applied to generic arguments @@ -31,7 +31,7 @@ LL | let _: Foo<#[cfg(not(wrong))]String> = Foo(String::new()); error: attributes cannot be applied to generic arguments --> $DIR/attribute-on-type.rs:28:16 | -LL | let _: Bar<#[cfg(any())] 'static> = Bar(&456); +LL | let _: Bar<#[cfg(false)] 'static> = Bar(&456); | ^^^^^^^^^^^^^ attributes are not allowed here error: attributes cannot be applied to generic arguments diff --git a/tests/ui/parser/attribute/attr-pat-struct-rest.rs b/tests/ui/parser/attribute/attr-pat-struct-rest.rs index b2bfcf82df8d..8f0e4cd827e0 100644 --- a/tests/ui/parser/attribute/attr-pat-struct-rest.rs +++ b/tests/ui/parser/attribute/attr-pat-struct-rest.rs @@ -3,6 +3,6 @@ struct S {} fn main() { - let S { #[cfg(any())] .. } = S {}; + let S { #[cfg(false)] .. } = S {}; //~^ ERROR expected identifier, found `..` } diff --git a/tests/ui/parser/attribute/attr-pat-struct-rest.stderr b/tests/ui/parser/attribute/attr-pat-struct-rest.stderr index f72c54973fce..94ad7d571101 100644 --- a/tests/ui/parser/attribute/attr-pat-struct-rest.stderr +++ b/tests/ui/parser/attribute/attr-pat-struct-rest.stderr @@ -1,7 +1,7 @@ error: expected identifier, found `..` --> $DIR/attr-pat-struct-rest.rs:6:27 | -LL | let S { #[cfg(any())] .. } = S {}; +LL | let S { #[cfg(false)] .. } = S {}; | - ^^ expected identifier | | | while parsing the fields for this pattern diff --git a/tests/ui/parser/cfg-keyword-lifetime.rs b/tests/ui/parser/cfg-keyword-lifetime.rs index a1588eddc074..c61b69175c88 100644 --- a/tests/ui/parser/cfg-keyword-lifetime.rs +++ b/tests/ui/parser/cfg-keyword-lifetime.rs @@ -1,6 +1,6 @@ // Disallow `'keyword` even in cfg'd code. -#[cfg(any())] +#[cfg(false)] fn hello() -> &'ref () {} //~^ ERROR lifetimes cannot use keyword names diff --git a/tests/ui/parser/issue-116781.rs b/tests/ui/parser/issue-116781.rs index 0e951d2eaa44..176350fe2eec 100644 --- a/tests/ui/parser/issue-116781.rs +++ b/tests/ui/parser/issue-116781.rs @@ -1,6 +1,6 @@ #[derive(Debug)] struct Foo { - #[cfg(all())] + #[cfg(true)] field: fn(($),), //~ ERROR expected pattern, found `$` //~^ ERROR expected pattern, found `$` } diff --git a/tests/ui/parser/raw/raw-idents.rs b/tests/ui/parser/raw/raw-idents.rs index 93015ee6c494..4e1e6b124c31 100644 --- a/tests/ui/parser/raw/raw-idents.rs +++ b/tests/ui/parser/raw/raw-idents.rs @@ -62,7 +62,7 @@ impl<$kw> Tr<$kw> for A<$kw> { impl<$kw> B<$kw> {} } mod extern_crate { - #[cfg(any())] + #[cfg(false)] extern crate $kw; } mod body { diff --git a/tests/ui/parser/ty-path-followed-by-single-colon.rs b/tests/ui/parser/ty-path-followed-by-single-colon.rs index a9082ea317a7..588fec3f2fc8 100644 --- a/tests/ui/parser/ty-path-followed-by-single-colon.rs +++ b/tests/ui/parser/ty-path-followed-by-single-colon.rs @@ -12,7 +12,7 @@ fn f() where path:to::somewhere {} // OK! fn g(_: impl Take) {} // OK! - #[cfg(any())] fn h() where a::path:to::nowhere {} // OK! + #[cfg(false)] fn h() where a::path:to::nowhere {} // OK! fn i(_: impl Take:to::somewhere>) {} // OK! diff --git a/tests/ui/proc-macro/ambiguous-builtin-attrs.rs b/tests/ui/proc-macro/ambiguous-builtin-attrs.rs index 63d3c79055ca..e36a12beb818 100644 --- a/tests/ui/proc-macro/ambiguous-builtin-attrs.rs +++ b/tests/ui/proc-macro/ambiguous-builtin-attrs.rs @@ -9,7 +9,7 @@ #[repr(C)] //~ ERROR `repr` is ambiguous struct S; -#[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous +#[cfg_attr(true, repr(C))] //~ ERROR `repr` is ambiguous struct SCond; #[test] // OK, shadowed diff --git a/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr b/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr index ff7894a41eab..d05701986260 100644 --- a/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr +++ b/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr @@ -20,10 +20,10 @@ LL | use builtin_attrs::*; = help: use `crate::repr` to refer to this attribute macro unambiguously error[E0659]: `repr` is ambiguous - --> $DIR/ambiguous-builtin-attrs.rs:12:19 + --> $DIR/ambiguous-builtin-attrs.rs:12:18 | -LL | #[cfg_attr(all(), repr(C))] - | ^^^^ ambiguous name +LL | #[cfg_attr(true, repr(C))] + | ^^^^ ambiguous name | = note: ambiguous because of a name conflict with a builtin attribute = note: `repr` could refer to a built-in attribute diff --git a/tests/ui/proc-macro/auxiliary/derive-attr-cfg.rs b/tests/ui/proc-macro/auxiliary/derive-attr-cfg.rs index cb60c182a43c..b1da93de2a6e 100644 --- a/tests/ui/proc-macro/auxiliary/derive-attr-cfg.rs +++ b/tests/ui/proc-macro/auxiliary/derive-attr-cfg.rs @@ -4,6 +4,6 @@ #[proc_macro_derive(Foo, attributes(foo))] pub fn derive(input: TokenStream) -> TokenStream { - assert!(!input.to_string().contains("#[cfg(any())]")); + assert!(!input.to_string().contains("#[cfg(false)]")); "".parse().unwrap() } diff --git a/tests/ui/proc-macro/cfg-eval.rs b/tests/ui/proc-macro/cfg-eval.rs index 9e9e46912588..60c94ad2a752 100644 --- a/tests/ui/proc-macro/cfg-eval.rs +++ b/tests/ui/proc-macro/cfg-eval.rs @@ -17,9 +17,9 @@ struct S1 { #[cfg(false)] field_false: u8, - #[cfg(all(/*true*/))] + #[cfg(true)] #[cfg_attr(FALSE, unknown_attr)] - #[cfg_attr(all(/*true*/), allow())] //~ WARN unused attribute + #[cfg_attr(true, allow())] //~ WARN unused attribute field_true: u8, } @@ -29,9 +29,9 @@ struct S2 {} fn main() { // Subtle - we need a trailing comma after the '1' - otherwise, `#[cfg_eval]` will - // turn this into `(#[cfg(all())] 1)`, which is a parenthesized expression, not a tuple + // turn this into `(#[cfg(true)] 1)`, which is a parenthesized expression, not a tuple // expression. `#[cfg]` is not supported inside parenthesized expressions, so this will // produce an error when attribute collection runs. let _ = #[cfg_eval] #[print_attr] #[cfg_attr(not(FALSE), rustc_dummy)] - (#[cfg(false)] 0, #[cfg(all(/*true*/))] 1,); + (#[cfg(false)] 0, #[cfg(true)] 1,); } diff --git a/tests/ui/proc-macro/cfg-eval.stderr b/tests/ui/proc-macro/cfg-eval.stderr index 1429dbde7bfc..72c452c7a08a 100644 --- a/tests/ui/proc-macro/cfg-eval.stderr +++ b/tests/ui/proc-macro/cfg-eval.stderr @@ -1,8 +1,8 @@ warning: unused attribute --> $DIR/cfg-eval.rs:22:5 | -LL | #[cfg_attr(all(/*true*/), allow())] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute +LL | #[cfg_attr(true, allow())] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | = note: attribute `allow` with an empty list has no effect = note: requested on the command line with `-W unused-attributes` diff --git a/tests/ui/proc-macro/cfg-eval.stdout b/tests/ui/proc-macro/cfg-eval.stdout index 5d88297ad688..6493eee46547 100644 --- a/tests/ui/proc-macro/cfg-eval.stdout +++ b/tests/ui/proc-macro/cfg-eval.stdout @@ -1,5 +1,5 @@ -PRINT-ATTR INPUT (DISPLAY): struct S1 { #[cfg(all())] #[allow()] field_true: u8, } -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): struct S1 { #[cfg(all())] #[allow()] field_true : u8, } +PRINT-ATTR INPUT (DISPLAY): struct S1 { #[cfg(true)] #[allow()] field_true: u8, } +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): struct S1 { #[cfg(true)] #[allow()] field_true : u8, } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -28,19 +28,14 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "all", - span: $DIR/cfg-eval.rs:20:11: 20:14 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [], - span: $DIR/cfg-eval.rs:20:14: 20:24 (#0), + ident: "true", + span: $DIR/cfg-eval.rs:20:11: 20:15 (#0), }, ], - span: $DIR/cfg-eval.rs:20:10: 20:25 (#0), + span: $DIR/cfg-eval.rs:20:10: 20:16 (#0), }, ], - span: $DIR/cfg-eval.rs:20:6: 20:26 (#0), + span: $DIR/cfg-eval.rs:20:6: 20:17 (#0), }, Punct { ch: '#', @@ -52,15 +47,15 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "allow", - span: $DIR/cfg-eval.rs:22:31: 22:36 (#0), + span: $DIR/cfg-eval.rs:22:22: 22:27 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/cfg-eval.rs:22:36: 22:38 (#0), + span: $DIR/cfg-eval.rs:22:27: 22:29 (#0), }, ], - span: $DIR/cfg-eval.rs:22:6: 22:40 (#0), + span: $DIR/cfg-eval.rs:22:6: 22:31 (#0), }, Ident { ident: "field_true", @@ -84,7 +79,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: $DIR/cfg-eval.rs:17:11: 24:2 (#0), }, ] -PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] (#[cfg(all())] 1,) +PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] (#[cfg(true)] 1,) PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', @@ -120,32 +115,27 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "all", - span: $DIR/cfg-eval.rs:36:29: 36:32 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [], - span: $DIR/cfg-eval.rs:36:32: 36:42 (#0), + ident: "true", + span: $DIR/cfg-eval.rs:36:29: 36:33 (#0), }, ], - span: $DIR/cfg-eval.rs:36:28: 36:43 (#0), + span: $DIR/cfg-eval.rs:36:28: 36:34 (#0), }, ], - span: $DIR/cfg-eval.rs:36:24: 36:44 (#0), + span: $DIR/cfg-eval.rs:36:24: 36:35 (#0), }, Literal { kind: Integer, symbol: "1", suffix: None, - span: $DIR/cfg-eval.rs:36:45: 36:46 (#0), + span: $DIR/cfg-eval.rs:36:36: 36:37 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/cfg-eval.rs:36:46: 36:47 (#0), + span: $DIR/cfg-eval.rs:36:37: 36:38 (#0), }, ], - span: $DIR/cfg-eval.rs:36:5: 36:48 (#0), + span: $DIR/cfg-eval.rs:36:5: 36:39 (#0), }, ] diff --git a/tests/ui/proc-macro/derive-attr-cfg.rs b/tests/ui/proc-macro/derive-attr-cfg.rs index 2f3516cabae9..21d3a93ffa6c 100644 --- a/tests/ui/proc-macro/derive-attr-cfg.rs +++ b/tests/ui/proc-macro/derive-attr-cfg.rs @@ -9,7 +9,7 @@ #[derive(Foo)] #[foo] struct S { - #[cfg(any())] + #[cfg(false)] x: i32 } diff --git a/tests/ui/proc-macro/derive-b.rs b/tests/ui/proc-macro/derive-b.rs index 68d341478f18..c04152f629ca 100644 --- a/tests/ui/proc-macro/derive-b.rs +++ b/tests/ui/proc-macro/derive-b.rs @@ -4,7 +4,7 @@ extern crate derive_b_rpass as derive_b; #[derive(Debug, PartialEq, derive_b::B, Eq, Copy, Clone)] -#[cfg_attr(all(), B[arbitrary tokens])] +#[cfg_attr(true, B[arbitrary tokens])] struct B { #[C] a: u64 diff --git a/tests/ui/proc-macro/derive-helper-configured.rs b/tests/ui/proc-macro/derive-helper-configured.rs index b753e29b8bf3..b96ebdebaebb 100644 --- a/tests/ui/proc-macro/derive-helper-configured.rs +++ b/tests/ui/proc-macro/derive-helper-configured.rs @@ -7,9 +7,9 @@ extern crate test_macros; #[derive(Empty)] -#[cfg_attr(all(), empty_helper)] +#[cfg_attr(true, empty_helper)] struct S { - #[cfg_attr(all(), empty_helper)] + #[cfg_attr(true, empty_helper)] field: u8, } diff --git a/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.fixed b/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.fixed index cfbf9ef38684..f6fbff175a99 100644 --- a/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.fixed +++ b/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.fixed @@ -3,7 +3,7 @@ //@ compile-flags: -Aunused use y::z; -#[cfg(all())] +#[cfg(true)] use y::Whatever; mod y { diff --git a/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.rs b/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.rs index 98be104d8fde..73f263e19aa4 100644 --- a/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.rs +++ b/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.rs @@ -2,7 +2,7 @@ //@ run-rustfix //@ compile-flags: -Aunused -#[cfg(all())] +#[cfg(true)] use y::Whatever; mod y { diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed index a2f04daa4b85..c1adc90161a4 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed @@ -43,7 +43,7 @@ macro_rules! meta2 { macro_rules! with_cfg_attr { () => { - #[cfg_attr(all(), unsafe(link_section = ".custom_section"))] + #[cfg_attr(true, unsafe(link_section = ".custom_section"))] //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition pub extern "C" fn abc() {} diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs index 88c9328fd9cd..9fdf37904634 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs @@ -43,7 +43,7 @@ extern "C" fn baw() {} macro_rules! with_cfg_attr { () => { - #[cfg_attr(all(), link_section = ".custom_section")] + #[cfg_attr(true, link_section = ".custom_section")] //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition pub extern "C" fn abc() {} diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr index 55df60c51d9c..279e61a9cb67 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr @@ -77,10 +77,10 @@ LL | #[unsafe($e = $l)] | +++++++ + error: unsafe attribute used without unsafe - --> $DIR/unsafe-attributes-fix.rs:46:27 + --> $DIR/unsafe-attributes-fix.rs:46:26 | -LL | #[cfg_attr(all(), link_section = ".custom_section")] - | ^^^^^^^^^^^^ usage of unsafe attribute +LL | #[cfg_attr(true, link_section = ".custom_section")] + | ^^^^^^^^^^^^ usage of unsafe attribute ... LL | with_cfg_attr!(); | ---------------- in this macro invocation @@ -90,8 +90,8 @@ LL | with_cfg_attr!(); = note: this error originates in the macro `with_cfg_attr` (in Nightly builds, run with -Z macro-backtrace for more info) help: wrap the attribute in `unsafe(...)` | -LL | #[cfg_attr(all(), unsafe(link_section = ".custom_section"))] - | +++++++ + +LL | #[cfg_attr(true, unsafe(link_section = ".custom_section"))] + | +++++++ + error: unsafe attribute used without unsafe --> $DIR/unsafe-attributes-fix.rs:67:3 diff --git a/tests/ui/static/static-align.rs b/tests/ui/static/static-align.rs index e2db7c01adf2..c1c9f79996ed 100644 --- a/tests/ui/static/static-align.rs +++ b/tests/ui/static/static-align.rs @@ -53,7 +53,7 @@ fn drop(&mut self) { #[allow(unused_mut, reason = "test attribute handling")] #[cfg_attr(TRUE, cfg_attr(FOURTY_TWO = "42", - cfg_attr(all(), + cfg_attr(true, cfg_attr(any(true), cfg_attr(true, rustc_align_static(4096))))))] #[allow(unused_mut, reason = "test attribute handling")] diff --git a/tests/ui/structs/struct-field-cfg.rs b/tests/ui/structs/struct-field-cfg.rs index 42cab8ab916b..84f913927dab 100644 --- a/tests/ui/structs/struct-field-cfg.rs +++ b/tests/ui/structs/struct-field-cfg.rs @@ -3,16 +3,16 @@ struct Foo { } fn main() { - let foo = Foo { #[cfg(all())] present: () }; - let _ = Foo { #[cfg(any())] present: () }; + let foo = Foo { #[cfg(true)] present: () }; + let _ = Foo { #[cfg(false)] present: () }; //~^ ERROR missing field `present` in initializer of `Foo` - let _ = Foo { present: (), #[cfg(any())] absent: () }; - let _ = Foo { present: (), #[cfg(all())] absent: () }; + let _ = Foo { present: (), #[cfg(false)] absent: () }; + let _ = Foo { present: (), #[cfg(true)] absent: () }; //~^ ERROR struct `Foo` has no field named `absent` - let Foo { #[cfg(all())] present: () } = foo; - let Foo { #[cfg(any())] present: () } = foo; + let Foo { #[cfg(true)] present: () } = foo; + let Foo { #[cfg(false)] present: () } = foo; //~^ ERROR pattern does not mention field `present` - let Foo { present: (), #[cfg(any())] absent: () } = foo; - let Foo { present: (), #[cfg(all())] absent: () } = foo; + let Foo { present: (), #[cfg(false)] absent: () } = foo; + let Foo { present: (), #[cfg(true)] absent: () } = foo; //~^ ERROR struct `Foo` does not have a field named `absent` } diff --git a/tests/ui/structs/struct-field-cfg.stderr b/tests/ui/structs/struct-field-cfg.stderr index 2bca6f302db7..db280a632d63 100644 --- a/tests/ui/structs/struct-field-cfg.stderr +++ b/tests/ui/structs/struct-field-cfg.stderr @@ -1,44 +1,44 @@ error[E0063]: missing field `present` in initializer of `Foo` --> $DIR/struct-field-cfg.rs:7:13 | -LL | let _ = Foo { #[cfg(any())] present: () }; +LL | let _ = Foo { #[cfg(false)] present: () }; | ^^^ missing `present` error[E0560]: struct `Foo` has no field named `absent` - --> $DIR/struct-field-cfg.rs:10:46 + --> $DIR/struct-field-cfg.rs:10:45 | -LL | let _ = Foo { present: (), #[cfg(all())] absent: () }; - | ^^^^^^ `Foo` does not have this field +LL | let _ = Foo { present: (), #[cfg(true)] absent: () }; + | ^^^^^^ `Foo` does not have this field | = note: all struct fields are already assigned error[E0027]: pattern does not mention field `present` --> $DIR/struct-field-cfg.rs:13:9 | -LL | let Foo { #[cfg(any())] present: () } = foo; +LL | let Foo { #[cfg(false)] present: () } = foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `present` | help: include the missing field in the pattern | -LL - let Foo { #[cfg(any())] present: () } = foo; +LL - let Foo { #[cfg(false)] present: () } = foo; LL + let Foo { present } = foo; | help: if you don't care about this missing field, you can explicitly ignore it | -LL - let Foo { #[cfg(any())] present: () } = foo; +LL - let Foo { #[cfg(false)] present: () } = foo; LL + let Foo { present: _ } = foo; | help: or always ignore missing fields here | -LL - let Foo { #[cfg(any())] present: () } = foo; +LL - let Foo { #[cfg(false)] present: () } = foo; LL + let Foo { .. } = foo; | error[E0026]: struct `Foo` does not have a field named `absent` - --> $DIR/struct-field-cfg.rs:16:42 + --> $DIR/struct-field-cfg.rs:16:41 | -LL | let Foo { present: (), #[cfg(all())] absent: () } = foo; - | ^^^^^^ struct `Foo` does not have this field +LL | let Foo { present: (), #[cfg(true)] absent: () } = foo; + | ^^^^^^ struct `Foo` does not have this field error: aborting due to 4 previous errors diff --git a/tests/ui/test-attrs/issue-34932.rs b/tests/ui/test-attrs/issue-34932.rs index feb6556b60a1..f0cbdd07df84 100644 --- a/tests/ui/test-attrs/issue-34932.rs +++ b/tests/ui/test-attrs/issue-34932.rs @@ -1,6 +1,6 @@ //@ run-pass //@ compile-flags:--test -#![cfg(any())] // This test should be configured away +#![cfg(false)] // This test should be configured away #![feature(rustc_attrs)] // Test that this is allowed on stable/beta #![feature(iter_arith_traits)] // Test that this is not unused #![deny(unused_features)] diff --git a/tests/ui/typeck/issue-86721-return-expr-ice.rs b/tests/ui/typeck/issue-86721-return-expr-ice.rs index ea3a2f2fbfe6..ed36164aea60 100644 --- a/tests/ui/typeck/issue-86721-return-expr-ice.rs +++ b/tests/ui/typeck/issue-86721-return-expr-ice.rs @@ -1,7 +1,7 @@ // Regression test for the ICE described in #86721. //@ revisions: rev1 rev2 -#![cfg_attr(any(), rev1, rev2)] +#![cfg_attr(false, rev1, rev2)] #![crate_type = "lib"] #[cfg(any(rev1))] From 51806323f9288e9cdab756a6b528823bcadcaa7a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 11 Dec 2025 01:35:28 +0100 Subject: [PATCH 504/585] Do not error if there are duplicated doc attributes --- compiler/rustc_attr_parsing/src/attributes/doc.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 2fe1b4ad174c..547f00d14041 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -358,10 +358,14 @@ macro_rules! no_args { return; } - if self.attribute.$ident.is_some() { - cx.duplicate_key(path.span(), path.word_sym().unwrap()); - return; - } + // FIXME: It's errorring when the attribute is passed multiple times on the command + // line. + // The right fix for this would be to only check this rule if the attribute is + // not set on the command line but directly in the code. + // if self.attribute.$ident.is_some() { + // cx.duplicate_key(path.span(), path.word_sym().unwrap()); + // return; + // } self.attribute.$ident = Some(path.span()); }}; From 1b790cdcac1d0f156f312b59b318ae42eb84797c Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Thu, 11 Dec 2025 16:46:32 +0700 Subject: [PATCH 505/585] Weak for Arc pointer is marked as DynSend/DynSync --- compiler/rustc_data_structures/src/marker.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 0ef3bb319ff8..72d5f004194a 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -75,6 +75,7 @@ macro_rules! impl_dyn_send { [std::sync::Mutex where T: ?Sized+ DynSend] [std::sync::mpsc::Sender where T: DynSend] [std::sync::Arc where T: ?Sized + DynSync + DynSend] + [std::sync::Weak where T: ?Sized + DynSync + DynSend] [std::sync::LazyLock where T: DynSend, F: DynSend] [std::collections::HashSet where K: DynSend, S: DynSend] [std::collections::HashMap where K: DynSend, V: DynSend, S: DynSend] @@ -157,6 +158,7 @@ macro_rules! impl_dyn_sync { [std::sync::OnceLock where T: DynSend + DynSync] [std::sync::Mutex where T: ?Sized + DynSend] [std::sync::Arc where T: ?Sized + DynSync + DynSend] + [std::sync::Weak where T: ?Sized + DynSync + DynSend] [std::sync::LazyLock where T: DynSend + DynSync, F: DynSend] [std::collections::HashSet where K: DynSync, S: DynSync] [std::collections::HashMap where K: DynSync, V: DynSync, S: DynSync] From b01a2fb652a382b20f9243403297b32569450d6c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 27 Nov 2025 13:58:24 +0000 Subject: [PATCH 506/585] Add a test for not resolving ambiguity for multiple --extern with same name --- .../foo-v1.rs | 1 + .../foo-v2.rs | 1 + .../main.rs | 10 ++++ .../main.stderr | 12 +++++ .../rmake.rs | 54 +++++++++++++++++++ .../use-foo.rs | 1 + 6 files changed, 79 insertions(+) create mode 100644 tests/run-make/duplicate-dependency-no-disambiguate/foo-v1.rs create mode 100644 tests/run-make/duplicate-dependency-no-disambiguate/foo-v2.rs create mode 100644 tests/run-make/duplicate-dependency-no-disambiguate/main.rs create mode 100644 tests/run-make/duplicate-dependency-no-disambiguate/main.stderr create mode 100644 tests/run-make/duplicate-dependency-no-disambiguate/rmake.rs create mode 100644 tests/run-make/duplicate-dependency-no-disambiguate/use-foo.rs diff --git a/tests/run-make/duplicate-dependency-no-disambiguate/foo-v1.rs b/tests/run-make/duplicate-dependency-no-disambiguate/foo-v1.rs new file mode 100644 index 000000000000..4a835673a596 --- /dev/null +++ b/tests/run-make/duplicate-dependency-no-disambiguate/foo-v1.rs @@ -0,0 +1 @@ +pub struct Foo; diff --git a/tests/run-make/duplicate-dependency-no-disambiguate/foo-v2.rs b/tests/run-make/duplicate-dependency-no-disambiguate/foo-v2.rs new file mode 100644 index 000000000000..4a835673a596 --- /dev/null +++ b/tests/run-make/duplicate-dependency-no-disambiguate/foo-v2.rs @@ -0,0 +1 @@ +pub struct Foo; diff --git a/tests/run-make/duplicate-dependency-no-disambiguate/main.rs b/tests/run-make/duplicate-dependency-no-disambiguate/main.rs new file mode 100644 index 000000000000..eae6b8b4527d --- /dev/null +++ b/tests/run-make/duplicate-dependency-no-disambiguate/main.rs @@ -0,0 +1,10 @@ +#![feature(custom_inner_attributes)] +#![rustfmt::skip] // use_foo must be referenced before foo + +// Load foo-v2 through use-foo +use use_foo as _; + +// Make sure we don't disambiguate this as foo-v2. +use foo as _; + +fn main() {} diff --git a/tests/run-make/duplicate-dependency-no-disambiguate/main.stderr b/tests/run-make/duplicate-dependency-no-disambiguate/main.stderr new file mode 100644 index 000000000000..23caa2caaef6 --- /dev/null +++ b/tests/run-make/duplicate-dependency-no-disambiguate/main.stderr @@ -0,0 +1,12 @@ +error[E0464]: multiple candidates for `rlib` dependency `foo` found + --> main.rs:8:5 + | +LL | use foo as _; + | ^^^ + | + = note: candidate #1: /build-root/test/run-make/duplicate-dependency-no-disambiguate/rmake_out/libfoo-v1.rlib + = note: candidate #2: /build-root/test/run-make/duplicate-dependency-no-disambiguate/rmake_out/libfoo-v2.rlib + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0464`. diff --git a/tests/run-make/duplicate-dependency-no-disambiguate/rmake.rs b/tests/run-make/duplicate-dependency-no-disambiguate/rmake.rs new file mode 100644 index 000000000000..7dd6f3840dfa --- /dev/null +++ b/tests/run-make/duplicate-dependency-no-disambiguate/rmake.rs @@ -0,0 +1,54 @@ +//@ needs-target-std + +use run_make_support::{Rustc, cwd, diff, regex, rust_lib_name, rustc}; + +fn rustc_with_common_args() -> Rustc { + let mut rustc = rustc(); + rustc.remap_path_prefix(cwd(), "$DIR"); + rustc.edition("2018"); // Don't require `extern crate` + rustc +} + +fn main() { + rustc_with_common_args() + .input("foo-v1.rs") + .crate_type("rlib") + .crate_name("foo") + .extra_filename("-v1") + .metadata("-v1") + .run(); + + rustc_with_common_args() + .input("foo-v2.rs") + .crate_type("rlib") + .crate_name("foo") + .extra_filename("-v2") + .metadata("-v2") + .run(); + + rustc_with_common_args() + .input("use-foo.rs") + .crate_type("rlib") + .extern_("foo", rust_lib_name("foo-v2")) + .run(); + + let stderr = rustc_with_common_args() + .input("main.rs") + .extern_("foo", rust_lib_name("foo-v1")) + .extern_("foo", rust_lib_name("foo-v2")) + .extern_("use_foo", rust_lib_name("use_foo")) + .library_search_path(cwd()) + .ui_testing() + .run_fail() + .stderr_utf8(); + + diff() + .expected_file("main.stderr") + .normalize( + regex::escape(run_make_support::build_root().canonicalize().unwrap().to_str().unwrap()), + "/build-root", + ) + .normalize(r"\\", "/") + .actual_text("(rustc)", &stderr) + .run(); +} diff --git a/tests/run-make/duplicate-dependency-no-disambiguate/use-foo.rs b/tests/run-make/duplicate-dependency-no-disambiguate/use-foo.rs new file mode 100644 index 000000000000..15c1d27f1b95 --- /dev/null +++ b/tests/run-make/duplicate-dependency-no-disambiguate/use-foo.rs @@ -0,0 +1 @@ +use foo as _; From 8fec0f495e44db4f2b3b23807f2247e238480c72 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 27 Nov 2025 13:58:49 +0000 Subject: [PATCH 507/585] Only check for already loaded indirect dependencies in existing_match For direct dependencies it is a lot harder to not accidentally resolve an ambiguity through an indirect dependency edge and as it turns out this check was actually more expensive than the work it skipped. For indirect dependencies existing_match is still necessary due to an assert in load, but at the same time it also can't accidentally resolve an ambiguity given that we already know exactly which crate to look for based on the crate hash. --- compiler/rustc_metadata/src/creader.rs | 51 ++++---------------------- 1 file changed, 8 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 250aa0769024..4400f9f68180 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -514,55 +514,20 @@ pub fn new(metadata_loader: Box) -> CStore { } } - fn existing_match( - &self, - externs: &Externs, - name: Symbol, - hash: Option, - ) -> Option { + fn existing_match(&self, name: Symbol, hash: Option) -> Option { + let hash = hash?; + for (cnum, data) in self.iter_crate_data() { if data.name() != name { trace!("{} did not match {}", data.name(), name); continue; } - match hash { - Some(hash) if hash == data.hash() => return Some(cnum), - Some(hash) => { - debug!("actual hash {} did not match expected {}", hash, data.hash()); - continue; - } - None => {} + if hash == data.hash() { + return Some(cnum); + } else { + debug!("actual hash {} did not match expected {}", hash, data.hash()); } - - // When the hash is None we're dealing with a top-level dependency - // in which case we may have a specification on the command line for - // this library. Even though an upstream library may have loaded - // something of the same name, we have to make sure it was loaded - // from the exact same location as well. - // - // We're also sure to compare *paths*, not actual byte slices. The - // `source` stores paths which are normalized which may be different - // from the strings on the command line. - let source = data.source(); - if let Some(entry) = externs.get(name.as_str()) { - // Only use `--extern crate_name=path` here, not `--extern crate_name`. - if let Some(mut files) = entry.files() { - if files.any(|l| { - let l = l.canonicalized(); - source.dylib.as_ref() == Some(l) - || source.rlib.as_ref() == Some(l) - || source.rmeta.as_ref() == Some(l) - }) { - return Some(cnum); - } - } - continue; - } - - // While the crate name matched, no --extern crate_name=path matched. It is possible - // that we have already loaded the target crate, but if that happens CStore::load will - // indicate so and we gracefully handle this, just potentially wasting a bit of time. } None @@ -799,7 +764,7 @@ fn maybe_resolve_crate<'b, 'tcx>( let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate }; let private_dep = origin.private_dep(); - let result = if let Some(cnum) = self.existing_match(&tcx.sess.opts.externs, name, hash) { + let result = if let Some(cnum) = self.existing_match(name, hash) { (LoadResult::Previous(cnum), None) } else { info!("falling back to a load"); From 7f1828c5926e67cec899d73ebe1af64a610d49c2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 25 Nov 2025 11:26:09 +0000 Subject: [PATCH 508/585] Avoid multiple copies of proc macros ending up in the sysroot --- src/bootstrap/src/core/build_steps/compile.rs | 57 +++++++++++++++++-- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 01b757bae246..7ef170c5e8e1 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -7,7 +7,7 @@ //! goes along from the output of the previous stage. use std::borrow::Cow; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::ffi::OsStr; use std::io::BufReader; use std::io::prelude::*; @@ -1558,7 +1558,7 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.never() } - /// Same as `std_link`, only for librustc + /// Same as `StdLink`, only for librustc fn run(self, builder: &Builder<'_>) { let build_compiler = self.build_compiler; let sysroot_compiler = self.sysroot_compiler; @@ -2418,13 +2418,52 @@ pub fn add_to_sysroot( t!(fs::create_dir_all(sysroot_dst)); t!(fs::create_dir_all(sysroot_host_dst)); t!(fs::create_dir_all(self_contained_dst)); + + let mut crates = HashMap::new(); for (path, dependency_type) in builder.read_stamp_file(stamp) { + let filename = path.file_name().unwrap().to_str().unwrap(); let dst = match dependency_type { - DependencyType::Host => sysroot_host_dst, - DependencyType::Target => sysroot_dst, + DependencyType::Host => { + if sysroot_dst == sysroot_host_dst { + // Only insert the part before the . to deduplicate different files for the same crate. + // For example foo-1234.dll and foo-1234.dll.lib. + crates.insert(filename.split_once('.').unwrap().0.to_owned(), path.clone()); + } + + sysroot_host_dst + } + DependencyType::Target => { + // Only insert the part before the . to deduplicate different files for the same crate. + // For example foo-1234.dll and foo-1234.dll.lib. + crates.insert(filename.split_once('.').unwrap().0.to_owned(), path.clone()); + + sysroot_dst + } DependencyType::TargetSelfContained => self_contained_dst, }; - builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::Regular); + builder.copy_link(&path, &dst.join(filename), FileType::Regular); + } + + // Check that none of the rustc_* crates have multiple versions. Otherwise using them from + // the sysroot would cause ambiguity errors. We do allow rustc_hash however as it is an + // external dependency that we build multiple copies of. It is re-exported by + // rustc_data_structures, so not being able to use extern crate rustc_hash; is not a big + // issue. + let mut seen_crates = HashMap::new(); + for (filestem, path) in crates { + if !filestem.contains("rustc_") || filestem.contains("rustc_hash") { + continue; + } + if let Some(other_path) = + seen_crates.insert(filestem.split_once('-').unwrap().0.to_owned(), path.clone()) + { + panic!( + "duplicate rustc crate {}\n- first copy at {}\n- second copy at {}", + filestem.split_once('-').unwrap().0.to_owned(), + other_path.display(), + path.display(), + ); + } } } @@ -2511,7 +2550,13 @@ pub fn run_cargo( if filename.starts_with(&host_root_dir) { // Unless it's a proc macro used in the compiler if crate_types.iter().any(|t| t == "proc-macro") { - deps.push((filename.to_path_buf(), DependencyType::Host)); + // Cargo will compile proc-macros that are part of the rustc workspace twice. + // Once as libmacro-hash.so as build dependency and once as libmacro.so as + // output artifact. Only keep the former to avoid ambiguity when trying to use + // the proc macro from the sysroot. + if filename.file_name().unwrap().to_str().unwrap().contains("-") { + deps.push((filename.to_path_buf(), DependencyType::Host)); + } } continue; } From 3d3b96e3ec120d5074fb2ef9fa8b8506e524f8f3 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 5 Oct 2025 17:28:56 +0800 Subject: [PATCH 509/585] rust-analyzer: prep crates for testing against in-tree `rustc_private` --- src/tools/rust-analyzer/crates/base-db/Cargo.toml | 4 ++++ src/tools/rust-analyzer/crates/base-db/src/lib.rs | 5 +++++ src/tools/rust-analyzer/crates/cfg/Cargo.toml | 4 ++++ src/tools/rust-analyzer/crates/cfg/src/lib.rs | 5 +++++ .../rust-analyzer/crates/ide-completion/Cargo.toml | 4 ++++ .../rust-analyzer/crates/ide-completion/src/lib.rs | 5 +++++ src/tools/rust-analyzer/crates/ide-db/Cargo.toml | 4 ++++ src/tools/rust-analyzer/crates/ide-db/src/lib.rs | 5 +++++ .../rust-analyzer/crates/ide-diagnostics/Cargo.toml | 4 ++++ .../rust-analyzer/crates/ide-diagnostics/src/lib.rs | 5 +++++ src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml | 4 ++++ src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs | 5 +++++ src/tools/rust-analyzer/crates/load-cargo/src/lib.rs | 6 ++++++ src/tools/rust-analyzer/crates/parser/src/lib.rs | 2 ++ .../rust-analyzer/crates/proc-macro-api/Cargo.toml | 2 ++ .../rust-analyzer/crates/proc-macro-api/src/lib.rs | 5 +++++ .../rust-analyzer/crates/project-model/Cargo.toml | 4 ++++ .../rust-analyzer/crates/project-model/src/lib.rs | 5 +++++ .../rust-analyzer/crates/rust-analyzer/Cargo.toml | 10 +++++++--- .../rust-analyzer/crates/rust-analyzer/src/lib.rs | 5 +++++ .../crates/rust-analyzer/tests/slow-tests/main.rs | 4 ++++ src/tools/rust-analyzer/crates/span/Cargo.toml | 1 + src/tools/rust-analyzer/crates/span/src/lib.rs | 6 ++++++ .../rust-analyzer/crates/syntax-bridge/src/lib.rs | 5 +++++ src/tools/rust-analyzer/crates/syntax/Cargo.toml | 1 + src/tools/rust-analyzer/crates/syntax/src/lib.rs | 5 +++++ src/tools/rust-analyzer/crates/test-fixture/Cargo.toml | 4 ++++ src/tools/rust-analyzer/crates/test-fixture/src/lib.rs | 6 ++++++ src/tools/rust-analyzer/crates/tt/Cargo.toml | 1 + src/tools/rust-analyzer/crates/tt/src/lib.rs | 3 +++ 30 files changed, 126 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index ea06fd9c48fc..55dfcbc7e508 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -31,5 +31,9 @@ vfs.workspace = true span.workspace = true intern.workspace = true +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 97938924100b..b6e346521187 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -1,5 +1,10 @@ //! base_db defines basic database traits. The concrete DB is defined by ide. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + pub use salsa; pub use salsa_macros; diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml index 9e2a95dbf32c..7207cfcf7dba 100644 --- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml +++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml @@ -33,5 +33,9 @@ syntax.workspace = true # tt is needed for testing cfg = { path = ".", default-features = false, features = ["tt"] } +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs index b1ec4c273a85..3e3d67cb4aaf 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs @@ -1,5 +1,10 @@ //! cfg defines conditional compiling options, `cfg` attribute parser and evaluator +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + mod cfg_expr; mod dnf; #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml index 277d5dfa495c..6abc009241cf 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml @@ -37,5 +37,9 @@ expect-test = "1.5.1" test-utils.workspace = true test-fixture.workspace = true +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index 31e33db104c7..c9d5971cd0e3 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -3,6 +3,11 @@ // It's useful to refer to code that is private in doc comments. #![allow(rustdoc::private_intra_doc_links)] +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + mod completions; mod config; mod context; diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml index f1f9d85cf964..fca06b69d1bb 100644 --- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml @@ -52,5 +52,9 @@ line-index.workspace = true [dev-dependencies] expect-test = "1.5.1" +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 0301b5020862..338c42325457 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -2,6 +2,11 @@ //! //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + extern crate self as ide_db; mod apply_change; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml index 6f1e66948f42..ddf5999036d2 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml @@ -34,5 +34,9 @@ expect-test = "1.5.1" test-utils.workspace = true test-fixture.workspace = true +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index fe04bd175c96..e001f4b3e438 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -23,6 +23,11 @@ //! There are also a couple of ad-hoc diagnostics implemented directly here, we //! don't yet have a great pattern for how to do them properly. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + mod handlers { pub(crate) mod await_outside_of_async; pub(crate) mod bad_rtn; diff --git a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml index 0620bd26fefd..1900b069e00f 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml @@ -30,5 +30,9 @@ triomphe.workspace = true test-utils.workspace = true test-fixture.workspace = true +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs index 977dfb7466e4..958a26324fff 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs @@ -63,6 +63,11 @@ // // foo($a, $b) ==>> ($a).foo($b) // ``` +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + mod fragments; mod from_comment; mod matching; diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index a486219efa20..28fbfecfde80 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -2,6 +2,12 @@ //! for incorporating changes. // Note, don't remove any public api from this. This API is consumed by external tools // to run rust-analyzer as a library. + +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + use std::{any::Any, collections::hash_map::Entry, mem, path::Path, sync}; use crossbeam_channel::{Receiver, unbounded}; diff --git a/src/tools/rust-analyzer/crates/parser/src/lib.rs b/src/tools/rust-analyzer/crates/parser/src/lib.rs index b15bf0cd0105..81cdc188012c 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lib.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lib.rs @@ -25,6 +25,8 @@ extern crate ra_ap_rustc_lexer as rustc_lexer; #[cfg(feature = "in-rust-tree")] extern crate rustc_lexer; +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; mod event; mod frontmatter; diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml index 18a2408c4035..4de1a3e5dd7d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml @@ -34,6 +34,8 @@ semver.workspace = true [features] sysroot-abi = ["proc-macro-srv", "proc-macro-srv/sysroot-abi"] +default = [] +in-rust-tree = [] [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs index f0c7ce7efd1c..8e1faca00a1b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs @@ -12,6 +12,11 @@ )] #![allow(internal_features)] +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + mod codec; mod framing; pub mod legacy_protocol; diff --git a/src/tools/rust-analyzer/crates/project-model/Cargo.toml b/src/tools/rust-analyzer/crates/project-model/Cargo.toml index 7e0b1f75f72c..f825a456dea7 100644 --- a/src/tools/rust-analyzer/crates/project-model/Cargo.toml +++ b/src/tools/rust-analyzer/crates/project-model/Cargo.toml @@ -39,5 +39,9 @@ toolchain.workspace = true [dev-dependencies] expect-test = "1.5.1" +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs index 8eee3d1455c1..0d89e13ed374 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs @@ -18,6 +18,11 @@ // It's useful to refer to code that is private in doc comments. #![allow(rustdoc::private_intra_doc_links)] +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + pub mod project_json; pub mod toolchain_info { pub mod rustc_cfg; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index 2e48c5a5a66c..d1283ca59e8c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -98,12 +98,16 @@ syntax-bridge.workspace = true jemalloc = ["jemallocator", "profile/jemalloc"] force-always-assert = ["stdx/force-always-assert"] in-rust-tree = [ - "syntax/in-rust-tree", - "parser/in-rust-tree", - "hir/in-rust-tree", + "cfg/in-rust-tree", "hir-def/in-rust-tree", "hir-ty/in-rust-tree", + "hir/in-rust-tree", + "ide-ssr/in-rust-tree", + "ide/in-rust-tree", "load-cargo/in-rust-tree", + "parser/in-rust-tree", + "proc-macro-api/in-rust-tree", + "syntax/in-rust-tree", ] dhat = ["dep:dhat"] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs index 3dea21e56485..a6cd43139229 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs @@ -9,6 +9,11 @@ //! The `cli` submodule implements some batch-processing analysis, primarily as //! a debugging aid. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + extern crate ra_ap_rustc_type_ir as rustc_type_ir; /// Any toolchain less than this version will likely not work with rust-analyzer built from this revision. diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index 5a4ad6f380f9..48433342d51d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -9,6 +9,10 @@ //! be sure without a real client anyway. #![allow(clippy::disallowed_types)] +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; mod cli; mod ratoml; diff --git a/src/tools/rust-analyzer/crates/span/Cargo.toml b/src/tools/rust-analyzer/crates/span/Cargo.toml index 966962bab381..cfb319d688b6 100644 --- a/src/tools/rust-analyzer/crates/span/Cargo.toml +++ b/src/tools/rust-analyzer/crates/span/Cargo.toml @@ -27,6 +27,7 @@ syntax.workspace = true [features] default = ["salsa"] +in-rust-tree = [] [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/span/src/lib.rs b/src/tools/rust-analyzer/crates/span/src/lib.rs index cb91f4924944..c44b0198b72c 100644 --- a/src/tools/rust-analyzer/crates/span/src/lib.rs +++ b/src/tools/rust-analyzer/crates/span/src/lib.rs @@ -1,4 +1,10 @@ //! File and span related types. + +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + use std::fmt::{self, Write}; mod ast_id; diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs index 1ded2b411319..815b4f279900 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs @@ -1,5 +1,10 @@ //! Conversions between [`SyntaxNode`] and [`tt::TokenTree`]. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + use std::{collections::VecDeque, fmt, hash::Hash}; use intern::Symbol; diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml index 1ee93013e3e8..8909fb423c4d 100644 --- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml +++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml @@ -33,6 +33,7 @@ rustc_apfloat = "0.2.3" test-utils.workspace = true [features] +default = [] in-rust-tree = [] [lints] diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs index de341f05538e..9e3083066c94 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs @@ -19,6 +19,11 @@ //! [RFC]: //! [Swift]: +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + mod parsing; mod ptr; mod syntax_error; diff --git a/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml b/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml index 353d4c312dba..7760ae7aa045 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml +++ b/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml @@ -21,5 +21,9 @@ intern.workspace = true triomphe.workspace = true paths.workspace = true +[features] +default = [] +in-rust-tree = [] + [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index 457cd3ac854a..5e8b250c24a0 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -1,4 +1,10 @@ //! A set of high-level utility fixture methods to use in tests. + +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + use std::{any::TypeId, mem, str::FromStr, sync}; use base_db::target::TargetData; diff --git a/src/tools/rust-analyzer/crates/tt/Cargo.toml b/src/tools/rust-analyzer/crates/tt/Cargo.toml index 82e7c24668fe..3183b72a6629 100644 --- a/src/tools/rust-analyzer/crates/tt/Cargo.toml +++ b/src/tools/rust-analyzer/crates/tt/Cargo.toml @@ -21,6 +21,7 @@ intern.workspace = true ra-ap-rustc_lexer.workspace = true [features] +default = [] in-rust-tree = [] [lints] diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs index ea0752250db1..d6a743c695e8 100644 --- a/src/tools/rust-analyzer/crates/tt/src/lib.rs +++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs @@ -5,6 +5,9 @@ #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_lexer as rustc_lexer; #[cfg(feature = "in-rust-tree")] From 24f00b63ef31c260e0e5a8393bc495dee9d7ad89 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 15 Sep 2025 20:37:24 +0800 Subject: [PATCH 510/585] bootstrap: run full `rust-analyzer` tests --- src/bootstrap/src/core/build_steps/test.rs | 55 ++++++++++++++++------ 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a699cd23fb60..59fcf761d9fc 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -465,35 +465,60 @@ fn make_run(run: RunConfig<'_>) { /// Runs `cargo test` for rust-analyzer fn run(self, builder: &Builder<'_>) { - let host = self.compilers.target(); + let build_compiler = self.compilers.build_compiler(); + let target = self.compilers.target(); - let workspace_path = "src/tools/rust-analyzer"; - // until the whole RA test suite runs on `i686`, we only run - // `proc-macro-srv` tests - let crate_path = "src/tools/rust-analyzer/crates/proc-macro-srv"; let mut cargo = tool::prepare_tool_cargo( builder, - self.compilers.build_compiler(), + build_compiler, Mode::ToolRustcPrivate, - host, + target, Kind::Test, - crate_path, + "src/tools/rust-analyzer", SourceType::InTree, &["in-rust-tree".to_owned()], ); cargo.allow_features(tool::RustAnalyzer::ALLOW_FEATURES); - let dir = builder.src.join(workspace_path); - // needed by rust-analyzer to find its own text fixtures, cf. - // https://github.com/rust-analyzer/expect-test/issues/33 - cargo.env("CARGO_WORKSPACE_DIR", &dir); + // N.B. it turns out _setting_ `CARGO_WORKSPACE_DIR` actually somehow breaks `expect-test`, + // even though previously we actually needed to set that hack to allow `expect-test` to + // correctly discover the r-a workspace instead of the outer r-l/r workspace. - // RA's test suite tries to write to the source directory, that can't - // work in Rust CI + // FIXME: RA's test suite tries to write to the source directory, that can't work in Rust CI + // without properly wiring up the writable test dir. cargo.env("SKIP_SLOW_TESTS", "1"); + // NOTE: we need to skip `src/tools/rust-analyzer/xtask` as they seem to exercise rustup / + // stable rustfmt. + // + // NOTE: you can only skip a specific workspace package via `--exclude=...` if you *also* + // specify `--workspace`. + cargo.arg("--workspace"); + cargo.arg("--exclude=xtask"); + + let mut skip_tests = vec![]; + + // NOTE: the following test skips is a bit cheeky in that it assumes there are no + // identically named tests across different r-a packages, where we want to run the + // identically named test in one package but not another. If we want to support that use + // case, we'd have to run the r-a tests in two batches (with one excluding the package that + // we *don't* want to run the test for, and the other batch including). + + // Across all platforms. + skip_tests.extend_from_slice(&[ + // FIXME: this test wants to find a `rustc`. We need to provide it with a path to staged + // in-tree `rustc`, but setting `RUSTC` env var requires some reworking of bootstrap. + "tests::smoke_test_real_sysroot_cargo", + // NOTE: part of `smol-str` test suite; this tries to access a stable rustfmt from the + // environment, which is not something we want to do. + "check_code_formatting", + ]); + + let skip_tests = skip_tests.iter().map(|name| format!("--skip={name}")).collect::>(); + let skip_tests = skip_tests.iter().map(|s| s.as_str()).collect::>(); + cargo.add_rustc_lib_path(builder); - run_cargo_test(cargo, &[], &[], "rust-analyzer", host, builder); + run_cargo_test(cargo, skip_tests.as_slice(), &[], "rust-analyzer", target, builder); } fn metadata(&self) -> Option { From 15e49699cab6d00fe626bff14c32e90860b99d21 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 11 Dec 2025 20:57:34 +0800 Subject: [PATCH 511/585] bootstrap: skip r-a main tests against 32-bit targets We don't really have a good way to get the target pointer width in bootstrap (yet), so I had to resort to hacky target tuple substring matches. This commit currently only gates on `i686-*` targets, which are 32-bits, and does not try to gate on `i586-*` targets (I need to run try jobs to check if r-a tests actually get run.) --- src/bootstrap/src/core/build_steps/test.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 59fcf761d9fc..6e2718f9f835 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -468,6 +468,19 @@ fn run(self, builder: &Builder<'_>) { let build_compiler = self.compilers.build_compiler(); let target = self.compilers.target(); + // NOTE: rust-analyzer repo currently (as of 2025-12-11) does not run tests against 32-bit + // targets, so we also don't run them in rust-lang/rust CI (because that will just mean that + // subtree syncs will keep getting 32-bit-specific failures that are not observed in + // rust-analyzer repo CI). + // + // Some 32-bit specific failures include e.g. target pointer width specific hashes. + + // FIXME: eventually, we should probably reduce the amount of target tuple substring + // matching in bootstrap. + if target.starts_with("i686") { + return; + } + let mut cargo = tool::prepare_tool_cargo( builder, build_compiler, From a96d486cbd96c5f6819bec25e1f23a71b23233a7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 11 Dec 2025 14:01:00 +0100 Subject: [PATCH 512/585] Update snapshot --- src/bootstrap/src/core/builder/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index b8ba1b4c2c34..28659f4c6fa5 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2912,6 +2912,7 @@ fn install_extended() { [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 [build] rustc 0 -> GenerateCopyright 1 [dist] rustc + [dist] rustc 1 -> rustc-dev 2 [build] rustc 1 -> cargo 2 [dist] rustc 1 -> cargo 2 [build] rustc 1 -> rust-analyzer 2 From c60ed211d1a7216fd422f99da158e853e3eca2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 10 Dec 2025 20:20:22 +0000 Subject: [PATCH 513/585] Do not suggest moving expression out of for loop when hitting `break` from desugaring --- .../src/diagnostics/conflict_errors.rs | 4 +- .../closure/spawn-thread.edition2018.stderr | 10 ----- .../moves/arc-consumed-in-looped-closure.rs | 37 +++++++++++++++++++ .../arc-consumed-in-looped-closure.stderr | 27 ++++++++++++++ .../nested-loop-moved-value-wrong-continue.rs | 6 +-- ...ted-loop-moved-value-wrong-continue.stderr | 30 +++------------ 6 files changed, 74 insertions(+), 40 deletions(-) create mode 100644 tests/ui/moves/arc-consumed-in-looped-closure.rs create mode 100644 tests/ui/moves/arc-consumed-in-looped-closure.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index f8a6fafbe78a..2999d1f2926c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -4521,7 +4521,9 @@ struct BreakFinder { impl<'hir> Visitor<'hir> for BreakFinder { fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { match ex.kind { - hir::ExprKind::Break(destination, _) => { + hir::ExprKind::Break(destination, _) + if !ex.span.is_desugaring(DesugaringKind::ForLoop) => + { self.found_breaks.push((destination, ex.span)); } hir::ExprKind::Continue(destination) => { diff --git a/tests/ui/ergonomic-clones/closure/spawn-thread.edition2018.stderr b/tests/ui/ergonomic-clones/closure/spawn-thread.edition2018.stderr index ac8e1c5fa858..4ac5dfb8d228 100644 --- a/tests/ui/ergonomic-clones/closure/spawn-thread.edition2018.stderr +++ b/tests/ui/ergonomic-clones/closure/spawn-thread.edition2018.stderr @@ -12,16 +12,6 @@ LL | | drop((x.0, x.1, x.2)); | | --- use occurs due to use in closure LL | | }); | |_________- value moved here, in previous iteration of loop - | -help: consider moving the expression out of the loop so it is only moved once - | -LL ~ let mut value = std::thread::spawn(use || { -LL + -LL + drop((x.0, x.1, x.2)); -LL + }); -LL ~ for _ in 0..10 { -LL ~ let handler = value; - | error: aborting due to 1 previous error diff --git a/tests/ui/moves/arc-consumed-in-looped-closure.rs b/tests/ui/moves/arc-consumed-in-looped-closure.rs new file mode 100644 index 000000000000..8700c7850847 --- /dev/null +++ b/tests/ui/moves/arc-consumed-in-looped-closure.rs @@ -0,0 +1,37 @@ +use std::thread; +use std::sync::{Arc, Mutex, Condvar}; +use std::collections::VecDeque; + +type Job = Box; + +struct ThreadPool { + workers: Vec>, + queue: Arc<()>, +} + +impl ThreadPool { + fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + panic!() + } +} + +fn main() { + let results = Arc::new(Mutex::new(Vec::new())); //~ NOTE move occurs because + let pool = ThreadPool { + workers: vec![], + queue: Arc::new(()), + }; + + for i in 0..20 { //~ NOTE inside of this loop + // let results = Arc::clone(&results); // Forgot this. + pool.execute(move || { //~ ERROR E0382 + //~^ NOTE value moved into closure here, in previous iteration of loop + //~| HELP consider cloning the value before moving it into the closure + let mut r = results.lock().unwrap(); //~ NOTE use occurs due to use in closure + r.push(i); + }); + } +} diff --git a/tests/ui/moves/arc-consumed-in-looped-closure.stderr b/tests/ui/moves/arc-consumed-in-looped-closure.stderr new file mode 100644 index 000000000000..47d6fd6cbad3 --- /dev/null +++ b/tests/ui/moves/arc-consumed-in-looped-closure.stderr @@ -0,0 +1,27 @@ +error[E0382]: use of moved value: `results` + --> $DIR/arc-consumed-in-looped-closure.rs:30:22 + | +LL | let results = Arc::new(Mutex::new(Vec::new())); + | ------- move occurs because `results` has type `Arc>>`, which does not implement the `Copy` trait +... +LL | for i in 0..20 { + | -------------- inside of this loop +LL | // let results = Arc::clone(&results); // Forgot this. +LL | pool.execute(move || { + | ^^^^^^^ value moved into closure here, in previous iteration of loop +... +LL | let mut r = results.lock().unwrap(); + | ------- use occurs due to use in closure + | +help: consider cloning the value before moving it into the closure + | +LL ~ let value = results.clone(); +LL ~ pool.execute(move || { +LL | +LL | +LL ~ let mut r = value.lock().unwrap(); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs b/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs index 87800d314ed5..0cbb501a5764 100644 --- a/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs +++ b/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs @@ -7,8 +7,6 @@ fn foo() { //~^ NOTE this reinitialization might get skipped //~| NOTE move occurs because `foo` has type `String` //~| NOTE inside of this loop - //~| HELP consider moving the expression out of the loop - //~| NOTE in this expansion of desugaring of `for` loop //~| NOTE //~| NOTE baz.push(foo); @@ -35,8 +33,6 @@ fn main() { //~| NOTE for bar in &bars { //~^ NOTE inside of this loop - //~| HELP consider moving the expression out of the loop - //~| NOTE in this expansion of desugaring of `for` loop //~| NOTE if foo == *bar { baz.push(foo); @@ -44,7 +40,7 @@ fn main() { //~| HELP consider cloning the value continue; //~^ NOTE verify that your loop breaking logic is correct - //~| NOTE this `continue` advances the loop at line 36 + //~| NOTE this `continue` advances the loop at line 34 } } qux.push(foo); diff --git a/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr b/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr index 6ef1a4193b1a..60be70007fbe 100644 --- a/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr +++ b/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `foo` - --> $DIR/nested-loop-moved-value-wrong-continue.rs:21:14 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:19:14 | LL | for foo in foos { for bar in &bars { if foo == *bar { | --- ---------------- inside of this loop @@ -14,29 +14,20 @@ LL | qux.push(foo); | ^^^ value used here after move | note: verify that your loop breaking logic is correct - --> $DIR/nested-loop-moved-value-wrong-continue.rs:17:9 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:15:9 | LL | for foo in foos { for bar in &bars { if foo == *bar { | --------------- ---------------- ... LL | continue; - | ^^^^^^^^ this `continue` advances the loop at $DIR/nested-loop-moved-value-wrong-continue.rs:6:23: 20:8 -help: consider moving the expression out of the loop so it is only moved once - | -LL ~ for foo in foos { let mut value = baz.push(foo); -LL ~ for bar in &bars { if foo == *bar { -LL | -... -LL | -LL ~ value; - | + | ^^^^^^^^ this `continue` advances the loop at $DIR/nested-loop-moved-value-wrong-continue.rs:6:23: 18:8 help: consider cloning the value if the performance cost is acceptable | LL | baz.push(foo.clone()); | ++++++++ error[E0382]: use of moved value: `foo` - --> $DIR/nested-loop-moved-value-wrong-continue.rs:50:18 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:46:18 | LL | for foo in foos { | --- @@ -54,7 +45,7 @@ LL | qux.push(foo); | ^^^ value used here after move | note: verify that your loop breaking logic is correct - --> $DIR/nested-loop-moved-value-wrong-continue.rs:45:17 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:41:17 | LL | for foo in foos { | --------------- @@ -63,16 +54,7 @@ LL | for bar in &bars { | ---------------- ... LL | continue; - | ^^^^^^^^ this `continue` advances the loop at line 36 -help: consider moving the expression out of the loop so it is only moved once - | -LL ~ let mut value = baz.push(foo); -LL ~ for bar in &bars { -LL | -... -LL | if foo == *bar { -LL ~ value; - | + | ^^^^^^^^ this `continue` advances the loop at line 34 help: consider cloning the value if the performance cost is acceptable | LL | baz.push(foo.clone()); From 42c8b68ee9b591b79cbdfd68f5656a172815aa21 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 11 Dec 2025 18:48:10 +0100 Subject: [PATCH 514/585] Bump nightly version -> 2025-12-11 --- clippy_utils/README.md | 2 +- rust-toolchain.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_utils/README.md b/clippy_utils/README.md index 4b1a10a3d9cf..dc8695fef9f5 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-11-28 +nightly-2025-12-11 ``` diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5157b79832a3..1384f4078ebe 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-11-28" +channel = "nightly-2025-12-11" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From 1ff46825908de84aa401b5be0ef7b70a89d8e8da Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 11 Dec 2025 18:48:15 +0100 Subject: [PATCH 515/585] Bump Clippy version -> 0.1.94 --- Cargo.toml | 2 +- clippy_config/Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- clippy_utils/Cargo.toml | 2 +- declare_clippy_lint/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fee885d8fa7e..67078adea2b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.93" +version = "0.1.94" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index 3f6b26d3334e..a65fe7bcbda5 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_config" -version = "0.1.93" +version = "0.1.94" edition = "2024" publish = false diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index bc97746a1cba..7a78ef32bf3c 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.93" +version = "0.1.94" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index f2e276b27a98..503d581d6c7f 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.93" +version = "0.1.94" edition = "2024" description = "Helpful tools for writing lints, provided as they are used in Clippy" repository = "https://github.com/rust-lang/rust-clippy" diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml index b73a7c7bb4d9..ee6d6cdbc34e 100644 --- a/declare_clippy_lint/Cargo.toml +++ b/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.93" +version = "0.1.94" edition = "2024" repository = "https://github.com/rust-lang/rust-clippy" license = "MIT OR Apache-2.0" From 43fa2a95c90d7ac4bb98d87e62630e9f549d00c2 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 11 Dec 2025 18:15:15 +0000 Subject: [PATCH 516/585] add regression test for `proc_macro` error subdiagnostics --- tests/ui/proc-macro/auxiliary/sub-error-diag.rs | 17 +++++++++++++++++ tests/ui/proc-macro/sub-error-diag.rs | 13 +++++++++++++ tests/ui/proc-macro/sub-error-diag.stderr | 11 +++++++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/ui/proc-macro/auxiliary/sub-error-diag.rs create mode 100644 tests/ui/proc-macro/sub-error-diag.rs create mode 100644 tests/ui/proc-macro/sub-error-diag.stderr diff --git a/tests/ui/proc-macro/auxiliary/sub-error-diag.rs b/tests/ui/proc-macro/auxiliary/sub-error-diag.rs new file mode 100644 index 000000000000..5ce8c5d90304 --- /dev/null +++ b/tests/ui/proc-macro/auxiliary/sub-error-diag.rs @@ -0,0 +1,17 @@ +#![feature(proc_macro_diagnostic)] + +extern crate proc_macro; + +use proc_macro::{Diagnostic, Level, Span}; + +#[proc_macro_attribute] +pub fn proc_emit_err( + _: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + Diagnostic::new(Level::Error, "Parent message") + .span_error(Span::call_site(), "Child message") + .emit(); + + input +} diff --git a/tests/ui/proc-macro/sub-error-diag.rs b/tests/ui/proc-macro/sub-error-diag.rs new file mode 100644 index 000000000000..11218fc66a37 --- /dev/null +++ b/tests/ui/proc-macro/sub-error-diag.rs @@ -0,0 +1,13 @@ +//@ proc-macro: sub-error-diag.rs + +// Regression test for issue https://github.com/rust-lang/rust/issues/145305, which used to cause an ICE +// due to an assertion in the compiler that errors could not be subdiagnostics. + +extern crate sub_error_diag; + +//~? ERROR: Parent message +#[sub_error_diag::proc_emit_err] +//~^ ERROR: Child message +fn foo() {} + +fn main() {} diff --git a/tests/ui/proc-macro/sub-error-diag.stderr b/tests/ui/proc-macro/sub-error-diag.stderr new file mode 100644 index 000000000000..b5d83e4d52ae --- /dev/null +++ b/tests/ui/proc-macro/sub-error-diag.stderr @@ -0,0 +1,11 @@ +error: Parent message + | +error: Child message + --> $DIR/sub-error-diag.rs:9:1 + | +LL | #[sub_error_diag::proc_emit_err] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the attribute macro `sub_error_diag::proc_emit_err` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + From 26c164f60cf6491146c5000cfda5c6602ac22088 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 11 Dec 2025 19:16:53 +0100 Subject: [PATCH 517/585] Update Cargo.lock --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03a4d71f67c3..0be6de0a2871 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -621,7 +621,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "clippy" -version = "0.1.93" +version = "0.1.94" dependencies = [ "anstream", "askama", @@ -648,7 +648,7 @@ dependencies = [ [[package]] name = "clippy_config" -version = "0.1.93" +version = "0.1.94" dependencies = [ "clippy_utils", "itertools", @@ -671,7 +671,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.93" +version = "0.1.94" dependencies = [ "arrayvec", "cargo_metadata 0.18.1", @@ -703,7 +703,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.93" +version = "0.1.94" dependencies = [ "arrayvec", "itertools", @@ -1107,7 +1107,7 @@ dependencies = [ [[package]] name = "declare_clippy_lint" -version = "0.1.93" +version = "0.1.94" [[package]] name = "derive-where" From 03493597922f6d1527955b1d7558dd369126f1d9 Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Mon, 8 Dec 2025 21:39:59 +0000 Subject: [PATCH 518/585] Suggest `cfg(false)` instead of `cfg(FALSE)` --- compiler/rustc_lint/messages.ftl | 1 + .../src/early/diagnostics/check_cfg.rs | 25 +++++ compiler/rustc_lint/src/lints.rs | 11 +++ tests/ui/check-cfg/false.rs | 61 ++++++++++++ tests/ui/check-cfg/false.stderr | 95 +++++++++++++++++++ 5 files changed, 193 insertions(+) create mode 100644 tests/ui/check-cfg/false.rs create mode 100644 tests/ui/check-cfg/false.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index bc1c246b8f03..846c83aff2d3 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -829,6 +829,7 @@ lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_printl lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg} lint_unexpected_cfg_add_cmdline_arg = to expect this configuration use `{$cmdline_arg}` +lint_unexpected_cfg_boolean = you may have meant to use `{$literal}` (notice the capitalization). Doing so makes this predicate evaluate to `{$literal}` unconditionally lint_unexpected_cfg_cargo_update = the {$macro_kind} `{$macro_name}` may come from an old version of the `{$crate_name}` crate, try updating your dependency with `cargo update -p {$crate_name}` lint_unexpected_cfg_define_features = consider defining some features in `Cargo.toml` diff --git a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs index e2f5dd315d57..0c8d7523a9dc 100644 --- a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs +++ b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs @@ -138,6 +138,16 @@ pub(super) fn unexpected_cfg_name( let is_from_external_macro = name_span.in_external_macro(sess.source_map()); let mut is_feature_cfg = name == sym::feature; + fn miscapitalized_boolean(name: Symbol) -> Option { + if name.as_str().eq_ignore_ascii_case("false") { + Some(false) + } else if name.as_str().eq_ignore_ascii_case("true") { + Some(true) + } else { + None + } + } + let code_sugg = if is_feature_cfg && is_from_cargo { lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures // Suggest correct `version("..")` predicate syntax @@ -148,6 +158,21 @@ pub(super) fn unexpected_cfg_name( between_name_and_value: name_span.between(value_span), after_value: value_span.shrink_to_hi(), } + // Suggest a literal `false` instead + // Detect miscapitalized `False`/`FALSE` etc, ensuring that this isn't `r#false` + } else if value.is_none() + // If this is a miscapitalized False/FALSE, suggest the boolean literal instead + && let Some(boolean) = miscapitalized_boolean(name) + // Check this isn't a raw identifier + && sess + .source_map() + .span_to_snippet(name_span) + .map_or(true, |snippet| !snippet.contains("r#")) + { + lints::unexpected_cfg_name::CodeSuggestion::BooleanLiteral { + span: name_span, + literal: boolean, + } // Suggest the most probable if we found one } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) { is_feature_cfg |= best_match == sym::feature; diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 1bec316ce45a..3f853e09c72d 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2401,6 +2401,17 @@ pub(crate) enum CodeSuggestion { #[subdiagnostic] expected_names: Option, }, + #[suggestion( + lint_unexpected_cfg_boolean, + applicability = "machine-applicable", + style = "verbose", + code = "{literal}" + )] + BooleanLiteral { + #[primary_span] + span: Span, + literal: bool, + }, } #[derive(Subdiagnostic)] diff --git a/tests/ui/check-cfg/false.rs b/tests/ui/check-cfg/false.rs new file mode 100644 index 000000000000..f7ed43ccfa95 --- /dev/null +++ b/tests/ui/check-cfg/false.rs @@ -0,0 +1,61 @@ +//! Check that `cfg(false)` is suggested instead of cfg(FALSE) +// +//@ check-pass +//@ no-auto-check-cfg +//@ compile-flags: --check-cfg=cfg() + +#[cfg(FALSE)] +//~^ WARNING unexpected `cfg` condition name: `FALSE` +//~| HELP: to expect this configuration use +//~| HELP: you may have meant to use `false` (notice the capitalization). +pub fn a() {} + +#[cfg(False)] +//~^ WARNING unexpected `cfg` condition name: `False` +//~| HELP: to expect this configuration use +//~| HELP: you may have meant to use `false` (notice the capitalization). +pub fn b() {} + +#[cfg(r#false)] +//~^ WARNING unexpected `cfg` condition name: `r#false` +//~| HELP: to expect this configuration use +// No capitalization help for r#false +pub fn c() {} + +#[cfg(r#False)] +//~^ WARNING unexpected `cfg` condition name: `False` +//~| HELP: to expect this configuration use +// No capitalization help for r#False +pub fn d() {} + +#[cfg(false)] +pub fn e() {} + +#[cfg(TRUE)] +//~^ WARNING unexpected `cfg` condition name: `TRUE` +//~| HELP: to expect this configuration use +//~| HELP: you may have meant to use `true` (notice the capitalization). +pub fn f() {} + +#[cfg(True)] +//~^ WARNING unexpected `cfg` condition name: `True` +//~| HELP: to expect this configuration use +//~| HELP: you may have meant to use `true` (notice the capitalization). +pub fn g() {} + +#[cfg(r#true)] +//~^ WARNING unexpected `cfg` condition name: `r#true` +//~| HELP: to expect this configuration use +// No capitalization help for r#true +pub fn h() {} + +#[cfg(r#True)] +//~^ WARNING unexpected `cfg` condition name: `True` +//~| HELP: to expect this configuration use +// No capitalization help for r#True +pub fn i() {} + +#[cfg(true)] +pub fn j() {} + +pub fn main() {} diff --git a/tests/ui/check-cfg/false.stderr b/tests/ui/check-cfg/false.stderr new file mode 100644 index 000000000000..f4480a3dc67e --- /dev/null +++ b/tests/ui/check-cfg/false.stderr @@ -0,0 +1,95 @@ +warning: unexpected `cfg` condition name: `FALSE` + --> $DIR/false.rs:7:7 + | +LL | #[cfg(FALSE)] + | ^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(FALSE)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default +help: you may have meant to use `false` (notice the capitalization). Doing so makes this predicate evaluate to `false` unconditionally + | +LL - #[cfg(FALSE)] +LL + #[cfg(false)] + | + +warning: unexpected `cfg` condition name: `False` + --> $DIR/false.rs:13:7 + | +LL | #[cfg(False)] + | ^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(False)` + = note: see for more information about checking conditional configuration +help: you may have meant to use `false` (notice the capitalization). Doing so makes this predicate evaluate to `false` unconditionally (notice the capitalization) + | +LL - #[cfg(False)] +LL + #[cfg(false)] + | + +warning: unexpected `cfg` condition name: `r#false` + --> $DIR/false.rs:19:7 + | +LL | #[cfg(r#false)] + | ^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(r#false)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `False` + --> $DIR/false.rs:25:7 + | +LL | #[cfg(r#False)] + | ^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(False)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `TRUE` + --> $DIR/false.rs:34:7 + | +LL | #[cfg(TRUE)] + | ^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(TRUE)` + = note: see for more information about checking conditional configuration +help: you may have meant to use `true` (notice the capitalization). Doing so makes this predicate evaluate to `true` unconditionally + | +LL - #[cfg(TRUE)] +LL + #[cfg(true)] + | + +warning: unexpected `cfg` condition name: `True` + --> $DIR/false.rs:40:7 + | +LL | #[cfg(True)] + | ^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(True)` + = note: see for more information about checking conditional configuration +help: you may have meant to use `true` (notice the capitalization). Doing so makes this predicate evaluate to `true` unconditionally + | +LL - #[cfg(True)] +LL + #[cfg(true)] + | + +warning: unexpected `cfg` condition name: `r#true` + --> $DIR/false.rs:46:7 + | +LL | #[cfg(r#true)] + | ^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(r#true)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `True` + --> $DIR/false.rs:52:7 + | +LL | #[cfg(r#True)] + | ^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(True)` + = note: see for more information about checking conditional configuration + +warning: 8 warnings emitted + From de0d961eb3cf26c73b2d03464845ab465a5484e5 Mon Sep 17 00:00:00 2001 From: Makai Date: Fri, 12 Dec 2025 10:25:23 +0800 Subject: [PATCH 519/585] triagebot: ping makai410 for rustc_public --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 397e6875eef9..00e2d4c787ab 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1154,7 +1154,7 @@ cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"] [mentions."compiler/rustc_public"] message = "This PR changes rustc_public" -cc = ["@oli-obk", "@celinval", "@ouz-a"] +cc = ["@oli-obk", "@celinval", "@ouz-a", "@makai410"] [mentions."compiler/rustc_target/src/spec"] message = """ From 24302fd95f026197304b4814cab668553b4b345c Mon Sep 17 00:00:00 2001 From: Makai Date: Fri, 12 Dec 2025 10:26:03 +0800 Subject: [PATCH 520/585] triagebot: add myself(makai410) to the review rotation --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 00e2d4c787ab..3182122bdeb0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1542,6 +1542,7 @@ project-stable-mir = [ "@celinval", "@oli-obk", "@scottmcm", + "@makai410", ] project-exploit-mitigations = [ "@cuviper", From 5aa2c14aebc731f54e737231e6f57cc7fc47a659 Mon Sep 17 00:00:00 2001 From: Makai Date: Fri, 12 Dec 2025 10:35:13 +0800 Subject: [PATCH 521/585] mailmap: add makai410 --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index a586e7047769..4c254b396b53 100644 --- a/.mailmap +++ b/.mailmap @@ -431,6 +431,7 @@ Lzu Tao Maik Klein Maja Kądziołka Maja Kądziołka +Makai Malo Jaffré Manish Goregaokar Mara Bos From b7b0007bf05320cbfe046c1e67f54b5d92b4685e Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 5 Dec 2025 20:38:22 +0100 Subject: [PATCH 522/585] Add current working to source map and `FileLoader` This is preparation for the filename handling overhaul where having access to the working directory is mandatory. --- compiler/rustc_span/src/source_map.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 17de34c8436f..090442bf64bd 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -105,6 +105,9 @@ pub trait FileLoader { /// Read the contents of a potentially non-UTF-8 file into memory. /// We don't normalize binary files, so we can start in an Arc. fn read_binary_file(&self, path: &Path) -> io::Result>; + + /// Current working directory + fn current_directory(&self) -> io::Result; } /// A FileLoader that uses std::fs to load real files. @@ -170,6 +173,10 @@ fn read_binary_file(&self, path: &Path) -> io::Result> { file.read_to_end(&mut bytes)?; Ok(bytes.into()) } + + fn current_directory(&self) -> io::Result { + std::env::current_dir() + } } // _____________________________________________________________________________ @@ -198,6 +205,9 @@ pub struct SourceMap { // `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`. path_mapping: FilePathMapping, + /// Current working directory + working_dir: RealFileName, + /// The algorithm used for hashing the contents of each source file. hash_kind: SourceFileHashAlgorithm, @@ -221,8 +231,14 @@ pub fn new(path_mapping: FilePathMapping) -> SourceMap { pub fn with_inputs( SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }: SourceMapInputs, ) -> SourceMap { + let cwd = file_loader + .current_directory() + .expect("expecting a current working directory to exist"); + let working_dir = cwd.to_path_buf().into(); + debug!(?working_dir); SourceMap { files: Default::default(), + working_dir, file_loader: IntoDynSyncSend(file_loader), path_mapping, hash_kind, @@ -234,6 +250,10 @@ pub fn path_mapping(&self) -> &FilePathMapping { &self.path_mapping } + pub fn working_dir(&self) -> &RealFileName { + &self.working_dir + } + pub fn file_exists(&self, path: &Path) -> bool { self.file_loader.file_exists(path) } From 5da3de7527d79c63cb6f0554037bffef376a5669 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 5 Dec 2025 21:00:04 +0100 Subject: [PATCH 523/585] Move users of `span_to_embeddable_string` to `span_to_diagnostic_string` This is done in order to simplify the filename overhaul and those places don't need to the embeddable path anyway. --- compiler/rustc_borrowck/src/region_infer/dump_mir.rs | 2 +- compiler/rustc_expand/src/stats.rs | 5 +---- compiler/rustc_middle/src/mir/pretty.rs | 8 ++++---- compiler/rustc_monomorphize/src/util.rs | 11 ++--------- 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs index a9ab30fd8fa3..68f822aac403 100644 --- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs +++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs @@ -80,7 +80,7 @@ fn for_each_constraint( let OutlivesConstraint { sup, sub, locations, category, span, .. } = constraint; let (name, arg) = match locations { Locations::All(span) => { - ("All", tcx.sess.source_map().span_to_embeddable_string(*span)) + ("All", tcx.sess.source_map().span_to_diagnostic_string(*span)) } Locations::Single(loc) => ("Single", format!("{loc:?}")), }; diff --git a/compiler/rustc_expand/src/stats.rs b/compiler/rustc_expand/src/stats.rs index 3e40632275b6..00f1c11044e0 100644 --- a/compiler/rustc_expand/src/stats.rs +++ b/compiler/rustc_expand/src/stats.rs @@ -138,10 +138,7 @@ pub(crate) fn update_macro_stats( if false { let name = ExpnKind::Macro(macro_kind, name).descr(); let crate_name = &ecx.ecfg.crate_name; - let span = ecx - .sess - .source_map() - .span_to_string(span, rustc_span::FileNameDisplayPreference::Local); + let span = ecx.sess.source_map().span_to_diagnostic_string(span); eprint!( "\ -------------------------------\n\ diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 3bdc5fdb420c..b225dd4ef60a 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -504,7 +504,7 @@ fn write_scope_tree( "{0:1$} // at {2}", indented_header, ALIGN, - tcx.sess.source_map().span_to_embeddable_string(span), + tcx.sess.source_map().span_to_diagnostic_string(span), )?; } else { writeln!(w, "{indented_header}")?; @@ -688,7 +688,7 @@ fn write_user_type_annotations( "| {:?}: user_ty: {}, span: {}, inferred_ty: {}", index.index(), annotation.user_ty, - tcx.sess.source_map().span_to_embeddable_string(annotation.span), + tcx.sess.source_map().span_to_diagnostic_string(annotation.span), with_no_trimmed_paths!(format!("{}", annotation.inferred_ty)), )?; } @@ -1420,7 +1420,7 @@ fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, _location: Loca self.push("mir::ConstOperand"); self.push(&format!( "+ span: {}", - self.tcx.sess.source_map().span_to_embeddable_string(*span) + self.tcx.sess.source_map().span_to_diagnostic_string(*span) )); if let Some(user_ty) = user_ty { self.push(&format!("+ user_ty: {user_ty:?}")); @@ -1503,7 +1503,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { } fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo) -> String { - let location = tcx.sess.source_map().span_to_embeddable_string(span); + let location = tcx.sess.source_map().span_to_diagnostic_string(span); format!("scope {} at {}", scope.index(), location,) } diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs index deb4ab433bfe..6fcb18177a14 100644 --- a/compiler/rustc_monomorphize/src/util.rs +++ b/compiler/rustc_monomorphize/src/util.rs @@ -49,7 +49,7 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In .unwrap_or_else(|e| format!("Failed {e:?}")); let closure_span = tcx.def_span(closure_def_id); - let src_file = tcx.sess.source_map().span_to_filename(closure_span); + let src_file = tcx.sess.source_map().span_to_diagnostic_string(closure_span); let line_nos = tcx .sess .source_map() @@ -57,14 +57,7 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In .map(|l| format!("{:?} {:?}", l.lines.first(), l.lines.last())) .unwrap_or_else(|e| format!("{e:?}")); - if let Err(e) = writeln!( - file, - "{}, {}, {}, {:?}", - old_size, - new_size, - src_file.prefer_local(), - line_nos - ) { + if let Err(e) = writeln!(file, "{}, {}, {}, {:?}", old_size, new_size, src_file, line_nos) { eprintln!("Error writing to file {e}") } } From 8cbfb26383347cf4970a488177acfdc35c30984b Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 28 Nov 2025 00:01:51 +0100 Subject: [PATCH 524/585] Overhaul filename handling for cross-compiler consistency This commit refactors `SourceMap` and most importantly `RealFileName` to make it self-contained in order to achieve cross-compiler consistency. This is achieved: - by making `RealFileName` immutable - by only having `SourceMap::to_real_filename` create `RealFileName` - by also making `RealFileName` holds it's working directory, it's embeddable name and the remapped scopes - by making most `FileName` and `RealFileName` methods take a scope as an argument In order for `SourceMap::to_real_filename` to know which scopes to apply `FilePathMapping` now takes the current remapping scopes to apply, which makes `FileNameDisplayPreference` and company useless and are removed. The scopes type `RemapPathScopeComponents` was moved from `rustc_session::config` to `rustc_span`. The previous system for scoping the local/remapped filenames `RemapFileNameExt::for_scope` is no longer useful as it's replaced by methods on `FileName` and `RealFileName`. --- Cargo.lock | 2 +- .../rustc_builtin_macros/src/source_util.rs | 7 +- compiler/rustc_builtin_macros/src/test.rs | 4 +- compiler/rustc_codegen_llvm/src/back/write.rs | 15 +- .../src/coverageinfo/mapgen.rs | 16 +- .../src/debuginfo/metadata.rs | 109 ++-- .../src/const_eval/machine.rs | 9 +- compiler/rustc_driver_impl/src/pretty.rs | 2 +- compiler/rustc_errors/src/json.rs | 14 +- compiler/rustc_errors/src/json/tests.rs | 6 +- compiler/rustc_expand/src/expand.rs | 2 +- compiler/rustc_interface/src/passes.rs | 10 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 52 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 8 +- compiler/rustc_middle/src/mir/consts.rs | 10 +- compiler/rustc_middle/src/ty/print/pretty.rs | 38 +- compiler/rustc_parse/src/lib.rs | 8 +- compiler/rustc_parse/src/parser/tests.rs | 20 +- compiler/rustc_passes/src/entry.rs | 7 +- .../rustc_public_bridge/src/context/impls.rs | 9 +- compiler/rustc_resolve/src/rustdoc/tests.rs | 10 +- compiler/rustc_session/Cargo.toml | 1 - compiler/rustc_session/src/config.rs | 58 +-- compiler/rustc_session/src/options.rs | 2 +- compiler/rustc_session/src/session.rs | 71 +-- compiler/rustc_span/Cargo.toml | 1 + compiler/rustc_span/src/lib.rs | 339 +++++++++---- compiler/rustc_span/src/profiling.rs | 3 +- compiler/rustc_span/src/source_map.rs | 256 ++++------ compiler/rustc_span/src/source_map/tests.rs | 472 ++++++++++++------ tests/run-make/duplicate-dependency/rmake.rs | 6 +- ...refix-diagnostics.only-diag-in-deps.stderr | 2 +- 32 files changed, 805 insertions(+), 764 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d818d87e0804..b7cca34528f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4630,7 +4630,6 @@ dependencies = [ name = "rustc_session" version = "0.0.0" dependencies = [ - "bitflags", "getopts", "libc", "rand 0.9.2", @@ -4657,6 +4656,7 @@ dependencies = [ name = "rustc_span" version = "0.0.0" dependencies = [ + "bitflags", "blake3", "derive-where", "indexmap", diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 16adaab15c52..d49f4ded010b 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -68,13 +68,10 @@ pub(crate) fn expand_file( let topmost = cx.expansion_cause().unwrap_or(sp); let loc = cx.source_map().lookup_char_pos(topmost.lo()); - use rustc_session::RemapFileNameExt; - use rustc_session::config::RemapPathScopeComponents; + use rustc_span::RemapPathScopeComponents; ExpandResult::Ready(MacEager::expr(cx.expr_str( topmost, - Symbol::intern( - &loc.file.name.for_scope(cx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(), - ), + Symbol::intern(&loc.file.name.display(RemapPathScopeComponents::MACRO).to_string_lossy()), ))) } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index f31ad4f591b1..6f14385d5d30 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -11,7 +11,7 @@ use rustc_expand::base::*; use rustc_hir::Attribute; use rustc_hir::attrs::AttributeKind; -use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Ident, Span, Symbol, sym}; +use rustc_span::{ErrorGuaranteed, Ident, RemapPathScopeComponents, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::debug; @@ -445,7 +445,7 @@ fn get_location_info(cx: &ExtCtxt<'_>, fn_: &ast::Fn) -> (Symbol, usize, usize, cx.sess.source_map().span_to_location_info(span); let file_name = match source_file { - Some(sf) => sf.name.display(FileNameDisplayPreference::Remapped).to_string(), + Some(sf) => sf.name.display(RemapPathScopeComponents::MACRO).to_string(), None => "no-location".to_string(), }; diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index b131de1df8ba..2c4943e835a6 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -21,10 +21,8 @@ use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_session::config::{ - self, Lto, OutputType, Passes, RemapPathScopeComponents, SplitDwarfKind, SwitchWithOptPath, -}; -use rustc_span::{BytePos, InnerSpan, Pos, SpanData, SyntaxContext, sym}; +use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath}; +use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext, sym}; use rustc_target::spec::{ Arch, CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel, }; @@ -248,6 +246,7 @@ pub(crate) fn target_machine_factory( !sess.opts.unstable_opts.use_ctors_section.unwrap_or(sess.target.use_ctors_section); let path_mapping = sess.source_map().path_mapping().clone(); + let working_dir = sess.source_map().working_dir().clone(); let use_emulated_tls = matches!(sess.tls_model(), TlsModel::Emulated); @@ -271,9 +270,6 @@ pub(crate) fn target_machine_factory( } }; - let file_name_display_preference = - sess.filename_display_preference(RemapPathScopeComponents::DEBUGINFO); - let use_wasm_eh = wants_wasm_eh(sess); let prof = SelfProfilerRef::clone(&sess.prof); @@ -284,8 +280,9 @@ pub(crate) fn target_machine_factory( let path_to_cstring_helper = |path: Option| -> CString { let path = path.unwrap_or_default(); let path = path_mapping - .to_real_filename(path) - .to_string_lossy(file_name_display_preference) + .to_real_filename(&working_dir, path) + .path(RemapPathScopeComponents::DEBUGINFO) + .to_string_lossy() .into_owned(); CString::new(path).unwrap() }; diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index b3a11f8b12bf..bc54657a380a 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -7,9 +7,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_index::IndexVec; use rustc_middle::ty::TyCtxt; -use rustc_session::RemapFileNameExt; -use rustc_session::config::RemapPathScopeComponents; -use rustc_span::{SourceFile, StableSourceFileId}; +use rustc_span::{RemapPathScopeComponents, SourceFile, StableSourceFileId}; use tracing::debug; use crate::common::CodegenCx; @@ -127,10 +125,7 @@ fn build<'a>(tcx: TyCtxt<'_>, all_files: impl Iterator) - for file in all_files { raw_file_table.entry(file.stable_id).or_insert_with(|| { - file.name - .for_scope(tcx.sess, RemapPathScopeComponents::COVERAGE) - .to_string_lossy() - .into_owned() + file.name.display(RemapPathScopeComponents::COVERAGE).to_string_lossy().into_owned() }); } @@ -145,9 +140,10 @@ fn build<'a>(tcx: TyCtxt<'_>, all_files: impl Iterator) - // resolve any other entries that are stored as relative paths. let base_dir = tcx .sess - .opts - .working_dir - .for_scope(tcx.sess, RemapPathScopeComponents::COVERAGE) + .psess + .source_map() + .working_dir() + .path(RemapPathScopeComponents::COVERAGE) .to_string_lossy(); table.push(base_dir.as_ref()); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 5535ebe65859..dc941cb41c56 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::fmt::{self, Write}; use std::hash::{Hash, Hasher}; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::sync::Arc; use std::{iter, ptr}; @@ -19,9 +19,7 @@ self, AdtKind, CoroutineArgsExt, ExistentialTraitRef, Instance, Ty, TyCtxt, Visibility, }; use rustc_session::config::{self, DebugInfo, Lto}; -use rustc_span::{ - DUMMY_SP, FileName, FileNameDisplayPreference, SourceFile, Span, Symbol, hygiene, -}; +use rustc_span::{DUMMY_SP, FileName, RemapPathScopeComponents, SourceFile, Span, Symbol, hygiene}; use rustc_symbol_mangling::typeid_for_trait_ref; use rustc_target::spec::DebuginfoKind; use smallvec::smallvec; @@ -555,79 +553,38 @@ fn alloc_new_file_metadata<'ll>( ) -> &'ll DIFile { debug!(?source_file.name); - let filename_display_preference = - cx.sess().filename_display_preference(RemapPathScopeComponents::DEBUGINFO); - - use rustc_session::config::RemapPathScopeComponents; let (directory, file_name) = match &source_file.name { FileName::Real(filename) => { - let working_directory = &cx.sess().opts.working_dir; - debug!(?working_directory); + let (working_directory, embeddable_name) = + filename.embeddable_name(RemapPathScopeComponents::DEBUGINFO); - if filename_display_preference == FileNameDisplayPreference::Remapped { - let filename = cx - .sess() - .source_map() - .path_mapping() - .to_embeddable_absolute_path(filename.clone(), working_directory); + debug!(?working_directory, ?embeddable_name); - // Construct the absolute path of the file - let abs_path = filename.remapped_path_if_available(); - debug!(?abs_path); - - if let Ok(rel_path) = - abs_path.strip_prefix(working_directory.remapped_path_if_available()) - { - // If the compiler's working directory (which also is the DW_AT_comp_dir of - // the compilation unit) is a prefix of the path we are about to emit, then - // only emit the part relative to the working directory. Because of path - // remapping we sometimes see strange things here: `abs_path` might - // actually look like a relative path (e.g. - // `/src/lib.rs`), so if we emit it without taking - // the working directory into account, downstream tooling will interpret it - // as `//src/lib.rs`, which - // makes no sense. Usually in such cases the working directory will also be - // remapped to `` or some other prefix of the path - // we are remapping, so we end up with - // `//src/lib.rs`. - // By moving the working directory portion into the `directory` part of the - // DIFile, we allow LLVM to emit just the relative path for DWARF, while - // still emitting the correct absolute path for CodeView. - ( - working_directory.to_string_lossy(FileNameDisplayPreference::Remapped), - rel_path.to_string_lossy().into_owned(), - ) - } else { - ("".into(), abs_path.to_string_lossy().into_owned()) - } + if let Ok(rel_path) = embeddable_name.strip_prefix(working_directory) { + // If the compiler's working directory (which also is the DW_AT_comp_dir of + // the compilation unit) is a prefix of the path we are about to emit, then + // only emit the part relative to the working directory. Because of path + // remapping we sometimes see strange things here: `abs_path` might + // actually look like a relative path (e.g. + // `/src/lib.rs`), so if we emit it without taking + // the working directory into account, downstream tooling will interpret it + // as `//src/lib.rs`, which + // makes no sense. Usually in such cases the working directory will also be + // remapped to `` or some other prefix of the path + // we are remapping, so we end up with + // `//src/lib.rs`. + // + // By moving the working directory portion into the `directory` part of the + // DIFile, we allow LLVM to emit just the relative path for DWARF, while + // still emitting the correct absolute path for CodeView. + (working_directory.to_string_lossy(), rel_path.to_string_lossy().into_owned()) } else { - let working_directory = working_directory.local_path_if_available(); - let filename = filename.local_path_if_available(); - - debug!(?working_directory, ?filename); - - let abs_path: Cow<'_, Path> = if filename.is_absolute() { - filename.into() - } else { - let mut p = PathBuf::new(); - p.push(working_directory); - p.push(filename); - p.into() - }; - - if let Ok(rel_path) = abs_path.strip_prefix(working_directory) { - ( - working_directory.to_string_lossy(), - rel_path.to_string_lossy().into_owned(), - ) - } else { - ("".into(), abs_path.to_string_lossy().into_owned()) - } + ("".into(), embeddable_name.to_string_lossy().into_owned()) } } other => { debug!(?other); - ("".into(), other.display(filename_display_preference).to_string()) + ("".into(), other.display(RemapPathScopeComponents::DEBUGINFO).to_string()) } }; @@ -889,12 +846,10 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( codegen_unit_name: &str, debug_context: &CodegenUnitDebugContext<'ll, 'tcx>, ) -> &'ll DIDescriptor { - use rustc_session::RemapFileNameExt; - use rustc_session::config::RemapPathScopeComponents; let mut name_in_debuginfo = tcx .sess .local_crate_source_file() - .map(|src| src.for_scope(&tcx.sess, RemapPathScopeComponents::DEBUGINFO).to_path_buf()) + .map(|src| src.path(RemapPathScopeComponents::DEBUGINFO).to_path_buf()) .unwrap_or_else(|| PathBuf::from(tcx.crate_name(LOCAL_CRATE).as_str())); // To avoid breaking split DWARF, we need to ensure that each codegen unit @@ -923,12 +878,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( let producer = format!("clang LLVM ({rustc_producer})"); let name_in_debuginfo = name_in_debuginfo.to_string_lossy(); - let work_dir = tcx - .sess - .opts - .working_dir - .for_scope(tcx.sess, RemapPathScopeComponents::DEBUGINFO) - .to_string_lossy(); + let work_dir = tcx.sess.psess.source_map().working_dir(); let output_filenames = tcx.output_filenames(()); let split_name = if tcx.sess.target_can_use_split_dwarf() && let Some(f) = output_filenames.split_dwarf_path( @@ -938,14 +888,15 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( tcx.sess.invocation_temp.as_deref(), ) { // We get a path relative to the working directory from split_dwarf_path - Some(tcx.sess.source_map().path_mapping().to_real_filename(f)) + Some(tcx.sess.source_map().path_mapping().to_real_filename(work_dir, f)) } else { None }; let split_name = split_name .as_ref() - .map(|f| f.for_scope(tcx.sess, RemapPathScopeComponents::DEBUGINFO).to_string_lossy()) + .map(|f| f.path(RemapPathScopeComponents::DEBUGINFO).to_string_lossy()) .unwrap_or_default(); + let work_dir = work_dir.path(RemapPathScopeComponents::DEBUGINFO).to_string_lossy(); let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo); let dwarf_version = tcx.sess.dwarf_version(); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index fccb6b171b1c..0c677b34df7b 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -208,15 +208,10 @@ fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) { let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); - use rustc_session::RemapFileNameExt; - use rustc_session::config::RemapPathScopeComponents; + use rustc_span::RemapPathScopeComponents; ( Symbol::intern( - &caller - .file - .name - .for_scope(self.tcx.sess, RemapPathScopeComponents::DIAGNOSTICS) - .to_string_lossy(), + &caller.file.name.display(RemapPathScopeComponents::DIAGNOSTICS).to_string_lossy(), ), u32::try_from(caller.line).unwrap(), u32::try_from(caller.col_display).unwrap().checked_add(1).unwrap(), diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 1604b704033b..962d035db862 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -181,7 +181,7 @@ fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { } fn get_source(sess: &Session) -> (String, FileName) { - let src_name = sess.io.input.source_name(); + let src_name = sess.io.input.file_name(&sess); let src = String::clone( sess.source_map() .get_source_file(&src_name) diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index ce5c830bbfcd..3b8c8baa5eff 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -11,7 +11,7 @@ use std::error::Report; use std::io::{self, Write}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; use std::vec; @@ -20,9 +20,9 @@ use rustc_data_structures::sync::IntoDynSyncSend; use rustc_error_messages::FluentArgs; use rustc_lint_defs::Applicability; -use rustc_span::Span; use rustc_span::hygiene::ExpnData; use rustc_span::source_map::{FilePathMapping, SourceMap}; +use rustc_span::{FileName, RealFileName, Span}; use serde::Serialize; use crate::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; @@ -490,8 +490,14 @@ fn from_span_full( None => { span = rustc_span::DUMMY_SP; empty_source_map = Arc::new(SourceMap::new(FilePathMapping::empty())); - empty_source_map - .new_source_file(std::path::PathBuf::from("empty.rs").into(), String::new()); + empty_source_map.new_source_file( + FileName::Real( + empty_source_map + .path_mapping() + .to_real_filename(&RealFileName::empty(), PathBuf::from("empty.rs")), + ), + String::new(), + ); &empty_source_map } }; diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs index 79bb5054dfef..30be06ae0bd3 100644 --- a/compiler/rustc_errors/src/json/tests.rs +++ b/compiler/rustc_errors/src/json/tests.rs @@ -36,11 +36,15 @@ fn flush(&mut self) -> io::Result<()> { } } +fn filename(sm: &SourceMap, path: &str) -> FileName { + FileName::Real(sm.path_mapping().to_real_filename(sm.working_dir(), PathBuf::from(path))) +} + /// Test the span yields correct positions in JSON. fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { rustc_span::create_default_session_globals_then(|| { let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); - sm.new_source_file(Path::new("test.rs").to_owned().into(), code.to_owned()); + sm.new_source_file(filename(&sm, "test.rs"), code.to_owned()); let translator = Translator::with_fallback_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false); diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 33431556c76c..6422779e13c9 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -470,7 +470,7 @@ pub fn expand_crate(&mut self, krate: ast::Crate) -> ast::Crate { FileName::Real(name) => name .into_local_path() .expect("attempting to resolve a file path in an external file"), - other => PathBuf::from(other.prefer_local().to_string()), + other => PathBuf::from(other.prefer_local_unconditionally().to_string()), }; let dir_path = file_path.parent().unwrap_or(&file_path).to_owned(); self.cx.root_path = dir_path.clone(); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index ddfec9f886a6..9acb69f5940d 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -40,8 +40,7 @@ use rustc_session::parse::feature_err; use rustc_session::search_paths::PathKind; use rustc_span::{ - DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, - Symbol, sym, + DUMMY_SP, ErrorGuaranteed, ExpnKind, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym, }; use rustc_trait_selection::{solve, traits}; use tracing::{info, instrument}; @@ -595,7 +594,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P .filter(|fmap| !fmap.is_imported()) .map(|fmap| { ( - escape_dep_filename(&fmap.name.prefer_local().to_string()), + escape_dep_filename(&fmap.name.prefer_local_unconditionally().to_string()), // This needs to be unnormalized, // as external tools wouldn't know how rustc normalizes them fmap.unnormalized_source_len as u64, @@ -610,10 +609,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P // (e.g. accessed in proc macros). let file_depinfo = sess.psess.file_depinfo.borrow(); - let normalize_path = |path: PathBuf| { - let file = FileName::from(path); - escape_dep_filename(&file.prefer_local().to_string()) - }; + let normalize_path = |path: PathBuf| escape_dep_filename(&path.to_string_lossy()); // The entries will be used to declare dependencies between files in a // Makefile-like output, so the iteration order does not matter. diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 65cbdc675962..0a6e5f153dde 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -33,8 +33,8 @@ use rustc_session::cstore::{CrateSource, ExternCrate}; use rustc_span::hygiene::HygieneDecodeContext; use rustc_span::{ - BlobDecoder, BytePos, ByteSymbol, DUMMY_SP, Pos, SpanData, SpanDecoder, Symbol, SyntaxContext, - kw, + BlobDecoder, BytePos, ByteSymbol, DUMMY_SP, Pos, RemapPathScopeComponents, SpanData, + SpanDecoder, Symbol, SyntaxContext, kw, }; use tracing::debug; @@ -1669,15 +1669,15 @@ fn filter<'a>( for virtual_dir in virtual_source_base_dir.iter().flatten() { if let Some(real_dir) = &real_source_base_dir && let rustc_span::FileName::Real(old_name) = name - && let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } = - old_name - && let Ok(rest) = virtual_name.strip_prefix(virtual_dir) + && let (_working_dir, embeddable_name) = + old_name.embeddable_name(RemapPathScopeComponents::MACRO) + && let Ok(rest) = embeddable_name.strip_prefix(virtual_dir) { let new_path = real_dir.join(rest); debug!( "try_to_translate_virtual_to_real: `{}` -> `{}`", - virtual_name.display(), + embeddable_name.display(), new_path.display(), ); @@ -1686,17 +1686,12 @@ fn filter<'a>( // Note that this is a special case for imported rust-src paths specified by // https://rust-lang.github.io/rfcs/3127-trim-paths.html#handling-sysroot-paths. // Other imported paths are not currently remapped (see #66251). - let (user_remapped, applied) = - tcx.sess.source_map().path_mapping().map_prefix(&new_path); - let new_name = if applied { - rustc_span::RealFileName::Remapped { - local_path: Some(new_path.clone()), - virtual_name: user_remapped.to_path_buf(), - } - } else { - rustc_span::RealFileName::LocalPath(new_path) - }; - *old_name = new_name; + *name = rustc_span::FileName::Real( + tcx.sess + .source_map() + .path_mapping() + .to_real_filename(&rustc_span::RealFileName::empty(), new_path), + ); } } }; @@ -1711,15 +1706,12 @@ fn filter<'a>( && let Some(real_dir) = real_source_base_dir && let rustc_span::FileName::Real(old_name) = name { - let relative_path = match old_name { - rustc_span::RealFileName::LocalPath(local) => { - local.strip_prefix(real_dir).ok() - } - rustc_span::RealFileName::Remapped { virtual_name, .. } => { - virtual_source_base_dir - .and_then(|virtual_dir| virtual_name.strip_prefix(virtual_dir).ok()) - } - }; + let (_working_dir, embeddable_path) = + old_name.embeddable_name(RemapPathScopeComponents::MACRO); + let relative_path = embeddable_path.strip_prefix(real_dir).ok().or_else(|| { + virtual_source_base_dir + .and_then(|virtual_dir| embeddable_path.strip_prefix(virtual_dir).ok()) + }); debug!( ?relative_path, ?virtual_dir, @@ -1727,10 +1719,10 @@ fn filter<'a>( "simulate_remapped_rust_src_base" ); if let Some(rest) = relative_path.and_then(|p| p.strip_prefix(subdir).ok()) { - *old_name = rustc_span::RealFileName::Remapped { - local_path: None, - virtual_name: virtual_dir.join(subdir).join(rest), - }; + *name = + rustc_span::FileName::Real(rustc_span::RealFileName::from_virtual_path( + &virtual_dir.join(subdir).join(rest), + )) } } }; diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 2069c06c3f77..b583c73b5a6b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -541,8 +541,6 @@ fn encode_source_map(&mut self) -> LazyTable LazyTable { - let adapted_file_name = source_map - .path_mapping() - .to_embeddable_absolute_path(original_file_name.clone(), working_directory); - + let mut adapted_file_name = original_file_name.clone(); + adapted_file_name.update_for_crate_metadata(); adapted_source_file.name = FileName::Real(adapted_file_name); } _ => { diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 6985cc7ddcfa..fe352df3b9f0 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -3,9 +3,7 @@ use rustc_abi::{HasDataLayout, Size}; use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -use rustc_session::RemapFileNameExt; -use rustc_session::config::RemapPathScopeComponents; -use rustc_span::{DUMMY_SP, Span, Symbol}; +use rustc_span::{DUMMY_SP, RemapPathScopeComponents, Span, Symbol}; use rustc_type_ir::TypeVisitableExt; use super::interpret::ReportedErrorInfo; @@ -587,11 +585,7 @@ pub fn span_as_caller_location(self, span: Span) -> ConstValue { let caller = self.sess.source_map().lookup_char_pos(topmost.lo()); self.const_caller_location( Symbol::intern( - &caller - .file - .name - .for_scope(self.sess, RemapPathScopeComponents::MACRO) - .to_string_lossy(), + &caller.file.name.display(RemapPathScopeComponents::MACRO).to_string_lossy(), ), caller.line as u32, caller.col_display as u32 + 1, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 798e14c6f378..c4f2917ad9e5 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -16,7 +16,7 @@ use rustc_hir::limit::Limit; use rustc_macros::{Lift, extension}; use rustc_session::cstore::{ExternCrate, ExternCrateSource}; -use rustc_span::{FileNameDisplayPreference, Ident, Symbol, kw, sym}; +use rustc_span::{Ident, RemapPathScopeComponents, Symbol, kw, sym}; use rustc_type_ir::{Upcast as _, elaborate}; use smallvec::SmallVec; @@ -890,7 +890,7 @@ fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> { "@{}", // This may end up in stderr diagnostics but it may also be emitted // into MIR. Hence we use the remapped path if available - self.tcx().sess.source_map().span_to_embeddable_string(span) + self.tcx().sess.source_map().span_to_diagnostic_string(span) )?; } else { write!(self, "@")?; @@ -921,7 +921,7 @@ fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> { "@{}", // This may end up in stderr diagnostics but it may also be emitted // into MIR. Hence we use the remapped path if available - self.tcx().sess.source_map().span_to_embeddable_string(span) + self.tcx().sess.source_map().span_to_diagnostic_string(span) )?; } else { write!(self, "@")?; @@ -947,10 +947,13 @@ fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> { self.print_def_path(did.to_def_id(), args)?; } else { let span = self.tcx().def_span(did); - let preference = if with_forced_trimmed_paths() { - FileNameDisplayPreference::Short + let loc = if with_forced_trimmed_paths() { + self.tcx().sess.source_map().span_to_short_string( + span, + RemapPathScopeComponents::DIAGNOSTICS, + ) } else { - FileNameDisplayPreference::Remapped + self.tcx().sess.source_map().span_to_diagnostic_string(span) }; write!( self, @@ -958,7 +961,7 @@ fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> { // This may end up in stderr diagnostics but it may also be // emitted into MIR. Hence we use the remapped path if // available - self.tcx().sess.source_map().span_to_string(span, preference) + loc )?; } } else { @@ -1004,18 +1007,17 @@ fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> { self.print_def_path(did.to_def_id(), args)?; } else { let span = self.tcx().def_span(did); - let preference = if with_forced_trimmed_paths() { - FileNameDisplayPreference::Short + // This may end up in stderr diagnostics but it may also be emitted + // into MIR. Hence we use the remapped path if available + let loc = if with_forced_trimmed_paths() { + self.tcx().sess.source_map().span_to_short_string( + span, + RemapPathScopeComponents::DIAGNOSTICS, + ) } else { - FileNameDisplayPreference::Remapped + self.tcx().sess.source_map().span_to_diagnostic_string(span) }; - write!( - self, - "@{}", - // This may end up in stderr diagnostics but it may also be emitted - // into MIR. Hence we use the remapped path if available - self.tcx().sess.source_map().span_to_string(span, preference) - )?; + write!(self, "@{loc}")?; } } else { write!(self, "@")?; @@ -2258,7 +2260,7 @@ fn print_def_path( "", // This may end up in stderr diagnostics but it may also be emitted // into MIR. Hence we use the remapped path if available - self.tcx.sess.source_map().span_to_embeddable_string(span) + self.tcx.sess.source_map().span_to_diagnostic_string(span) )?; self.empty_path = false; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 0992bee32f32..df8f970e0599 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -129,7 +129,13 @@ pub fn utf8_error( note.clone() }; let contents = String::from_utf8_lossy(contents).to_string(); - let source = sm.new_source_file(PathBuf::from(path).into(), contents); + + // We only emit this error for files in the current session + // so the working directory can only be the current working directory + let filename = FileName::Real( + sm.path_mapping().to_real_filename(sm.working_dir(), PathBuf::from(path).as_path()), + ); + let source = sm.new_source_file(filename, contents); // Avoid out-of-bounds span from lossy UTF-8 conversion. if start as u32 > source.normalized_source_len.0 { diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 9b157cb6c7bf..a46fcd30fef4 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -2,7 +2,7 @@ use std::assert_matches::assert_matches; use std::io::prelude::*; use std::iter::Peekable; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::{io, str}; @@ -29,11 +29,15 @@ fn psess() -> ParseSess { ParseSess::new(vec![crate::DEFAULT_LOCALE_RESOURCE]) } +fn filename(sm: &SourceMap, path: &str) -> FileName { + FileName::Real(sm.path_mapping().to_real_filename(sm.working_dir(), PathBuf::from(path))) +} + /// Map string to parser (via tts). fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> { unwrap_or_emit_fatal(new_parser_from_source_str( psess, - PathBuf::from("bogofile").into(), + filename(psess.source_map(), "bogofile"), source_str, StripTokens::Nothing, )) @@ -100,7 +104,7 @@ pub(crate) fn string_to_stream(source_str: String) -> TokenStream { let psess = psess(); unwrap_or_emit_fatal(source_str_to_stream( &psess, - PathBuf::from("bogofile").into(), + filename(psess.source_map(), "bogofile"), source_str, None, )) @@ -194,8 +198,7 @@ fn test_harness( (OutputTheme::Unicode, expected_output_unicode), ] { let (dcx, source_map, output) = create_test_handler(theme); - source_map - .new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned()); + source_map.new_source_file(filename(&source_map, "test.rs"), file_text.to_owned()); let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end); let mut msp = MultiSpan::from_span(primary_span); @@ -2525,7 +2528,7 @@ fn parse_expr_from_source_str( create_default_session_globals_then(|| { let psess = psess(); let expr = parse_expr_from_source_str( - PathBuf::from("foo").into(), + filename(psess.source_map(), "foo"), "foo!( fn main() { body } )".to_string(), &psess, ) @@ -2888,10 +2891,11 @@ fn debug_lookahead() { #[test] fn out_of_line_mod() { create_default_session_globals_then(|| { + let psess = psess(); let item = parse_item_from_source_str( - PathBuf::from("foo").into(), + filename(psess.source_map(), "foo"), "mod foo { struct S; mod this_does_not_exist; }".to_owned(), - &psess(), + &psess, ) .unwrap() .unwrap(); diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 8ed2c2a89266..c02a01c1b823 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -6,9 +6,8 @@ use rustc_hir::{CRATE_HIR_ID, ItemId, Node, find_attr}; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_session::RemapFileNameExt; -use rustc_session::config::{CrateType, EntryFnType, RemapPathScopeComponents, sigpipe}; -use rustc_span::{Span, sym}; +use rustc_session::config::{CrateType, EntryFnType, sigpipe}; +use rustc_span::{RemapPathScopeComponents, Span, sym}; use crate::errors::{ExternMain, MultipleRustcMain, NoMainErr}; @@ -115,7 +114,7 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) { let filename = tcx .sess .local_crate_source_file() - .map(|src| src.for_scope(&tcx.sess, RemapPathScopeComponents::DIAGNOSTICS).to_path_buf()) + .map(|src| src.path(RemapPathScopeComponents::DIAGNOSTICS).to_path_buf()) .unwrap_or_else(|| { has_filename = false; Default::default() diff --git a/compiler/rustc_public_bridge/src/context/impls.rs b/compiler/rustc_public_bridge/src/context/impls.rs index 26728a34b84a..56aa22378072 100644 --- a/compiler/rustc_public_bridge/src/context/impls.rs +++ b/compiler/rustc_public_bridge/src/context/impls.rs @@ -23,7 +23,7 @@ use rustc_middle::{mir, ty}; use rustc_session::cstore::ForeignModule; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc_span::{FileNameDisplayPreference, Span, Symbol}; +use rustc_span::{Span, Symbol}; use rustc_target::callconv::FnAbi; use super::{AllocRangeHelpers, CompilerCtxt, TyHelpers, TypingEnvHelpers}; @@ -324,12 +324,7 @@ pub fn span_to_string(&self, span: Span) -> String { /// Return filename from given `Span`, for diagnostic purposes. pub fn get_filename(&self, span: Span) -> String { - self.tcx - .sess - .source_map() - .span_to_filename(span) - .display(FileNameDisplayPreference::Local) - .to_string() + self.tcx.sess.source_map().span_to_filename(span).prefer_local_unconditionally().to_string() } /// Return lines corresponding to this `Span`. diff --git a/compiler/rustc_resolve/src/rustdoc/tests.rs b/compiler/rustc_resolve/src/rustdoc/tests.rs index 9fea6f6807e4..7ad0a5003e4b 100644 --- a/compiler/rustc_resolve/src/rustdoc/tests.rs +++ b/compiler/rustc_resolve/src/rustdoc/tests.rs @@ -2,14 +2,18 @@ use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::symbol::sym; -use rustc_span::{BytePos, DUMMY_SP, Span}; +use rustc_span::{BytePos, DUMMY_SP, FileName, Span}; use super::{DocFragment, DocFragmentKind, source_span_for_markdown_range_inner}; +fn filename(sm: &SourceMap, path: &str) -> FileName { + FileName::Real(sm.path_mapping().to_real_filename(sm.working_dir(), PathBuf::from(path))) +} + #[test] fn single_backtick() { let sm = SourceMap::new(FilePathMapping::empty()); - sm.new_source_file(PathBuf::from("foo.rs").into(), r#"#[doc = "`"] fn foo() {}"#.to_string()); + sm.new_source_file(filename(&sm, "foo.rs"), r#"#[doc = "`"] fn foo() {}"#.to_string()); let (span, _) = source_span_for_markdown_range_inner( &sm, "`", @@ -32,7 +36,7 @@ fn single_backtick() { fn utf8() { // regression test for https://github.com/rust-lang/rust/issues/141665 let sm = SourceMap::new(FilePathMapping::empty()); - sm.new_source_file(PathBuf::from("foo.rs").into(), r#"#[doc = "⚠"] fn foo() {}"#.to_string()); + sm.new_source_file(filename(&sm, "foo.rs"), r#"#[doc = "⚠"] fn foo() {}"#.to_string()); let (span, _) = source_span_for_markdown_range_inner( &sm, "⚠", diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 0516982aeabb..aebac3880d2f 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" getopts = "0.2" rand = "0.9.0" rustc_abi = { path = "../rustc_abi" } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 35d9b77f2ea8..b5b19c64951b 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -24,10 +24,7 @@ use rustc_macros::{BlobDecodable, Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::{DEFAULT_EDITION, EDITION_NAME_LIST, Edition, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; -use rustc_span::{ - FileName, FileNameDisplayPreference, FileNameEmbeddablePreference, RealFileName, - SourceFileHashAlgorithm, Symbol, sym, -}; +use rustc_span::{FileName, SourceFileHashAlgorithm, Symbol, sym}; use rustc_target::spec::{ FramePointer, LinkSelfContainedComponents, LinkerFeatures, PanicStrategy, SplitDebuginfo, Target, TargetTuple, @@ -1022,9 +1019,15 @@ pub fn filestem(&self) -> &str { "rust_out" } - pub fn source_name(&self) -> FileName { + pub fn file_name(&self, session: &Session) -> FileName { match *self { - Input::File(ref ifile) => ifile.clone().into(), + Input::File(ref ifile) => FileName::Real( + session + .psess + .source_map() + .path_mapping() + .to_real_filename(session.psess.source_map().working_dir(), ifile.as_path()), + ), Input::Str { ref name, .. } => name.clone(), } } @@ -1312,25 +1315,6 @@ pub fn split_dwarf_path( } } -bitflags::bitflags! { - /// Scopes used to determined if it need to apply to --remap-path-prefix - #[derive(Clone, Copy, PartialEq, Eq, Hash)] - pub struct RemapPathScopeComponents: u8 { - /// Apply remappings to the expansion of std::file!() macro - const MACRO = 1 << 0; - /// Apply remappings to printed compiler diagnostics - const DIAGNOSTICS = 1 << 1; - /// Apply remappings to debug information - const DEBUGINFO = 1 << 3; - /// Apply remappings to coverage information - const COVERAGE = 1 << 4; - - /// An alias for `macro`, `debuginfo` and `coverage`. This ensures all paths in compiled - /// executables, libraries and objects are remapped but not elsewhere. - const OBJECT = Self::MACRO.bits() | Self::DEBUGINFO.bits() | Self::COVERAGE.bits(); - } -} - #[derive(Clone, Debug)] pub struct Sysroot { pub explicit: Option, @@ -1369,21 +1353,7 @@ fn file_path_mapping( remap_path_prefix: Vec<(PathBuf, PathBuf)>, unstable_opts: &UnstableOptions, ) -> FilePathMapping { - FilePathMapping::new( - remap_path_prefix.clone(), - if unstable_opts.remap_path_scope.contains(RemapPathScopeComponents::DIAGNOSTICS) - && !remap_path_prefix.is_empty() - { - FileNameDisplayPreference::Remapped - } else { - FileNameDisplayPreference::Local - }, - if unstable_opts.remap_path_scope.is_all() { - FileNameEmbeddablePreference::RemappedOnly - } else { - FileNameEmbeddablePreference::LocalAndRemapped - }, - ) + FilePathMapping::new(remap_path_prefix.clone(), unstable_opts.remap_path_scope) } impl Default for Options { @@ -3115,8 +3085,8 @@ pub(crate) mod dep_tracking { use rustc_errors::LanguageIdentifier; use rustc_feature::UnstableFeatures; use rustc_hashes::Hash64; - use rustc_span::RealFileName; use rustc_span::edition::Edition; + use rustc_span::{RealFileName, RemapPathScopeComponents}; use rustc_target::spec::{ CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTuple, @@ -3128,9 +3098,9 @@ pub(crate) mod dep_tracking { CoverageOptions, CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OptLevel, - OutFileName, OutputType, OutputTypes, PatchableFunctionEntry, Polonius, - RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, - SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, + OutFileName, OutputType, OutputTypes, PatchableFunctionEntry, Polonius, ResolveDocLinks, + SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, + WasiExecModel, }; use crate::lint; use crate::utils::NativeLib; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 92dd4a23125c..d7ac39ecc9e8 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -12,7 +12,7 @@ use rustc_hashes::Hash64; use rustc_macros::{BlobDecodable, Encodable}; use rustc_span::edition::Edition; -use rustc_span::{RealFileName, SourceFileHashAlgorithm}; +use rustc_span::{RemapPathScopeComponents, SourceFileHashAlgorithm}; use rustc_target::spec::{ CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index acc65fc11a2a..14b80099bafe 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,5 +1,5 @@ use std::any::Any; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::str::FromStr; use std::sync::Arc; use std::sync::atomic::AtomicBool; @@ -28,7 +28,7 @@ pub use rustc_span::def_id::StableCrateId; use rustc_span::edition::Edition; use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{FileNameDisplayPreference, RealFileName, Span, Symbol}; +use rustc_span::{RealFileName, Span, Symbol}; use rustc_target::asm::InlineAsmArch; use rustc_target::spec::{ Arch, CodeModel, DebuginfoKind, Os, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, @@ -40,8 +40,7 @@ pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use crate::config::{ self, CoverageLevel, CoverageOptions, CrateType, DebugInfo, ErrorOutputType, FunctionReturn, - Input, InstrumentCoverage, OptLevel, OutFileName, OutputType, RemapPathScopeComponents, - SwitchWithOptPath, + Input, InstrumentCoverage, OptLevel, OutFileName, OutputType, SwitchWithOptPath, }; use crate::filesearch::FileSearch; use crate::lint::LintId; @@ -192,7 +191,11 @@ pub fn miri_unleashed_feature(&self, span: Span, feature_gate: Option) { } pub fn local_crate_source_file(&self) -> Option { - Some(self.source_map().path_mapping().to_real_filename(self.io.input.opt_path()?)) + Some( + self.source_map() + .path_mapping() + .to_real_filename(self.source_map().working_dir(), self.io.input.opt_path()?), + ) } fn check_miri_unleashed_features(&self) -> Option { @@ -846,21 +849,6 @@ pub fn link_dead_code(&self) -> bool { self.opts.cg.link_dead_code.unwrap_or(false) } - pub fn filename_display_preference( - &self, - scope: RemapPathScopeComponents, - ) -> FileNameDisplayPreference { - assert!( - scope.bits().count_ones() == 1, - "one and only one scope should be passed to `Session::filename_display_preference`" - ); - if self.opts.unstable_opts.remap_path_scope.contains(scope) { - FileNameDisplayPreference::Remapped - } else { - FileNameDisplayPreference::Local - } - } - /// Get the deployment target on Apple platforms based on the standard environment variables, /// or fall back to the minimum version supported by `rustc`. /// @@ -1496,46 +1484,3 @@ fn mk_emitter(output: ErrorOutputType) -> Box { }; emitter } - -pub trait RemapFileNameExt { - type Output<'a> - where - Self: 'a; - - /// Returns a possibly remapped filename based on the passed scope and remap cli options. - /// - /// One and only one scope should be passed to this method, it will panic otherwise. - fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_>; -} - -impl RemapFileNameExt for rustc_span::FileName { - type Output<'a> = rustc_span::FileNameDisplay<'a>; - - fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_> { - assert!( - scope.bits().count_ones() == 1, - "one and only one scope should be passed to for_scope" - ); - if sess.opts.unstable_opts.remap_path_scope.contains(scope) { - self.prefer_remapped_unconditionally() - } else { - self.prefer_local() - } - } -} - -impl RemapFileNameExt for rustc_span::RealFileName { - type Output<'a> = &'a Path; - - fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_> { - assert!( - scope.bits().count_ones() == 1, - "one and only one scope should be passed to for_scope" - ); - if sess.opts.unstable_opts.remap_path_scope.contains(scope) { - self.remapped_path_if_available() - } else { - self.local_path_if_available() - } - } -} diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 43a2d692577e..bf0cad63e543 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +bitflags = "2.4.1" blake3 = "1.5.2" derive-where = "1.2.7" indexmap = { version = "2.0.0" } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 6a359c5f4656..49b2e0c1ff1a 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -221,99 +221,227 @@ pub fn with_metavar_spans(f: impl FnOnce(&MetavarSpansMap) -> R) -> R { with_session_globals(|session_globals| f(&session_globals.metavar_spans)) } -// FIXME: We should use this enum or something like it to get rid of the -// use of magic `/rust/1.x/...` paths across the board. +bitflags::bitflags! { + /// Scopes used to determined if it need to apply to `--remap-path-prefix` + #[derive(Debug, Eq, PartialEq, Clone, Copy, Ord, PartialOrd, Hash)] + pub struct RemapPathScopeComponents: u8 { + /// Apply remappings to the expansion of `std::file!()` macro + const MACRO = 1 << 0; + /// Apply remappings to printed compiler diagnostics + const DIAGNOSTICS = 1 << 1; + /// Apply remappings to debug information + const DEBUGINFO = 1 << 3; + /// Apply remappings to coverage information + const COVERAGE = 1 << 4; + + /// An alias for `macro`, `debuginfo` and `coverage`. This ensures all paths in compiled + /// executables, libraries and objects are remapped but not elsewhere. + const OBJECT = Self::MACRO.bits() | Self::DEBUGINFO.bits() | Self::COVERAGE.bits(); + } +} + +impl Encodable for RemapPathScopeComponents { + fn encode(&self, s: &mut E) { + s.emit_u8(self.bits()); + } +} + +impl Decodable for RemapPathScopeComponents { + fn decode(s: &mut D) -> RemapPathScopeComponents { + RemapPathScopeComponents::from_bits(s.read_u8()) + .expect("invalid bits for RemapPathScopeComponents") + } +} + +/// A self-contained "real" filename. +/// +/// It is produced by `SourceMap::to_real_filename`. +/// +/// `RealFileName` represents a filename that may have been (partly) remapped +/// by `--remap-path-prefix` and `-Zremap-path-scope`. +/// +/// It also contains an embedabble component which gives a working directory +/// and a maybe-remapped maybe-aboslote name. This is useful for debuginfo where +/// some formats and tools highly prefer absolute paths. +/// +/// ## Consistency across compiler sessions +/// +/// The type-system, const-eval and other parts of the compiler rely on `FileName` +/// and by extension `RealFileName` to be consistent across compiler sessions. +/// +/// Otherwise unsoudness (like rust-lang/rust#148328) may occur. +/// +/// As such this type is self-sufficient and consistent in it's output. +/// +/// The [`RealFileName::path`] and [`RealFileName::embeddable_name`] methods +/// are guaranteed to always return the same output across compiler sessions. +/// +/// ## Usage +/// +/// Creation of a [`RealFileName`] should be done using +/// [`FilePathMapping::to_real_filename`][rustc_span::source_map::FilePathMapping::to_real_filename]. +/// +/// Retrieving a path can be done in two main ways: +/// - by using [`RealFileName::path`] with a given scope (should be preferred) +/// - or by using [`RealFileName::embeddable_name`] with a given scope #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable, Encodable)] -pub enum RealFileName { - LocalPath(PathBuf), - /// For remapped paths (namely paths into libstd that have been mapped - /// to the appropriate spot on the local host's file system, and local file - /// system paths that have been remapped with `FilePathMapping`), - Remapped { - /// `local_path` is the (host-dependent) local path to the file. This is - /// None if the file was imported from another crate - local_path: Option, - /// `virtual_name` is the stable path rustc will store internally within - /// build artifacts. - virtual_name: PathBuf, - }, +pub struct RealFileName { + /// The local name (always present in the original crate) + local: Option, + /// The maybe remapped part. Correspond to `local` when no remapped happened. + maybe_remapped: InnerRealFileName, + /// The remapped scopes. Any active scope MUST use `maybe_virtual` + scopes: RemapPathScopeComponents, +} + +/// The inner workings of `RealFileName`. +/// +/// It contains the `name`, `working_directory` and `embeddable_name` components. +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable, Encodable, Hash)] +struct InnerRealFileName { + /// The name. + name: PathBuf, + /// The working directory associated with the embeddable name. + working_directory: PathBuf, + /// The embeddable name. + embeddable_name: PathBuf, } impl Hash for RealFileName { fn hash(&self, state: &mut H) { // To prevent #70924 from happening again we should only hash the - // remapped (virtualized) path if that exists. This is because - // virtualized paths to sysroot crates (/rust/$hash or /rust/$version) - // remain stable even if the corresponding local_path changes - self.remapped_path_if_available().hash(state) + // remapped path if that exists. This is because remapped paths to + // sysroot crates (/rust/$hash or /rust/$version) remain stable even + // if the corresponding local path changes. + if !self.scopes.is_all() { + self.local.hash(state); + } + self.maybe_remapped.hash(state); + self.scopes.bits().hash(state); } } impl RealFileName { - /// Returns the path suitable for reading from the file system on the local host, - /// if this information exists. - /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that. - pub fn local_path(&self) -> Option<&Path> { - match self { - RealFileName::LocalPath(p) => Some(p), - RealFileName::Remapped { local_path, virtual_name: _ } => local_path.as_deref(), - } - } - - /// Returns the path suitable for reading from the file system on the local host, - /// if this information exists. - /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that. - pub fn into_local_path(self) -> Option { - match self { - RealFileName::LocalPath(p) => Some(p), - RealFileName::Remapped { local_path: p, virtual_name: _ } => p, - } - } - - /// Returns the path suitable for embedding into build artifacts. This would still - /// be a local path if it has not been remapped. A remapped path will not correspond - /// to a valid file system path: see `local_path_if_available()` for something that - /// is more likely to return paths into the local host file system. - pub fn remapped_path_if_available(&self) -> &Path { - match self { - RealFileName::LocalPath(p) - | RealFileName::Remapped { local_path: _, virtual_name: p } => p, - } - } - - /// Returns the path suitable for reading from the file system on the local host, - /// if this information exists. Otherwise returns the remapped name. - /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that. - pub fn local_path_if_available(&self) -> &Path { - match self { - RealFileName::LocalPath(path) - | RealFileName::Remapped { local_path: None, virtual_name: path } - | RealFileName::Remapped { local_path: Some(path), virtual_name: _ } => path, - } - } - - /// Return the path remapped or not depending on the [`FileNameDisplayPreference`]. + /// Returns the associated path for the given remapping scope. /// - /// For the purpose of this function, local and short preference are equal. - pub fn to_path(&self, display_pref: FileNameDisplayPreference) -> &Path { - match display_pref { - FileNameDisplayPreference::Local | FileNameDisplayPreference::Short => { - self.local_path_if_available() - } - FileNameDisplayPreference::Remapped => self.remapped_path_if_available(), + /// ## Panic + /// + /// Only one scope components can be given to this function. + pub fn path(&self, scope: RemapPathScopeComponents) -> &Path { + assert!( + scope.bits().count_ones() == 1, + "one and only one scope should be passed to `RealFileName::path`: {scope:?}" + ); + if !self.scopes.contains(scope) + && let Some(local_name) = &self.local + { + local_name.name.as_path() + } else { + self.maybe_remapped.name.as_path() } } - pub fn to_string_lossy(&self, display_pref: FileNameDisplayPreference) -> Cow<'_, str> { + /// Returns the working directory and embeddable path for the given remapping scope. + /// + /// Useful for embedding a mostly abosolute path (modulo remapping) in the compiler outputs. + /// + /// The embedabble path is not guaranteed to be an absolute path, nor is it garuenteed + /// that the working directory part is always a prefix of embeddable path. + /// + /// ## Panic + /// + /// Only one scope components can be given to this function. + pub fn embeddable_name(&self, scope: RemapPathScopeComponents) -> (&Path, &Path) { + assert!( + scope.bits().count_ones() == 1, + "one and only one scope should be passed to `RealFileName::embeddable_path`: {scope:?}" + ); + if !self.scopes.contains(scope) + && let Some(local_name) = &self.local + { + (&local_name.working_directory, &local_name.embeddable_name) + } else { + (&self.maybe_remapped.working_directory, &self.maybe_remapped.embeddable_name) + } + } + + /// Returns the path suitable for reading from the file system on the local host, + /// if this information exists. + /// + /// May not exists if the filename was imported from another crate. + pub fn local_path(&self) -> Option<&Path> { + self.local.as_ref().map(|lp| lp.name.as_ref()) + } + + /// Returns the path suitable for reading from the file system on the local host, + /// if this information exists. + /// + /// May not exists if the filename was imported from another crate. + pub fn into_local_path(self) -> Option { + self.local.map(|lp| lp.name) + } + + /// Returns whenever the filename was remapped. + pub(crate) fn was_remapped(&self) -> bool { + !self.scopes.is_empty() + } + + /// Returns an empty `RealFileName` + /// + /// Useful as the working directory input to `SourceMap::to_real_filename`. + pub fn empty() -> RealFileName { + RealFileName { + local: Some(InnerRealFileName { + name: PathBuf::new(), + working_directory: PathBuf::new(), + embeddable_name: PathBuf::new(), + }), + maybe_remapped: InnerRealFileName { + name: PathBuf::new(), + working_directory: PathBuf::new(), + embeddable_name: PathBuf::new(), + }, + scopes: RemapPathScopeComponents::empty(), + } + } + + /// Returns a `RealFileName` that is completely remapped without any local components. + /// + /// Only exposed for the purpose of `-Zsimulate-remapped-rust-src-base`. + pub fn from_virtual_path(path: &Path) -> RealFileName { + let name = InnerRealFileName { + name: path.to_owned(), + embeddable_name: path.to_owned(), + working_directory: PathBuf::new(), + }; + RealFileName { local: None, maybe_remapped: name, scopes: RemapPathScopeComponents::all() } + } + + /// Update the filename for encoding in the crate metadata. + /// + /// Currently it's about removing the local part when the filename + /// is fully remapped. + pub fn update_for_crate_metadata(&mut self) { + if self.scopes.is_all() { + self.local = None; + } + } + + /// Internal routine to display the filename. + /// + /// Users should always use the `RealFileName::path` method or `FileName` methods instead. + fn to_string_lossy<'a>(&'a self, display_pref: FileNameDisplayPreference) -> Cow<'a, str> { match display_pref { - FileNameDisplayPreference::Local => self.local_path_if_available().to_string_lossy(), - FileNameDisplayPreference::Remapped => { - self.remapped_path_if_available().to_string_lossy() + FileNameDisplayPreference::Remapped => self.maybe_remapped.name.to_string_lossy(), + FileNameDisplayPreference::Local => { + self.local.as_ref().unwrap_or(&self.maybe_remapped).name.to_string_lossy() } FileNameDisplayPreference::Short => self - .local_path_if_available() + .maybe_remapped + .name .file_name() .map_or_else(|| "".into(), |f| f.to_string_lossy()), + FileNameDisplayPreference::Scope(scope) => self.path(scope).to_string_lossy(), } } } @@ -339,40 +467,20 @@ pub enum FileName { InlineAsm(Hash64), } -impl From for FileName { - fn from(p: PathBuf) -> Self { - FileName::Real(RealFileName::LocalPath(p)) - } -} - -#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] -pub enum FileNameEmbeddablePreference { - /// If a remapped path is available, only embed the `virtual_path` and omit the `local_path`. - /// - /// Otherwise embed the local-path into the `virtual_path`. - RemappedOnly, - /// Embed the original path as well as its remapped `virtual_path` component if available. - LocalAndRemapped, -} - -#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] -pub enum FileNameDisplayPreference { - /// Display the path after the application of rewrite rules provided via `--remap-path-prefix`. - /// This is appropriate for paths that get embedded into files produced by the compiler. - Remapped, - /// Display the path before the application of rewrite rules provided via `--remap-path-prefix`. - /// This is appropriate for use in user-facing output (such as diagnostics). - Local, - /// Display only the filename, as a way to reduce the verbosity of the output. - /// This is appropriate for use in user-facing output (such as diagnostics). - Short, -} - pub struct FileNameDisplay<'a> { inner: &'a FileName, display_pref: FileNameDisplayPreference, } +// Internal enum. Should not be exposed. +#[derive(Clone, Copy)] +enum FileNameDisplayPreference { + Remapped, + Local, + Short, + Scope(RemapPathScopeComponents), +} + impl fmt::Display for FileNameDisplay<'_> { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use FileName::*; @@ -417,18 +525,30 @@ pub fn is_real(&self) -> bool { } } + /// Returns the path suitable for reading from the file system on the local host, + /// if this information exists. + /// + /// Avoid embedding this in build artifacts. Prefer using the `display` method. pub fn prefer_remapped_unconditionally(&self) -> FileNameDisplay<'_> { FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Remapped } } - /// This may include transient local filesystem information. - /// Must not be embedded in build outputs. - pub fn prefer_local(&self) -> FileNameDisplay<'_> { + /// Returns the path suitable for reading from the file system on the local host, + /// if this information exists. + /// + /// Avoid embedding this in build artifacts. Prefer using the `display` method. + pub fn prefer_local_unconditionally(&self) -> FileNameDisplay<'_> { FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Local } } - pub fn display(&self, display_pref: FileNameDisplayPreference) -> FileNameDisplay<'_> { - FileNameDisplay { inner: self, display_pref } + /// Returns a short (either the filename or an empty string). + pub fn short(&self) -> FileNameDisplay<'_> { + FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Short } + } + + /// Returns a `Display`-able path for the given scope. + pub fn display(&self, scope: RemapPathScopeComponents) -> FileNameDisplay<'_> { + FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Scope(scope) } } pub fn macro_expansion_source_code(src: &str) -> FileName { @@ -473,7 +593,8 @@ pub fn inline_asm_source_code(src: &str) -> FileName { /// Returns the path suitable for reading from the file system on the local host, /// if this information exists. - /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that. + /// + /// Avoid embedding this in build artifacts. pub fn into_local_path(self) -> Option { match self { FileName::Real(path) => path.into_local_path(), diff --git a/compiler/rustc_span/src/profiling.rs b/compiler/rustc_span/src/profiling.rs index c5a8bd3b15be..ab47e441cc35 100644 --- a/compiler/rustc_span/src/profiling.rs +++ b/compiler/rustc_span/src/profiling.rs @@ -2,6 +2,7 @@ use rustc_data_structures::profiling::EventArgRecorder; +use crate::RemapPathScopeComponents; use crate::source_map::SourceMap; /// Extension trait for self-profiling purposes: allows to record spans within a generic activity's @@ -24,6 +25,6 @@ fn record_arg_with_span(&mut self, source_map: &SourceMap, event_arg: A, span A: Borrow + Into, { self.record_arg(event_arg); - self.record_arg(source_map.span_to_embeddable_string(span)); + self.record_arg(source_map.span_to_string(span, RemapPathScopeComponents::DEBUGINFO)); } } diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 090442bf64bd..35694be9e492 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -234,7 +234,7 @@ pub fn with_inputs( let cwd = file_loader .current_directory() .expect("expecting a current working directory to exist"); - let working_dir = cwd.to_path_buf().into(); + let working_dir = path_mapping.to_real_filename(&RealFileName::empty(), &cwd); debug!(?working_dir); SourceMap { files: Default::default(), @@ -260,7 +260,7 @@ pub fn file_exists(&self, path: &Path) -> bool { pub fn load_file(&self, path: &Path) -> io::Result> { let src = self.file_loader.read_file(path)?; - let filename = path.to_owned().into(); + let filename = FileName::Real(self.path_mapping.to_real_filename(&self.working_dir, path)); Ok(self.new_source_file(filename, src)) } @@ -277,7 +277,8 @@ pub fn load_binary_file(&self, path: &Path) -> io::Result<(Arc<[u8]>, Span)> { // via `mod`, so we try to use real file contents and not just an // empty string. let text = std::str::from_utf8(&bytes).unwrap_or("").to_string(); - let file = self.new_source_file(path.to_owned().into(), text); + let filename = FileName::Real(self.path_mapping.to_real_filename(&self.working_dir, path)); + let file = self.new_source_file(filename, text); Ok(( bytes, Span::new( @@ -345,7 +346,6 @@ fn try_new_source_file( // Note that filename may not be a valid path, eg it may be `` etc, // but this is okay because the directory determined by `path.pop()` will // be empty, so the working directory will be used. - let (filename, _) = self.path_mapping.map_filename_prefix(&filename); let stable_id = StableSourceFileId::from_filename_in_current_crate(&filename); match self.source_file_by_stable_id(stable_id) { @@ -444,25 +444,36 @@ pub fn lookup_line(&self, pos: BytePos) -> Result String { + self.span_to_string_ext(sp, display_scope, false) + } + + pub fn span_to_short_string( &self, sp: Span, - filename_display_pref: FileNameDisplayPreference, + display_scope: RemapPathScopeComponents, + ) -> String { + self.span_to_string_ext(sp, display_scope, true) + } + + fn span_to_string_ext( + &self, + sp: Span, + display_scope: RemapPathScopeComponents, + short: bool, ) -> String { let (source_file, lo_line, lo_col, hi_line, hi_col) = self.span_to_location_info(sp); let file_name = match source_file { - Some(sf) => sf.name.display(filename_display_pref).to_string(), + Some(sf) => { + if short { sf.name.short() } else { sf.name.display(display_scope) }.to_string() + } None => return "no-location".to_string(), }; format!( "{file_name}:{lo_line}:{lo_col}{}", - if let FileNameDisplayPreference::Short = filename_display_pref { - String::new() - } else { - format!(": {hi_line}:{hi_col}") - } + if short { String::new() } else { format!(": {hi_line}:{hi_col}") } ) } @@ -479,16 +490,11 @@ pub fn span_to_location_info( (Some(lo.file), lo.line, lo.col.to_usize() + 1, hi.line, hi.col.to_usize() + 1) } - /// Format the span location suitable for embedding in build artifacts - pub fn span_to_embeddable_string(&self, sp: Span) -> String { - self.span_to_string(sp, FileNameDisplayPreference::Remapped) - } - /// Format the span location to be printed in diagnostics. Must not be emitted /// to build artifacts as this may leak local file paths. Use span_to_embeddable_string /// for string suitable for embedding. pub fn span_to_diagnostic_string(&self, sp: Span) -> String { - self.span_to_string(sp, self.path_mapping.filename_display_for_diagnostics) + self.span_to_string(sp, RemapPathScopeComponents::DIAGNOSTICS) } pub fn span_to_filename(&self, sp: Span) -> FileName { @@ -496,7 +502,7 @@ pub fn span_to_filename(&self, sp: Span) -> FileName { } pub fn filename_for_diagnostics<'a>(&self, filename: &'a FileName) -> FileNameDisplay<'a> { - filename.display(self.path_mapping.filename_display_for_diagnostics) + filename.display(RemapPathScopeComponents::DIAGNOSTICS) } pub fn is_multiline(&self, sp: Span) -> bool { @@ -1045,10 +1051,8 @@ fn find_width_of_character_at_span(&self, sp: SpanData, forwards: bool) -> u32 { } pub fn get_source_file(&self, filename: &FileName) -> Option> { - // Remap filename before lookup - let filename = self.path_mapping().map_filename_prefix(filename).0; for sf in self.files.borrow().source_files.iter() { - if filename == sf.name { + if *filename == sf.name { return Some(Arc::clone(&sf)); } } @@ -1080,16 +1084,20 @@ pub fn ensure_source_file_source_present(&self, source_file: &SourceFile) -> boo return None; }; - let local_path: Cow<'_, Path> = match name { - RealFileName::LocalPath(local_path) => local_path.into(), - RealFileName::Remapped { local_path: Some(local_path), .. } => local_path.into(), - RealFileName::Remapped { local_path: None, virtual_name } => { + let local_path: Cow<'_, Path> = match name.local_path() { + Some(local) => local.into(), + None => { // The compiler produces better error messages if the sources of dependencies // are available. Attempt to undo any path mapping so we can find remapped // dependencies. + // // We can only use the heuristic because `add_external_src` checks the file // content hash. - self.path_mapping.reverse_map_prefix_heuristically(virtual_name)?.into() + let maybe_remapped_path = name.path(RemapPathScopeComponents::DIAGNOSTICS); + self.path_mapping + .reverse_map_prefix_heuristically(maybe_remapped_path) + .map(Cow::from) + .unwrap_or(maybe_remapped_path.into()) } }; @@ -1135,35 +1143,25 @@ pub fn get_source_map() -> Option> { #[derive(Clone)] pub struct FilePathMapping { mapping: Vec<(PathBuf, PathBuf)>, - filename_display_for_diagnostics: FileNameDisplayPreference, - filename_embeddable_preference: FileNameEmbeddablePreference, + filename_remapping_scopes: RemapPathScopeComponents, } impl FilePathMapping { pub fn empty() -> FilePathMapping { - FilePathMapping::new( - Vec::new(), - FileNameDisplayPreference::Local, - FileNameEmbeddablePreference::RemappedOnly, - ) + FilePathMapping::new(Vec::new(), RemapPathScopeComponents::empty()) } pub fn new( mapping: Vec<(PathBuf, PathBuf)>, - filename_display_for_diagnostics: FileNameDisplayPreference, - filename_embeddable_preference: FileNameEmbeddablePreference, + filename_remapping_scopes: RemapPathScopeComponents, ) -> FilePathMapping { - FilePathMapping { - mapping, - filename_display_for_diagnostics, - filename_embeddable_preference, - } + FilePathMapping { mapping, filename_remapping_scopes } } /// Applies any path prefix substitution as defined by the mapping. /// The return value is the remapped path and a boolean indicating whether /// the path was affected by the mapping. - pub fn map_prefix<'a>(&'a self, path: impl Into>) -> (Cow<'a, Path>, bool) { + fn map_prefix<'a>(&'a self, path: impl Into>) -> (Cow<'a, Path>, bool) { let path = path.into(); if path.as_os_str().is_empty() { // Exit early if the path is empty and therefore there's nothing to remap. @@ -1209,138 +1207,68 @@ fn remap_path_prefix<'a>( } } - fn map_filename_prefix(&self, file: &FileName) -> (FileName, bool) { - match file { - FileName::Real(realfile) if let RealFileName::LocalPath(local_path) = realfile => { - let (mapped_path, mapped) = self.map_prefix(local_path); - let realfile = if mapped { - RealFileName::Remapped { - local_path: Some(local_path.clone()), - virtual_name: mapped_path.into_owned(), - } - } else { - realfile.clone() - }; - (FileName::Real(realfile), mapped) - } - FileName::Real(_) => unreachable!("attempted to remap an already remapped filename"), - other => (other.clone(), false), - } - } - /// Applies any path prefix substitution as defined by the mapping. - /// The return value is the local path with a "virtual path" representing the remapped - /// part if any remapping was performed. - pub fn to_real_filename<'a>(&self, local_path: impl Into>) -> RealFileName { - let local_path = local_path.into(); - if let (remapped_path, true) = self.map_prefix(&*local_path) { - RealFileName::Remapped { - virtual_name: remapped_path.into_owned(), - local_path: Some(local_path.into_owned()), - } - } else { - RealFileName::LocalPath(local_path.into_owned()) - } - } - - /// Expand a relative path to an absolute path with remapping taken into account. - /// Use this when absolute paths are required (e.g. debuginfo or crate metadata). /// - /// The resulting `RealFileName` will have its `local_path` portion erased if - /// possible (i.e. if there's also a remapped path). - pub fn to_embeddable_absolute_path( + /// The returned filename contains the a remapped path representing the remapped + /// part if any remapping was performed. + pub fn to_real_filename<'a>( &self, - file_path: RealFileName, working_directory: &RealFileName, + local_path: impl Into>, ) -> RealFileName { - match file_path { - // Anything that's already remapped we don't modify, except for erasing - // the `local_path` portion (if desired). - RealFileName::Remapped { local_path, virtual_name } => { - RealFileName::Remapped { - local_path: match self.filename_embeddable_preference { - FileNameEmbeddablePreference::RemappedOnly => None, - FileNameEmbeddablePreference::LocalAndRemapped => local_path, - }, - // We use the remapped name verbatim, even if it looks like a relative - // path. The assumption is that the user doesn't want us to further - // process paths that have gone through remapping. - virtual_name, - } - } + let local_path = local_path.into(); - RealFileName::LocalPath(unmapped_file_path) => { - // If no remapping has been applied yet, try to do so - let (new_path, was_remapped) = self.map_prefix(&unmapped_file_path); - if was_remapped { - // It was remapped, so don't modify further - return RealFileName::Remapped { - virtual_name: new_path.into_owned(), - // But still provide the local path if desired - local_path: match self.filename_embeddable_preference { - FileNameEmbeddablePreference::RemappedOnly => None, - FileNameEmbeddablePreference::LocalAndRemapped => { - Some(unmapped_file_path) - } - }, - }; - } + let (remapped_path, mut was_remapped) = self.map_prefix(&*local_path); + debug!(?local_path, ?remapped_path, ?was_remapped, ?self.filename_remapping_scopes); - if new_path.is_absolute() { - // No remapping has applied to this path and it is absolute, - // so the working directory cannot influence it either, so - // we are done. - return RealFileName::LocalPath(new_path.into_owned()); - } + // Always populate the local part, even if we just remapped it and the scopes are + // total, so that places that load the file from disk still have access to it. + let local = InnerRealFileName { + name: local_path.to_path_buf(), + working_directory: working_directory + .local_path() + .expect("working directory should be local") + .to_path_buf(), + embeddable_name: if local_path.is_absolute() { + local_path.to_path_buf() + } else { + working_directory + .local_path() + .expect("working directory should be local") + .to_path_buf() + .join(&local_path) + }, + }; - debug_assert!(new_path.is_relative()); - let unmapped_file_path_rel = new_path; + RealFileName { + maybe_remapped: InnerRealFileName { + working_directory: working_directory.maybe_remapped.name.clone(), + embeddable_name: if remapped_path.is_absolute() || was_remapped { + // The current directory may have been remapped so we take that + // into account, otherwise we'll forget to include the scopes + was_remapped = was_remapped || working_directory.was_remapped(); - match working_directory { - RealFileName::LocalPath(unmapped_working_dir_abs) => { - let unmapped_file_path_abs = - unmapped_working_dir_abs.join(unmapped_file_path_rel); + remapped_path.to_path_buf() + } else { + // Create an absolute path and remap it as well. + let (abs_path, abs_was_remapped) = self.map_prefix( + working_directory.maybe_remapped.name.clone().join(&remapped_path), + ); - // Although neither `working_directory` nor the file name were subject - // to path remapping, the concatenation between the two may be. Hence - // we need to do a remapping here. - let (file_path_abs, was_remapped) = - self.map_prefix(&unmapped_file_path_abs); - if was_remapped { - RealFileName::Remapped { - virtual_name: file_path_abs.into_owned(), - local_path: match self.filename_embeddable_preference { - FileNameEmbeddablePreference::RemappedOnly => None, - FileNameEmbeddablePreference::LocalAndRemapped => { - Some(unmapped_file_path_abs) - } - }, - } - } else { - // No kind of remapping applied to this path, so - // we leave it as it is. - RealFileName::LocalPath(file_path_abs.into_owned()) - } - } - RealFileName::Remapped { - local_path, - virtual_name: remapped_working_dir_abs, - } => { - // If working_directory has been remapped, then we emit - // Remapped variant as the expanded path won't be valid - RealFileName::Remapped { - virtual_name: Path::new(remapped_working_dir_abs) - .join(&unmapped_file_path_rel), - local_path: match self.filename_embeddable_preference { - FileNameEmbeddablePreference::RemappedOnly => None, - FileNameEmbeddablePreference::LocalAndRemapped => local_path - .as_ref() - .map(|local_path| local_path.join(unmapped_file_path_rel)), - }, - } - } - } - } + // If either the embeddable name or the working directory was + // remapped, then the filename was remapped + was_remapped = abs_was_remapped || working_directory.was_remapped(); + + abs_path.to_path_buf() + }, + name: remapped_path.to_path_buf(), + }, + local: Some(local), + scopes: if was_remapped { + self.filename_remapping_scopes + } else { + RemapPathScopeComponents::empty() + }, } } diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index c919aacf6b5f..16d28f393d7f 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -1,10 +1,14 @@ use super::*; +fn filename(sm: &SourceMap, path: &str) -> FileName { + FileName::Real(sm.path_mapping().to_real_filename(sm.working_dir(), PathBuf::from(path))) +} + fn init_source_map() -> SourceMap { let sm = SourceMap::new(FilePathMapping::empty()); - sm.new_source_file(PathBuf::from("blork.rs").into(), "first line.\nsecond line".to_string()); - sm.new_source_file(PathBuf::from("empty.rs").into(), String::new()); - sm.new_source_file(PathBuf::from("blork2.rs").into(), "first line.\nsecond line".to_string()); + sm.new_source_file(filename(&sm, "blork.rs"), "first line.\nsecond line".to_string()); + sm.new_source_file(filename(&sm, "empty.rs"), String::new()); + sm.new_source_file(filename(&sm, "blork2.rs"), "first line.\nsecond line".to_string()); sm } @@ -59,15 +63,15 @@ fn t3() { let sm = init_source_map(); let srcfbp1 = sm.lookup_byte_offset(BytePos(23)); - assert_eq!(srcfbp1.sf.name, PathBuf::from("blork.rs").into()); + assert_eq!(srcfbp1.sf.name, filename(&sm, "blork.rs")); assert_eq!(srcfbp1.pos, BytePos(23)); let srcfbp1 = sm.lookup_byte_offset(BytePos(24)); - assert_eq!(srcfbp1.sf.name, PathBuf::from("empty.rs").into()); + assert_eq!(srcfbp1.sf.name, filename(&sm, "empty.rs")); assert_eq!(srcfbp1.pos, BytePos(0)); let srcfbp2 = sm.lookup_byte_offset(BytePos(25)); - assert_eq!(srcfbp2.sf.name, PathBuf::from("blork2.rs").into()); + assert_eq!(srcfbp2.sf.name, filename(&sm, "blork2.rs")); assert_eq!(srcfbp2.pos, BytePos(0)); } @@ -89,12 +93,12 @@ fn t5() { let sm = init_source_map(); let loc1 = sm.lookup_char_pos(BytePos(22)); - assert_eq!(loc1.file.name, PathBuf::from("blork.rs").into()); + assert_eq!(loc1.file.name, filename(&sm, "blork.rs")); assert_eq!(loc1.line, 2); assert_eq!(loc1.col, CharPos(10)); let loc2 = sm.lookup_char_pos(BytePos(25)); - assert_eq!(loc2.file.name, PathBuf::from("blork2.rs").into()); + assert_eq!(loc2.file.name, filename(&sm, "blork2.rs")); assert_eq!(loc2.line, 1); assert_eq!(loc2.col, CharPos(0)); } @@ -102,14 +106,8 @@ fn t5() { fn init_source_map_mbc() -> SourceMap { let sm = SourceMap::new(FilePathMapping::empty()); // "€" is a three-byte UTF8 char. - sm.new_source_file( - PathBuf::from("blork.rs").into(), - "fir€st €€€€ line.\nsecond line".to_string(), - ); - sm.new_source_file( - PathBuf::from("blork2.rs").into(), - "first line€€.\n€ second line".to_string(), - ); + sm.new_source_file(filename(&sm, "blork.rs"), "fir€st €€€€ line.\nsecond line".to_string()); + sm.new_source_file(filename(&sm, "blork2.rs"), "first line€€.\n€ second line".to_string()); sm } @@ -138,7 +136,7 @@ fn t7() { let span = Span::with_root_ctxt(BytePos(12), BytePos(23)); let file_lines = sm.span_to_lines(span).unwrap(); - assert_eq!(file_lines.file.name, PathBuf::from("blork.rs").into()); + assert_eq!(file_lines.file.name, filename(&sm, "blork.rs")); assert_eq!(file_lines.lines.len(), 1); assert_eq!(file_lines.lines[0].line_index, 1); } @@ -161,7 +159,7 @@ fn span_to_snippet_and_lines_spanning_multiple_lines() { let sm = SourceMap::new(FilePathMapping::empty()); let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; let selection = " \n ~~\n~~~\n~~~~~ \n \n"; - sm.new_source_file(Path::new("blork.rs").to_owned().into(), inputtext.to_string()); + sm.new_source_file(filename(&sm, "blork.rs"), inputtext.to_string()); let span = span_from_selection(inputtext, selection); // Check that we are extracting the text we thought we were extracting. @@ -204,7 +202,7 @@ fn span_merging_fail() { let inputtext = "bbbb BB\ncc CCC\n"; let selection1 = " ~~\n \n"; let selection2 = " \n ~~~\n"; - sm.new_source_file(Path::new("blork.rs").to_owned().into(), inputtext.to_owned()); + sm.new_source_file(filename(&sm, "blork.rs"), inputtext.to_owned()); let span1 = span_from_selection(inputtext, selection1); let span2 = span_from_selection(inputtext, selection2); @@ -218,7 +216,7 @@ fn t10() { let unnormalized = "first line.\r\nsecond line"; let normalized = "first line.\nsecond line"; - let src_file = sm.new_source_file(PathBuf::from("blork.rs").into(), unnormalized.to_string()); + let src_file = sm.new_source_file(filename(&sm, "blork.rs"), unnormalized.to_string()); assert_eq!(src_file.src.as_ref().unwrap().as_ref(), normalized); assert!( @@ -306,8 +304,7 @@ fn path_prefix_remapping() { { let mapping = &FilePathMapping::new( vec![(path("abc/def"), path("foo"))], - FileNameDisplayPreference::Remapped, - FileNameEmbeddablePreference::RemappedOnly, + RemapPathScopeComponents::all(), ); assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("foo/src/main.rs")); @@ -318,8 +315,7 @@ fn path_prefix_remapping() { { let mapping = &FilePathMapping::new( vec![(path("abc/def"), path("/foo"))], - FileNameDisplayPreference::Remapped, - FileNameEmbeddablePreference::RemappedOnly, + RemapPathScopeComponents::all(), ); assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("/foo/src/main.rs")); @@ -330,8 +326,7 @@ fn path_prefix_remapping() { { let mapping = &FilePathMapping::new( vec![(path("/abc/def"), path("foo"))], - FileNameDisplayPreference::Remapped, - FileNameEmbeddablePreference::RemappedOnly, + RemapPathScopeComponents::all(), ); assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("foo/src/main.rs")); @@ -342,8 +337,7 @@ fn path_prefix_remapping() { { let mapping = &FilePathMapping::new( vec![(path("/abc/def"), path("/foo"))], - FileNameDisplayPreference::Remapped, - FileNameEmbeddablePreference::RemappedOnly, + RemapPathScopeComponents::all(), ); assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("/foo/src/main.rs")); @@ -352,171 +346,322 @@ fn path_prefix_remapping() { } #[test] -fn path_prefix_remapping_expand_to_absolute() { +fn to_real_filename_with_full_scopes() { // "virtual" working directory is relative path let mapping = &FilePathMapping::new( vec![(path("/foo"), path("FOO")), (path("/bar"), path("BAR"))], - FileNameDisplayPreference::Remapped, - FileNameEmbeddablePreference::RemappedOnly, + RemapPathScopeComponents::all(), ); let working_directory = path("/foo"); - let working_directory = RealFileName::Remapped { - local_path: Some(working_directory.clone()), - virtual_name: mapping.map_prefix(working_directory).0.into_owned(), - }; + let working_directory = mapping.to_real_filename(&RealFileName::empty(), working_directory); - assert_eq!(working_directory.remapped_path_if_available(), path("FOO")); + assert_eq!(working_directory.path(RemapPathScopeComponents::DIAGNOSTICS), path("FOO")); + assert_eq!(working_directory.path(RemapPathScopeComponents::MACRO), path("FOO")); + assert_eq!(working_directory.path(RemapPathScopeComponents::DEBUGINFO), path("FOO")); - // Unmapped absolute path + // Absolute path assert_eq!( - mapping.to_embeddable_absolute_path( - RealFileName::LocalPath(path("/foo/src/main.rs")), - &working_directory - ), - RealFileName::Remapped { local_path: None, virtual_name: path("FOO/src/main.rs") } - ); - - // Unmapped absolute path with unrelated working directory - assert_eq!( - mapping.to_embeddable_absolute_path( - RealFileName::LocalPath(path("/bar/src/main.rs")), - &working_directory - ), - RealFileName::Remapped { local_path: None, virtual_name: path("BAR/src/main.rs") } - ); - - // Unmapped absolute path that does not match any prefix - assert_eq!( - mapping.to_embeddable_absolute_path( - RealFileName::LocalPath(path("/quux/src/main.rs")), - &working_directory - ), - RealFileName::LocalPath(path("/quux/src/main.rs")), - ); - - // Unmapped relative path - assert_eq!( - mapping.to_embeddable_absolute_path( - RealFileName::LocalPath(path("src/main.rs")), - &working_directory - ), - RealFileName::Remapped { local_path: None, virtual_name: path("FOO/src/main.rs") } - ); - - // Unmapped relative path with `./` - assert_eq!( - mapping.to_embeddable_absolute_path( - RealFileName::LocalPath(path("./src/main.rs")), - &working_directory - ), - RealFileName::Remapped { local_path: None, virtual_name: path("FOO/src/main.rs") } - ); - - // Unmapped relative path that does not match any prefix - assert_eq!( - mapping.to_embeddable_absolute_path( - RealFileName::LocalPath(path("quux/src/main.rs")), - &RealFileName::LocalPath(path("/abc")), - ), - RealFileName::LocalPath(path("/abc/quux/src/main.rs")), - ); - - // Already remapped absolute path - assert_eq!( - mapping.to_embeddable_absolute_path( - RealFileName::Remapped { - local_path: Some(path("/foo/src/main.rs")), - virtual_name: path("FOO/src/main.rs"), + mapping.to_real_filename(&working_directory, path("/foo/src/main.rs")), + RealFileName { + local: Some(InnerRealFileName { + name: path("/foo/src/main.rs"), + working_directory: path("/foo"), + embeddable_name: path("/foo/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("FOO/src/main.rs"), + working_directory: path("FOO"), + embeddable_name: path("FOO/src/main.rs") }, - &working_directory - ), - RealFileName::Remapped { local_path: None, virtual_name: path("FOO/src/main.rs") } + scopes: RemapPathScopeComponents::all() + } ); - // Already remapped absolute path, with unrelated working directory + // Absolute path with unrelated working directory assert_eq!( - mapping.to_embeddable_absolute_path( - RealFileName::Remapped { - local_path: Some(path("/bar/src/main.rs")), - virtual_name: path("BAR/src/main.rs"), + mapping.to_real_filename(&working_directory, path("/bar/src/main.rs")), + RealFileName { + local: Some(InnerRealFileName { + name: path("/bar/src/main.rs"), + working_directory: path("/foo"), + embeddable_name: path("/bar/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("BAR/src/main.rs"), + working_directory: path("FOO"), + embeddable_name: path("BAR/src/main.rs") }, - &working_directory - ), - RealFileName::Remapped { local_path: None, virtual_name: path("BAR/src/main.rs") } + scopes: RemapPathScopeComponents::all() + } ); - // Already remapped relative path + // Absolute path that does not match any prefix assert_eq!( - mapping.to_embeddable_absolute_path( - RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") }, - &working_directory + mapping.to_real_filename(&working_directory, path("/quux/src/main.rs")), + RealFileName { + local: Some(InnerRealFileName { + name: path("/quux/src/main.rs"), + working_directory: path("/foo"), + embeddable_name: path("/quux/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("/quux/src/main.rs"), + working_directory: path("FOO"), + embeddable_name: path("/quux/src/main.rs") + }, + scopes: RemapPathScopeComponents::all() + } + ); + + // Relative path + assert_eq!( + mapping.to_real_filename(&working_directory, path("src/main.rs")), + RealFileName { + local: Some(InnerRealFileName { + name: path("src/main.rs"), + working_directory: path("/foo"), + embeddable_name: path("/foo/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("src/main.rs"), + working_directory: path("FOO"), + embeddable_name: path("FOO/src/main.rs") + }, + scopes: RemapPathScopeComponents::all() + } + ); + + // Relative path with `./` + assert_eq!( + mapping.to_real_filename(&working_directory, path("./src/main.rs"),), + RealFileName { + local: Some(InnerRealFileName { + name: path("./src/main.rs"), + working_directory: path("/foo"), + embeddable_name: path("/foo/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("./src/main.rs"), + working_directory: path("FOO"), + embeddable_name: path("FOO/src/main.rs") + }, + scopes: RemapPathScopeComponents::all() + } + ); + + // Relative path that does not match any prefix + assert_eq!( + mapping.to_real_filename( + &mapping.to_real_filename(&RealFileName::empty(), path("/abc")), + path("quux/src/main.rs"), ), - RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") } + RealFileName { + local: Some(InnerRealFileName { + name: path("quux/src/main.rs"), + working_directory: path("/abc"), + embeddable_name: path("/abc/quux/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("quux/src/main.rs"), + working_directory: path("/abc"), + embeddable_name: path("/abc/quux/src/main.rs") + }, + scopes: RemapPathScopeComponents::empty() + } ); } #[test] -fn path_prefix_remapping_expand_to_absolute_and_local() { +fn to_real_filename_with_mixed_scopes() { // "virtual" working directory is relative path let mapping = &FilePathMapping::new( vec![(path("/foo"), path("FOO")), (path("/bar"), path("BAR"))], - FileNameDisplayPreference::Remapped, - FileNameEmbeddablePreference::LocalAndRemapped, + RemapPathScopeComponents::OBJECT, ); let working_directory = path("/foo"); - let working_directory = RealFileName::Remapped { - local_path: Some(working_directory.clone()), - virtual_name: mapping.map_prefix(working_directory).0.into_owned(), - }; + let working_directory = mapping.to_real_filename(&RealFileName::empty(), working_directory); - assert_eq!(working_directory.remapped_path_if_available(), path("FOO")); + assert_eq!(working_directory.path(RemapPathScopeComponents::DIAGNOSTICS), path("/foo")); + assert_eq!(working_directory.path(RemapPathScopeComponents::MACRO), path("FOO")); + assert_eq!(working_directory.path(RemapPathScopeComponents::DEBUGINFO), path("FOO")); - // Unmapped absolute path + // Absolute path assert_eq!( - mapping.to_embeddable_absolute_path( - RealFileName::LocalPath(path("/foo/src/main.rs")), - &working_directory - ), - RealFileName::Remapped { - local_path: Some(path("/foo/src/main.rs")), - virtual_name: path("FOO/src/main.rs") - } - ); - - // Unmapped absolute path with unrelated working directory - assert_eq!( - mapping.to_embeddable_absolute_path( - RealFileName::LocalPath(path("/bar/src/main.rs")), - &working_directory - ), - RealFileName::Remapped { - local_path: Some(path("/bar/src/main.rs")), - virtual_name: path("BAR/src/main.rs") - } - ); - - // Already remapped absolute path, with unrelated working directory - assert_eq!( - mapping.to_embeddable_absolute_path( - RealFileName::Remapped { - local_path: Some(path("/bar/src/main.rs")), - virtual_name: path("BAR/src/main.rs"), + mapping.to_real_filename(&working_directory, path("/foo/src/main.rs")), + RealFileName { + local: Some(InnerRealFileName { + name: path("/foo/src/main.rs"), + working_directory: path("/foo"), + embeddable_name: path("/foo/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("FOO/src/main.rs"), + working_directory: path("FOO"), + embeddable_name: path("FOO/src/main.rs") }, - &working_directory - ), - RealFileName::Remapped { - local_path: Some(path("/bar/src/main.rs")), - virtual_name: path("BAR/src/main.rs") + scopes: RemapPathScopeComponents::OBJECT } ); - // Already remapped relative path + // Absolute path with unrelated working directory assert_eq!( - mapping.to_embeddable_absolute_path( - RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") }, - &working_directory + mapping.to_real_filename(&working_directory, path("/bar/src/main.rs")), + RealFileName { + local: Some(InnerRealFileName { + name: path("/bar/src/main.rs"), + working_directory: path("/foo"), + embeddable_name: path("/bar/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("BAR/src/main.rs"), + working_directory: path("FOO"), + embeddable_name: path("BAR/src/main.rs") + }, + scopes: RemapPathScopeComponents::OBJECT + } + ); + + // Absolute path without remapping + assert_eq!( + mapping.to_real_filename(&working_directory, path("/quux/src/main.rs")), + RealFileName { + local: Some(InnerRealFileName { + name: path("/quux/src/main.rs"), + working_directory: path("/foo"), + embeddable_name: path("/quux/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("/quux/src/main.rs"), + working_directory: path("FOO"), + embeddable_name: path("/quux/src/main.rs") + }, + scopes: RemapPathScopeComponents::OBJECT + } + ); + + // Relative path + assert_eq!( + mapping.to_real_filename(&working_directory, path("src/main.rs")), + RealFileName { + local: Some(InnerRealFileName { + name: path("src/main.rs"), + working_directory: path("/foo"), + embeddable_name: path("/foo/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("src/main.rs"), + working_directory: path("FOO"), + embeddable_name: path("FOO/src/main.rs") + }, + scopes: RemapPathScopeComponents::OBJECT + } + ); + + // Relative path that does not match any prefix + assert_eq!( + mapping.to_real_filename( + &mapping.to_real_filename(&RealFileName::empty(), path("/abc")), + path("quux/src/main.rs"), ), - RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") } + RealFileName { + local: Some(InnerRealFileName { + name: path("quux/src/main.rs"), + working_directory: path("/abc"), + embeddable_name: path("/abc/quux/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("quux/src/main.rs"), + working_directory: path("/abc"), + embeddable_name: path("/abc/quux/src/main.rs") + }, + scopes: RemapPathScopeComponents::empty() + } + ); +} +#[test] +fn to_real_filename_without_remapped_cwd() { + // "virtual" working directory is relative path + let mapping = &FilePathMapping::new( + vec![(path("/foo"), path("FOO")), (path("/cwd/bar"), path("CWDBAR"))], + RemapPathScopeComponents::OBJECT, + ); + let working_directory = path("/cwd"); + let working_directory = mapping.to_real_filename(&RealFileName::empty(), working_directory); + + assert_eq!(working_directory.path(RemapPathScopeComponents::DIAGNOSTICS), path("/cwd")); + assert_eq!(working_directory.path(RemapPathScopeComponents::MACRO), path("/cwd")); + assert_eq!(working_directory.path(RemapPathScopeComponents::DEBUGINFO), path("/cwd")); + + // Absolute path + assert_eq!( + mapping.to_real_filename(&working_directory, path("/foo/src/main.rs")), + RealFileName { + local: Some(InnerRealFileName { + name: path("/foo/src/main.rs"), + working_directory: path("/cwd"), + embeddable_name: path("/foo/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("FOO/src/main.rs"), + working_directory: path("/cwd"), + embeddable_name: path("FOO/src/main.rs") + }, + scopes: RemapPathScopeComponents::OBJECT + } + ); + + // Absolute path with unrelated root + assert_eq!( + mapping.to_real_filename(&working_directory, path("/bar/src/main.rs")), + RealFileName { + local: Some(InnerRealFileName { + name: path("/bar/src/main.rs"), + working_directory: path("/cwd"), + embeddable_name: path("/bar/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("/bar/src/main.rs"), + working_directory: path("/cwd"), + embeddable_name: path("/bar/src/main.rs") + }, + scopes: RemapPathScopeComponents::empty() + } + ); + + // Absolute path with cwd + assert_eq!( + mapping.to_real_filename(&working_directory, path("/cwd/bar/src/main.rs")), + RealFileName { + local: Some(InnerRealFileName { + name: path("/cwd/bar/src/main.rs"), + working_directory: path("/cwd"), + embeddable_name: path("/cwd/bar/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("CWDBAR/src/main.rs"), + working_directory: path("/cwd"), + embeddable_name: path("CWDBAR/src/main.rs") + }, + scopes: RemapPathScopeComponents::OBJECT + } + ); + + // Relative path + assert_eq!( + mapping.to_real_filename(&working_directory, path("src/main.rs")), + RealFileName { + local: Some(InnerRealFileName { + name: path("src/main.rs"), + working_directory: path("/cwd"), + embeddable_name: path("/cwd/src/main.rs") + }), + maybe_remapped: InnerRealFileName { + name: path("src/main.rs"), + working_directory: path("/cwd"), + embeddable_name: path("/cwd/src/main.rs") + }, + scopes: RemapPathScopeComponents::empty() + } ); } @@ -526,8 +671,7 @@ fn path_prefix_remapping_reverse() { { let mapping = &FilePathMapping::new( vec![(path("abc"), path("/")), (path("def"), path("."))], - FileNameDisplayPreference::Remapped, - FileNameEmbeddablePreference::RemappedOnly, + RemapPathScopeComponents::all(), ); assert_eq!(reverse_map_prefix(mapping, "/hello.rs"), None); @@ -538,8 +682,7 @@ fn path_prefix_remapping_reverse() { { let mapping = &FilePathMapping::new( vec![(path("abc"), path("/redacted")), (path("def"), path("/redacted"))], - FileNameDisplayPreference::Remapped, - FileNameEmbeddablePreference::RemappedOnly, + RemapPathScopeComponents::all(), ); assert_eq!(reverse_map_prefix(mapping, "/redacted/hello.rs"), None); @@ -549,8 +692,7 @@ fn path_prefix_remapping_reverse() { { let mapping = &FilePathMapping::new( vec![(path("abc"), path("/redacted")), (path("def/ghi"), path("/fake/dir"))], - FileNameDisplayPreference::Remapped, - FileNameEmbeddablePreference::RemappedOnly, + RemapPathScopeComponents::all(), ); assert_eq!( @@ -567,7 +709,7 @@ fn path_prefix_remapping_reverse() { #[test] fn test_next_point() { let sm = SourceMap::new(FilePathMapping::empty()); - sm.new_source_file(PathBuf::from("example.rs").into(), "a…b".to_string()); + sm.new_source_file(filename(&sm, "example.rs"), "a…b".to_string()); // Dummy spans don't advance. let span = DUMMY_SP; diff --git a/tests/run-make/duplicate-dependency/rmake.rs b/tests/run-make/duplicate-dependency/rmake.rs index 762d97e4311f..274db933feb8 100644 --- a/tests/run-make/duplicate-dependency/rmake.rs +++ b/tests/run-make/duplicate-dependency/rmake.rs @@ -11,7 +11,7 @@ fn rustc_with_common_args() -> Rustc { fn main() { rustc_with_common_args() - .input("foo-v1.rs") + .input(cwd().join("foo-v1.rs")) .crate_type("rlib") .crate_name("foo") .extra_filename("-v1") @@ -19,7 +19,7 @@ fn main() { .run(); rustc_with_common_args() - .input("foo-v2.rs") + .input(cwd().join("foo-v2.rs")) .crate_type("rlib") .crate_name("foo") .extra_filename("-v2") @@ -27,7 +27,7 @@ fn main() { .run(); rustc_with_common_args() - .input("re-export-foo.rs") + .input(cwd().join("re-export-foo.rs")) .crate_type("rlib") .extern_("foo", rust_lib_name("foo-v2")) .run(); diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr index e77c0e5f68d6..86c1140573e3 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr @@ -10,7 +10,7 @@ help: the trait `std::fmt::Display` is not implemented for `A` LL | struct A; | ^^^^^^^^ note: required by a bound in `Trait` - --> $DIR/auxiliary/trait-diag.rs:LL:COL + --> remapped/errors/auxiliary/trait-diag.rs:LL:COL | LL | pub trait Trait: std::fmt::Display {} | ^^^^^^^^^^^^^^^^^ required by this bound in `Trait` From fb7ab6de1619128cc1708332b2ccc97987bda24d Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 5 Dec 2025 20:44:34 +0100 Subject: [PATCH 525/585] Adapt rustdoc to the overhauled filename handling --- src/librustdoc/clean/types.rs | 17 ++++++++++++----- src/librustdoc/doctest.rs | 13 +++---------- src/librustdoc/doctest/markdown.rs | 11 ++++++++--- src/librustdoc/doctest/rust.rs | 10 ---------- src/librustdoc/html/render/context.rs | 4 ++-- src/librustdoc/html/render/mod.rs | 4 ++-- src/librustdoc/html/sources.rs | 12 ++++++------ src/librustdoc/passes/calculate_doc_coverage.rs | 10 +++++++--- 8 files changed, 40 insertions(+), 41 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 7a4650feac1c..a390a03ff114 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -25,7 +25,7 @@ use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{Symbol, kw, sym}; -use rustc_span::{DUMMY_SP, FileName, Loc}; +use rustc_span::{DUMMY_SP, FileName, Loc, RemapPathScopeComponents}; use tracing::{debug, trace}; use {rustc_ast as ast, rustc_hir as hir}; @@ -148,10 +148,17 @@ pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol { pub(crate) fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf { match self.src(tcx) { - FileName::Real(ref p) => match p.local_path_if_available().parent() { - Some(p) => p.to_path_buf(), - None => PathBuf::new(), - }, + FileName::Real(ref p) => { + match p + .local_path() + .or(Some(p.path(RemapPathScopeComponents::MACRO))) + .unwrap() + .parent() + { + Some(p) => p.to_path_buf(), + None => PathBuf::new(), + } + } _ => PathBuf::new(), } } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 19e8fe3e3ed2..92b4a01409dd 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -29,7 +29,7 @@ use rustc_session::config::{self, CrateType, ErrorOutputType, Input}; use rustc_session::lint; use rustc_span::edition::Edition; -use rustc_span::{FileName, Span}; +use rustc_span::{FileName, RemapPathScopeComponents, Span}; use rustc_target::spec::{Target, TargetTuple}; use tempfile::{Builder as TempFileBuilder, TempDir}; use tracing::debug; @@ -952,14 +952,7 @@ fn no_run(&self, opts: &RustdocOptions) -> bool { } fn path(&self) -> PathBuf { match &self.filename { - FileName::Real(path) => { - if let Some(local_path) = path.local_path() { - local_path.to_path_buf() - } else { - // Somehow we got the filename from the metadata of another crate, should never happen - unreachable!("doctest from a different crate"); - } - } + FileName::Real(name) => name.path(RemapPathScopeComponents::DIAGNOSTICS).to_path_buf(), _ => PathBuf::from(r"doctest.rs"), } } @@ -1007,7 +1000,7 @@ fn add_test(&mut self, scraped_test: ScrapedDocTest, dcx: Option Result<(), String> { cur_path: vec![], filename: input .opt_path() - .map(ToOwned::to_owned) - .map(FileName::from) + .map(|f| { + // We don't have access to a rustc Session so let's just use a dummy + // filepath mapping to create a real filename. + let file_mapping = FilePathMapping::empty(); + FileName::Real(file_mapping.to_real_filename(&RealFileName::empty(), f)) + }) .unwrap_or(FileName::Custom("input".to_owned())), }; let codes = ErrorCodes::from(options.unstable_features.is_nightly_build()); diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index ee1419d17d6e..b4397b1f01ff 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -1,7 +1,6 @@ //! Doctest functionality used only for doctests in `.rs` source files. use std::cell::Cell; -use std::env; use std::str::FromStr; use std::sync::Arc; @@ -31,15 +30,6 @@ struct RustCollector { impl RustCollector { fn get_filename(&self) -> FileName { let filename = self.source_map.span_to_filename(self.position); - if let FileName::Real(ref filename) = filename { - let path = filename.remapped_path_if_available(); - // Strip the cwd prefix from the path. This will likely exist if - // the path was not remapped. - let path = env::current_dir() - .map(|cur_dir| path.strip_prefix(&cur_dir).unwrap_or(path)) - .unwrap_or(path); - return path.to_owned().into(); - } filename } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 3d4dff4a17d2..ee71564a1417 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -365,7 +365,7 @@ pub(crate) fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Opti // We can safely ignore synthetic `SourceFile`s. let file = match span.filename(self.sess()) { - FileName::Real(ref path) => path.local_path_if_available().to_path_buf(), + FileName::Real(ref path) => path.local_path()?.to_path_buf(), _ => return None, }; let file = &file; @@ -499,7 +499,7 @@ pub(crate) fn init( } = options; let src_root = match krate.src(tcx) { - FileName::Real(ref p) => match p.local_path_if_available().parent() { + FileName::Real(ref p) => match p.local_path().map(|p| p.parent()).flatten() { Some(p) => p.to_path_buf(), None => PathBuf::new(), }, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 8740b5935973..4529f5a8c016 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -60,7 +60,7 @@ use rustc_middle::ty::print::PrintTraitRefExt; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::{Symbol, sym}; -use rustc_span::{BytePos, DUMMY_SP, FileName, RealFileName}; +use rustc_span::{BytePos, DUMMY_SP, FileName}; use tracing::{debug, info}; pub(crate) use self::context::*; @@ -2772,7 +2772,7 @@ fn render_call_locations( files .iter() .find(|file| match &file.name { - FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path, + FileName::Real(real) => real.local_path().map_or(false, |p| p == rel_path), _ => false, }) .map(|file| file.start_pos) diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 55f8ddab25b1..89fd78979839 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::{FileName, FileNameDisplayPreference, RealFileName}; +use rustc_span::{FileName, RealFileName, RemapPathScopeComponents}; use tracing::info; use super::render::Context; @@ -148,7 +148,10 @@ fn visit_item(&mut self, item: &clean::Item) { span, format!( "failed to render source code for `{filename}`: {e}", - filename = filename.to_string_lossy(FileNameDisplayPreference::Local), + filename = filename + .path(RemapPathScopeComponents::DIAGNOSTICS) + .to_string_lossy() + .into_owned(), ), ); false @@ -224,10 +227,7 @@ fn emit_source( cur.push(&fname); let title = format!("{} - source", src_fname.to_string_lossy()); - let desc = format!( - "Source of the Rust file `{}`.", - file.to_string_lossy(FileNameDisplayPreference::Remapped) - ); + let desc = format!("Source of the Rust file `{}`.", p.to_string_lossy()); let page = layout::Page { title: &title, short_title: &src_fname.to_string_lossy(), diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 66d8b667a4ca..2782baae5e20 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -7,7 +7,7 @@ use rustc_lint::builtin::MISSING_DOCS; use rustc_middle::lint::{LevelAndSource, LintLevelSource}; use rustc_session::lint; -use rustc_span::FileName; +use rustc_span::{FileName, RemapPathScopeComponents}; use serde::Serialize; use tracing::debug; @@ -124,7 +124,7 @@ fn to_json(&self) -> String { &self .items .iter() - .map(|(k, v)| (k.prefer_local().to_string(), v)) + .map(|(k, v)| (k.prefer_local_unconditionally().to_string(), v)) .collect::>(), ) .expect("failed to convert JSON data to string") @@ -167,7 +167,11 @@ fn print_table_record( for (file, &count) in &self.items { if let Some(percentage) = count.percentage() { print_table_record( - &limit_filename_len(file.prefer_local().to_string_lossy().into()), + &limit_filename_len( + file.display(RemapPathScopeComponents::DIAGNOSTICS) + .to_string_lossy() + .into(), + ), count, percentage, count.examples_percentage().unwrap_or(0.), From 799eecf1eb622704a602fed39b3733b96394560e Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 5 Dec 2025 21:46:29 +0100 Subject: [PATCH 526/585] Adapt Clippy to the overhaul filename handling --- src/tools/clippy/clippy_lints/src/module_style.rs | 2 +- src/tools/clippy/clippy_utils/src/source.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs index 9096d6f1c7b3..befd50a5c85f 100644 --- a/src/tools/clippy/clippy_lints/src/module_style.rs +++ b/src/tools/clippy/clippy_lints/src/module_style.rs @@ -81,7 +81,7 @@ pub struct ModStyle { impl EarlyLintPass for ModStyle { fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { - self.working_dir = cx.sess().opts.working_dir.local_path().map(Path::to_path_buf); + self.working_dir = cx.sess().source_map().working_dir().local_path().map(Path::to_path_buf); } fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index e29d45551d1b..b48d17863aa3 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -13,7 +13,7 @@ use rustc_session::Session; use rustc_span::source_map::{SourceMap, original_sp}; use rustc_span::{ - BytePos, DUMMY_SP, DesugaringKind, FileNameDisplayPreference, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, + BytePos, DUMMY_SP, DesugaringKind, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, hygiene, }; use std::borrow::Cow; @@ -268,7 +268,7 @@ fn map_range( debug_assert!( range.start <= text.len() && range.end <= text.len(), "Range `{range:?}` is outside the source file (file `{}`, length `{}`)", - src.sf.name.display(FileNameDisplayPreference::Local), + src.sf.name.prefer_local_unconditionally(), text.len(), ); debug_assert!(range.start <= range.end, "Range `{range:?}` has overlapping bounds"); From d5b1a0cfc6c0a170719d4eb84741c76ef072ce74 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 5 Dec 2025 22:04:55 +0100 Subject: [PATCH 527/585] Adapt Miri to the overhauled filename handling And use the diagnostic method for diagnostic paths. --- src/tools/miri/src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 01f77f261d70..0c7ce472556b 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -627,7 +627,7 @@ pub fn report_msg<'tcx>( err.subdiagnostic(frame_info.as_note(machine.tcx)); } else { let sm = sess.source_map(); - let span = sm.span_to_embeddable_string(frame_info.span); + let span = sm.span_to_diagnostic_string(frame_info.span); err.note(format!("{frame_info} at {span}")); } } From cc4cdea3fac026bae72849032bbc5d7770b009ac Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 6 Dec 2025 13:02:03 +0100 Subject: [PATCH 528/585] Adapt rustfmt to the overhaul filename handling --- src/tools/rustfmt/src/config/file_lines.rs | 10 ++- src/tools/rustfmt/src/parse/session.rs | 80 +++++++++++----------- src/tools/rustfmt/src/source_file.rs | 12 ---- 3 files changed, 50 insertions(+), 52 deletions(-) diff --git a/src/tools/rustfmt/src/config/file_lines.rs b/src/tools/rustfmt/src/config/file_lines.rs index 2f2a6c8d5520..f9ae0d16e298 100644 --- a/src/tools/rustfmt/src/config/file_lines.rs +++ b/src/tools/rustfmt/src/config/file_lines.rs @@ -28,7 +28,15 @@ pub enum FileName { impl From for FileName { fn from(name: rustc_span::FileName) -> FileName { match name { - rustc_span::FileName::Real(rustc_span::RealFileName::LocalPath(p)) => FileName::Real(p), + rustc_span::FileName::Real(real) => { + if let Some(p) = real.into_local_path() { + FileName::Real(p) + } else { + // rustfmt does not remap filenames; the local path should always + // remain accessible. + unreachable!() + } + } rustc_span::FileName::Custom(ref f) if f == "stdin" => FileName::Stdin, _ => unreachable!(), } diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index 10e2809e58bf..2fd8bfdaf3e1 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -58,19 +58,19 @@ fn emit_diagnostic(&mut self, diag: DiagInner, registry: &Registry) { } if let Some(primary_span) = &diag.span.primary_span() { let file_name = self.source_map.span_to_filename(*primary_span); - if let rustc_span::FileName::Real(rustc_span::RealFileName::LocalPath(ref path)) = - file_name - { - if self - .ignore_path_set - .is_match(&FileName::Real(path.to_path_buf())) - { - if !self.has_non_ignorable_parser_errors { - self.can_reset.store(true, Ordering::Release); + if let rustc_span::FileName::Real(real) = file_name { + if let Some(path) = real.local_path() { + if self + .ignore_path_set + .is_match(&FileName::Real(path.to_path_buf())) + { + if !self.has_non_ignorable_parser_errors { + self.can_reset.store(true, Ordering::Release); + } + return; } - return; } - }; + } } self.handle_non_ignoreable_error(diag, registry); } @@ -181,7 +181,10 @@ pub(crate) fn is_file_parsed(&self, path: &Path) -> bool { self.raw_psess .source_map() .get_source_file(&rustc_span::FileName::Real( - rustc_span::RealFileName::LocalPath(path.to_path_buf()), + self.raw_psess + .source_map() + .path_mapping() + .to_real_filename(self.raw_psess.source_map().working_dir(), path), )) .is_some() } @@ -246,10 +249,20 @@ pub(crate) fn snippet_provider(&self, span: Span) -> SnippetProvider { ) } - pub(crate) fn get_original_snippet(&self, file_name: &FileName) -> Option> { + pub(crate) fn get_original_snippet(&self, filename: &FileName) -> Option> { + let rustc_filename = match filename { + FileName::Real(path) => rustc_span::FileName::Real( + self.raw_psess + .source_map() + .path_mapping() + .to_real_filename(self.raw_psess.source_map().working_dir(), path), + ), + FileName::Stdin => rustc_span::FileName::Custom("stdin".to_owned()), + }; + self.raw_psess .source_map() - .get_source_file(&file_name.into()) + .get_source_file(&rustc_filename) .and_then(|source_file| source_file.src.clone()) } } @@ -313,7 +326,7 @@ mod emitter { use crate::config::IgnoreList; use crate::utils::mk_sp; use rustc_errors::MultiSpan; - use rustc_span::{FileName as SourceMapFileName, RealFileName}; + use rustc_span::FileName as SourceMapFileName; use std::path::PathBuf; use std::sync::atomic::AtomicU32; @@ -372,6 +385,13 @@ fn get_ignore_list(config: &str) -> IgnoreList { .ignore() } + fn filename(sm: &SourceMap, path: &str) -> SourceMapFileName { + SourceMapFileName::Real( + sm.path_mapping() + .to_real_filename(sm.working_dir(), PathBuf::from(path)), + ) + } + #[test] fn handles_fatal_parse_error_in_ignored_file() { let num_emitted_errors = Arc::new(AtomicU32::new(0)); @@ -380,10 +400,7 @@ fn handles_fatal_parse_error_in_ignored_file() { let source_map = Arc::new(SourceMap::new(FilePathMapping::empty())); let source = String::from(r#"extern "system" fn jni_symbol!( funcName ) ( ... ) -> {} "#); - source_map.new_source_file( - SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("foo.rs"))), - source, - ); + source_map.new_source_file(filename(&source_map, "foo.rs"), source); let registry = Registry::new(&[]); let mut emitter = build_emitter( Arc::clone(&num_emitted_errors), @@ -406,10 +423,7 @@ fn handles_recoverable_parse_error_in_ignored_file() { let ignore_list = get_ignore_list(r#"ignore = ["foo.rs"]"#); let source_map = Arc::new(SourceMap::new(FilePathMapping::empty())); let source = String::from(r#"pub fn bar() { 1x; }"#); - source_map.new_source_file( - SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("foo.rs"))), - source, - ); + source_map.new_source_file(filename(&source_map, "foo.rs"), source); let registry = Registry::new(&[]); let mut emitter = build_emitter( Arc::clone(&num_emitted_errors), @@ -431,10 +445,7 @@ fn handles_recoverable_parse_error_in_non_ignored_file() { let can_reset_errors = Arc::new(AtomicBool::new(false)); let source_map = Arc::new(SourceMap::new(FilePathMapping::empty())); let source = String::from(r#"pub fn bar() { 1x; }"#); - source_map.new_source_file( - SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("foo.rs"))), - source, - ); + source_map.new_source_file(filename(&source_map, "foo.rs"), source); let registry = Registry::new(&[]); let mut emitter = build_emitter( Arc::clone(&num_emitted_errors), @@ -460,18 +471,9 @@ fn handles_mix_of_recoverable_parse_error() { let foo_source = String::from(r#"pub fn foo() { 1x; }"#); let fatal_source = String::from(r#"extern "system" fn jni_symbol!( funcName ) ( ... ) -> {} "#); - source_map.new_source_file( - SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("bar.rs"))), - bar_source, - ); - source_map.new_source_file( - SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("foo.rs"))), - foo_source, - ); - source_map.new_source_file( - SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("fatal.rs"))), - fatal_source, - ); + source_map.new_source_file(filename(&source_map, "bar.rs"), bar_source); + source_map.new_source_file(filename(&source_map, "foo.rs"), foo_source); + source_map.new_source_file(filename(&source_map, "fatal.rs"), fatal_source); let registry = Registry::new(&[]); let mut emitter = build_emitter( Arc::clone(&num_emitted_errors), diff --git a/src/tools/rustfmt/src/source_file.rs b/src/tools/rustfmt/src/source_file.rs index e942058a0a83..b0ec24f3db66 100644 --- a/src/tools/rustfmt/src/source_file.rs +++ b/src/tools/rustfmt/src/source_file.rs @@ -65,18 +65,6 @@ fn ensure_real_path(filename: &FileName) -> &Path { } } - #[allow(non_local_definitions)] - impl From<&FileName> for rustc_span::FileName { - fn from(filename: &FileName) -> rustc_span::FileName { - match filename { - FileName::Real(path) => { - rustc_span::FileName::Real(rustc_span::RealFileName::LocalPath(path.to_owned())) - } - FileName::Stdin => rustc_span::FileName::Custom("stdin".to_owned()), - } - } - } - // SourceFile's in the SourceMap will always have Unix-style line endings // See: https://github.com/rust-lang/rustfmt/issues/3850 // So if the user has explicitly overridden the rustfmt `newline_style` From d59c4d903fbd58718aa6aebba9a88fb15378de8c Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 6 Dec 2025 11:31:46 +0100 Subject: [PATCH 529/585] Adapt `cg_cranelift` to the overhauled filename handling --- .../src/debuginfo/line_info.rs | 7 ++++-- .../src/debuginfo/mod.rs | 22 +++++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index db58ee890911..12b0d5ec4963 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -6,7 +6,10 @@ use cranelift_codegen::MachSrcLoc; use cranelift_codegen::binemit::CodeOffset; use gimli::write::{FileId, FileInfo, LineProgram, LineString, LineStringTable}; -use rustc_span::{FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHashAlgorithm, hygiene}; +use rustc_span::{ + FileName, Pos, RemapPathScopeComponents, SourceFile, SourceFileAndLine, + SourceFileHashAlgorithm, hygiene, +}; use crate::debuginfo::FunctionDebugContext; use crate::debuginfo::emit::address_for_func; @@ -95,7 +98,7 @@ pub(crate) fn add_source_file(&mut self, source_file: &SourceFile) -> FileId { match &source_file.name { FileName::Real(path) => { let (dir_path, file_name) = - split_path_dir_and_file(path.to_path(self.filename_display_preference)); + split_path_dir_and_file(path.path(RemapPathScopeComponents::DEBUGINFO)); let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str()); let file_name = osstr_as_utf8_bytes(file_name); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 8c43db92fe05..0cd510037293 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -21,7 +21,7 @@ use rustc_hir::def_id::DefIdMap; use rustc_session::Session; use rustc_session::config::DebugInfo; -use rustc_span::{FileNameDisplayPreference, SourceFileHash, StableSourceFileId}; +use rustc_span::{RemapPathScopeComponents, SourceFileHash, StableSourceFileId}; use rustc_target::callconv::FnAbi; pub(crate) use self::emit::{DebugReloc, DebugRelocName}; @@ -44,7 +44,6 @@ pub(crate) struct DebugContext { namespace_map: DefIdMap, array_size_type: Option, - filename_display_preference: FileNameDisplayPreference, embed_source: bool, } @@ -102,18 +101,18 @@ pub(crate) fn new( let mut dwarf = DwarfUnit::new(encoding); - use rustc_session::config::RemapPathScopeComponents; - - let filename_display_preference = - tcx.sess.filename_display_preference(RemapPathScopeComponents::DEBUGINFO); - let producer = producer(tcx.sess); - let comp_dir = - tcx.sess.opts.working_dir.to_string_lossy(filename_display_preference).to_string(); + let comp_dir = tcx + .sess + .source_map() + .working_dir() + .path(RemapPathScopeComponents::DEBUGINFO) + .to_string_lossy(); let (name, file_info) = match tcx.sess.local_crate_source_file() { Some(path) => { - let name = path.to_string_lossy(filename_display_preference).to_string(); + let name = + path.path(RemapPathScopeComponents::DEBUGINFO).to_string_lossy().into_owned(); (name, None) } None => (tcx.crate_name(LOCAL_CRATE).to_string(), None), @@ -137,7 +136,7 @@ pub(crate) fn new( { let name = dwarf.strings.add(format!("{name}/@/{cgu_name}")); - let comp_dir = dwarf.strings.add(comp_dir); + let comp_dir = dwarf.strings.add(&*comp_dir); let root = dwarf.unit.root(); let root = dwarf.unit.get_mut(root); @@ -180,7 +179,6 @@ pub(crate) fn new( stack_pointer_register, namespace_map: DefIdMap::default(), array_size_type, - filename_display_preference, embed_source, }) } From b1eb21bb851db6089bc77e9321401cd0c13cd909 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 6 Dec 2025 11:54:06 +0100 Subject: [PATCH 530/585] Adapt and fix `cg_gcc` to the overhauled filename remapping --- compiler/rustc_codegen_gcc/src/debuginfo.rs | 28 ++++----------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 3979f62987f2..53d3670c1524 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -297,29 +297,11 @@ fn dbg_loc( let pos = span.lo(); let DebugLoc { file, line, col } = self.lookup_debug_loc(pos); match file.name { - rustc_span::FileName::Real(ref name) => match *name { - rustc_span::RealFileName::LocalPath(ref name) => { - if let Some(name) = name.to_str() { - self.context.new_location(name, line as i32, col as i32) - } else { - Location::null() - } - } - rustc_span::RealFileName::Remapped { - ref local_path, - virtual_name: ref _unused, - } => { - if let Some(name) = local_path.as_ref() { - if let Some(name) = name.to_str() { - self.context.new_location(name, line as i32, col as i32) - } else { - Location::null() - } - } else { - Location::null() - } - } - }, + rustc_span::FileName::Real(ref name) => self.context.new_location( + name.path(rustc_span::RemapPathScopeComponents::DEBUGINFO).to_string_lossy(), + line as i32, + col as i32, + ), _ => Location::null(), } } From 8b035e473a080a33525ee33524cb2ef57ec3d94d Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 22 Nov 2025 00:30:23 +0100 Subject: [PATCH 531/585] Add regression test for `Location::caller()` in consts across crates --- .../location-caller.rs | 21 ++++ .../remap-path-prefix-consts/rmake.rs | 114 ++++++++++++++++++ .../remap-path-prefix-consts/runner.rs | 19 +++ 3 files changed, 154 insertions(+) create mode 100644 tests/run-make/remap-path-prefix-consts/location-caller.rs create mode 100644 tests/run-make/remap-path-prefix-consts/rmake.rs create mode 100644 tests/run-make/remap-path-prefix-consts/runner.rs diff --git a/tests/run-make/remap-path-prefix-consts/location-caller.rs b/tests/run-make/remap-path-prefix-consts/location-caller.rs new file mode 100644 index 000000000000..70685e032e4a --- /dev/null +++ b/tests/run-make/remap-path-prefix-consts/location-caller.rs @@ -0,0 +1,21 @@ +// Reproducer from https://github.com/rust-lang/rust/issues/148328#issuecomment-3473688412 +#[inline(always)] +pub const fn the_path() -> &'static str { + std::panic::Location::caller().file() +} + +#[inline(never)] +pub fn the_path2() -> &'static str { + const { std::panic::Location::caller().file() } +} + +// Reproducer from https://github.com/rust-lang/rust/issues/148328#issuecomment-3473761194 +pub const fn the_path_len() -> usize { + std::panic::Location::caller().file().len() +} + +pub type Array = [u8; the_path_len()]; + +pub fn the_zeroed_path_len_array() -> Array { + [0; _] +} diff --git a/tests/run-make/remap-path-prefix-consts/rmake.rs b/tests/run-make/remap-path-prefix-consts/rmake.rs new file mode 100644 index 000000000000..02a75aa02278 --- /dev/null +++ b/tests/run-make/remap-path-prefix-consts/rmake.rs @@ -0,0 +1,114 @@ +//@ needs-target-std + +use run_make_support::{bin_name, cwd, run, rustc}; + +fn main() { + // No remapping - relative paths + { + let runner_bin = bin_name("runner-no-remap-rel-paths"); + + let mut location_caller = rustc(); + location_caller.crate_type("lib").input("location-caller.rs"); + location_caller.run(); + + let mut runner = rustc(); + runner.crate_type("bin").input("runner.rs").output(&runner_bin); + runner.run(); + + run(&runner_bin); + } + + // No remapping - absolute paths + { + let runner_bin = bin_name("runner-no-remap-abs-paths"); + + let mut location_caller = rustc(); + location_caller.crate_type("lib").input(cwd().join("location-caller.rs")); + location_caller.run(); + + let mut runner = rustc(); + runner.crate_type("bin").input(cwd().join("runner.rs")).output(&runner_bin); + runner.run(); + + run(&runner_bin); + } + + // No remapping - mixed paths + { + let runner_bin = bin_name("runner-no-remap-mixed-paths"); + + let mut location_caller = rustc(); + location_caller.crate_type("lib").input(cwd().join("location-caller.rs")); + location_caller.run(); + + let mut runner = rustc(); + runner.crate_type("bin").input("runner.rs").output(&runner_bin); + runner.run(); + + run(&runner_bin); + } + + // Remapping current working directory + { + let runner_bin = bin_name("runner-remap-cwd"); + + let mut location_caller = rustc(); + location_caller + .crate_type("lib") + .remap_path_prefix(cwd(), "/remapped") + .input(cwd().join("location-caller.rs")); + location_caller.run(); + + let mut runner = rustc(); + runner + .crate_type("bin") + .remap_path_prefix(cwd(), "/remapped") + .input(cwd().join("runner.rs")) + .output(&runner_bin); + runner.run(); + + run(&runner_bin); + } + + // Remapping current working directory - only in the dependency + { + let runner_bin = bin_name("runner-remap-cwd-only-dep"); + + let mut location_caller = rustc(); + location_caller + .crate_type("lib") + .remap_path_prefix(cwd(), "/remapped") + .input(cwd().join("location-caller.rs")); + location_caller.run(); + + let mut runner = rustc(); + runner.crate_type("bin").input(cwd().join("runner.rs")).output(&runner_bin); + runner.run(); + + run(&runner_bin); + } + + // Remapping current working directory - different scopes + { + let runner_bin = bin_name("runner-remap-cwd-diff-scope"); + + let mut location_caller = rustc(); + location_caller + .crate_type("lib") + .remap_path_prefix(cwd(), "/remapped") + .arg("-Zremap-path-scope=object") + .input(cwd().join("location-caller.rs")); + location_caller.run(); + + let mut runner = rustc(); + runner + .crate_type("bin") + .remap_path_prefix(cwd(), "/remapped") + .arg("-Zremap-path-scope=diagnostics") + .input(cwd().join("runner.rs")) + .output(&runner_bin); + runner.run(); + + run(&runner_bin); + } +} diff --git a/tests/run-make/remap-path-prefix-consts/runner.rs b/tests/run-make/remap-path-prefix-consts/runner.rs new file mode 100644 index 000000000000..d67dbe3b398a --- /dev/null +++ b/tests/run-make/remap-path-prefix-consts/runner.rs @@ -0,0 +1,19 @@ +// Verifies that the paths are the same and consistent between this crate and location_caller crate. +// +// https://github.com/rust-lang/rust/issues/148328 + +extern crate location_caller; + +fn main() { + { + // Assert both paths are the same + let the_path = location_caller::the_path(); + let the_path2 = location_caller::the_path2(); + assert_eq!(the_path, the_path2); + } + + { + // Let's make sure we don't read OOB memory + println!("{:?}", location_caller::the_zeroed_path_len_array()); + } +} From 0be1a9b59ae9f8d6caeb3c58a3e112443c9a5b6c Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 5 Dec 2025 20:52:14 +0100 Subject: [PATCH 532/585] Somewhat retire `Options::working_dir` in favor `SourceMap::working_dir` We can't completely remove it as it's needed for incr comp but direct consumers towards `SourceMap::working_dir` instead. --- compiler/rustc_session/src/config.rs | 31 ++++++++++++++++++++------- compiler/rustc_session/src/options.rs | 4 +++- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index b5b19c64951b..be4b36e3b926 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -24,7 +24,7 @@ use rustc_macros::{BlobDecodable, Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::{DEFAULT_EDITION, EDITION_NAME_LIST, Edition, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; -use rustc_span::{FileName, SourceFileHashAlgorithm, Symbol, sym}; +use rustc_span::{FileName, RealFileName, SourceFileHashAlgorithm, Symbol, sym}; use rustc_target::spec::{ FramePointer, LinkSelfContainedComponents, LinkerFeatures, PanicStrategy, SplitDebuginfo, Target, TargetTuple, @@ -1358,6 +1358,17 @@ fn file_path_mapping( impl Default for Options { fn default() -> Options { + let unstable_opts = UnstableOptions::default(); + + // FIXME(Urgau): This is a hack that ideally shouldn't exist, but rustdoc + // currently uses this `Default` implementation, so we have no choice but + // to create a default working directory. + let working_dir = { + let working_dir = std::env::current_dir().unwrap(); + let file_mapping = file_path_mapping(Vec::new(), &unstable_opts); + file_mapping.to_real_filename(&RealFileName::empty(), &working_dir) + }; + Options { assert_incr_state: None, crate_types: Vec::new(), @@ -1374,7 +1385,7 @@ fn default() -> Options { test: false, incremental: None, untracked_state_hash: Default::default(), - unstable_opts: Default::default(), + unstable_opts, prints: Vec::new(), cg: Default::default(), error_format: ErrorOutputType::default(), @@ -1398,7 +1409,7 @@ fn default() -> Options { json_unused_externs: JsonUnusedExterns::No, json_future_incompat: false, pretty: None, - working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()), + working_dir, color: ColorConfig::Auto, logical_env: FxIndexMap::default(), verbose: false, @@ -2752,12 +2763,16 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M .collect() }; - let working_dir = std::env::current_dir().unwrap_or_else(|e| { - early_dcx.early_fatal(format!("Current directory is invalid: {e}")); - }); + // Ideally we would use `SourceMap::working_dir` instead, but we don't have access to it + // so we manually create the potentially-remapped working directory + let working_dir = { + let working_dir = std::env::current_dir().unwrap_or_else(|e| { + early_dcx.early_fatal(format!("Current directory is invalid: {e}")); + }); - let file_mapping = file_path_mapping(remap_path_prefix.clone(), &unstable_opts); - let working_dir = file_mapping.to_real_filename(&working_dir); + let file_mapping = file_path_mapping(remap_path_prefix.clone(), &unstable_opts); + file_mapping.to_real_filename(&RealFileName::empty(), &working_dir) + }; let verbose = matches.opt_present("verbose") || unstable_opts.verbose_internals; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index d7ac39ecc9e8..aea0b73ee927 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -12,7 +12,7 @@ use rustc_hashes::Hash64; use rustc_macros::{BlobDecodable, Encodable}; use rustc_span::edition::Edition; -use rustc_span::{RemapPathScopeComponents, SourceFileHashAlgorithm}; +use rustc_span::{RealFileName, RemapPathScopeComponents, SourceFileHashAlgorithm}; use rustc_target::spec::{ CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, @@ -492,7 +492,9 @@ pub struct Options { pretty: Option [UNTRACKED], /// The (potentially remapped) working directory + #[rustc_lint_opt_deny_field_access("use `SourceMap::working_dir` instead of this field")] working_dir: RealFileName [TRACKED], + color: ColorConfig [UNTRACKED], verbose: bool [TRACKED_NO_CRATE_HASH], From 0afd21d646d5a6e43541cc1ffedff36dca44eb08 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 9 Dec 2025 18:48:03 +0100 Subject: [PATCH 533/585] Add `ignore-cross-compile` to `remap-path-prefix-consts` run-make test --- tests/run-make/remap-path-prefix-consts/rmake.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-make/remap-path-prefix-consts/rmake.rs b/tests/run-make/remap-path-prefix-consts/rmake.rs index 02a75aa02278..d07a5e00768a 100644 --- a/tests/run-make/remap-path-prefix-consts/rmake.rs +++ b/tests/run-make/remap-path-prefix-consts/rmake.rs @@ -1,3 +1,4 @@ +//@ ignore-cross-compile (relocations in generic ELF against `arm-unknown-linux-gnueabihf`) //@ needs-target-std use run_make_support::{bin_name, cwd, run, rustc}; From cefcd99c1779a1e46aa7950fb65fa5b5f77d56e1 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 10 Dec 2025 19:42:18 +0100 Subject: [PATCH 534/585] Fix normalization logic of the rustdoc extract doctests tests on Windows --- tests/rustdoc-ui/extract-doctests-result.rs | 1 + tests/rustdoc-ui/extract-doctests-result.stdout | 2 +- tests/rustdoc-ui/extract-doctests.rs | 1 + tests/rustdoc-ui/extract-doctests.stdout | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/rustdoc-ui/extract-doctests-result.rs b/tests/rustdoc-ui/extract-doctests-result.rs index 88affb6d3331..4869fcd0259b 100644 --- a/tests/rustdoc-ui/extract-doctests-result.rs +++ b/tests/rustdoc-ui/extract-doctests-result.rs @@ -3,6 +3,7 @@ //@ compile-flags:-Z unstable-options --output-format=doctest //@ normalize-stdout: "tests/rustdoc-ui" -> "$$DIR" +//@ normalize-stdout: "[A-Z]:[\\/](?:[^\\/]+[\\/])*?\$DIR" -> "$$DIR" //@ check-pass //! ``` diff --git a/tests/rustdoc-ui/extract-doctests-result.stdout b/tests/rustdoc-ui/extract-doctests-result.stdout index 44e6d33c6626..bb5d2c3e68c6 100644 --- a/tests/rustdoc-ui/extract-doctests-result.stdout +++ b/tests/rustdoc-ui/extract-doctests-result.stdout @@ -1 +1 @@ -{"format_version":2,"doctests":[{"file":"$DIR/extract-doctests-result.rs","line":8,"doctest_attributes":{"original":"","should_panic":false,"no_run":false,"ignore":"None","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nOk(())","doctest_code":{"crate_level":"#![allow(unused)]\n","code":"let x = 12;\nOk(())","wrapper":{"before":"fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n","after":"\n} _inner().unwrap() }","returns_result":true}},"name":"$DIR/extract-doctests-result.rs - (line 8)"}]} \ No newline at end of file +{"format_version":2,"doctests":[{"file":"$DIR/extract-doctests-result.rs","line":9,"doctest_attributes":{"original":"","should_panic":false,"no_run":false,"ignore":"None","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nOk(())","doctest_code":{"crate_level":"#![allow(unused)]\n","code":"let x = 12;\nOk(())","wrapper":{"before":"fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n","after":"\n} _inner().unwrap() }","returns_result":true}},"name":"$DIR/extract-doctests-result.rs - (line 9)"}]} \ No newline at end of file diff --git a/tests/rustdoc-ui/extract-doctests.rs b/tests/rustdoc-ui/extract-doctests.rs index 06bd35969d0c..e2071f4ec10c 100644 --- a/tests/rustdoc-ui/extract-doctests.rs +++ b/tests/rustdoc-ui/extract-doctests.rs @@ -3,6 +3,7 @@ //@ compile-flags:-Z unstable-options --output-format=doctest //@ normalize-stdout: "tests/rustdoc-ui" -> "$$DIR" +//@ normalize-stdout: "[A-Z]:[\\/](?:[^\\/]+[\\/])*?\$DIR" -> "$$DIR" //@ check-pass //! ```ignore (checking attributes) diff --git a/tests/rustdoc-ui/extract-doctests.stdout b/tests/rustdoc-ui/extract-doctests.stdout index 796ecd82f1c9..4e2acc91f498 100644 --- a/tests/rustdoc-ui/extract-doctests.stdout +++ b/tests/rustdoc-ui/extract-doctests.stdout @@ -1 +1 @@ -{"format_version":2,"doctests":[{"file":"$DIR/extract-doctests.rs","line":8,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":{"crate_level":"#![allow(unused)]\n","code":"let x = 12;\nlet y = 14;","wrapper":{"before":"fn main() {\n","after":"\n}","returns_result":false}},"name":"$DIR/extract-doctests.rs - (line 8)"},{"file":"$DIR/extract-doctests.rs","line":13,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":null,"name":"$DIR/extract-doctests.rs - (line 13)"}]} \ No newline at end of file +{"format_version":2,"doctests":[{"file":"$DIR/extract-doctests.rs","line":9,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":{"crate_level":"#![allow(unused)]\n","code":"let x = 12;\nlet y = 14;","wrapper":{"before":"fn main() {\n","after":"\n}","returns_result":false}},"name":"$DIR/extract-doctests.rs - (line 9)"},{"file":"$DIR/extract-doctests.rs","line":14,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":null,"name":"$DIR/extract-doctests.rs - (line 14)"}]} \ No newline at end of file From 97252d3747161635253ec7fefa413c2843be5321 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 8 Dec 2025 22:31:55 +0100 Subject: [PATCH 535/585] Remove from `MetaItemParser::from_attr` --- compiler/rustc_attr_parsing/src/interface.rs | 21 ++++++++++---------- compiler/rustc_attr_parsing/src/parser.rs | 18 +---------------- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 5eefce75ace2..45b46803419d 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::convert::identity; use rustc_ast as ast; use rustc_ast::token::DocFragmentKind; @@ -13,7 +14,7 @@ use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage}; -use crate::parser::{ArgParser, MetaItemParser, PathParser}; +use crate::parser::{ArgParser, PathParser}; use crate::session_diagnostics::ParsedDescription; use crate::{Early, Late, OmitDoc, ShouldEmit}; @@ -144,22 +145,23 @@ pub fn parse_single( }; let parts = normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); - let meta_parser = MetaItemParser::from_attr(normal_attr, &parts, &sess.psess, emit_errors)?; - let path = meta_parser.path(); - let args = meta_parser.args(); + + let path = AttrPath::from_ast(&normal_attr.item.path, identity); + let args = + ArgParser::from_attr_args(&normal_attr.item.args, &parts, &sess.psess, emit_errors)?; Self::parse_single_args( sess, attr.span, normal_attr.item.span(), attr.style, - path.get_attribute_path(), + path, Some(normal_attr.item.unsafety), ParsedDescription::Attribute, target_span, target_node_id, features, emit_errors, - args, + &args, parse_fn, template, ) @@ -316,15 +318,14 @@ pub fn parse_attribute_list( n.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) { - let Some(parser) = MetaItemParser::from_attr( - n, + let Some(args) = ArgParser::from_attr_args( + &n.item.args, &parts, &self.sess.psess, self.stage.should_emit(), ) else { continue; }; - let args = parser.args(); // Special-case handling for `#[doc = "..."]`: if we go through with // `DocParser`, the order of doc comments will be messed up because `///` @@ -373,7 +374,7 @@ pub fn parse_attribute_list( attr_path: attr_path.clone(), }; - (accept.accept_fn)(&mut cx, args); + (accept.accept_fn)(&mut cx, &args); if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) { Self::check_target(&accept.allowed_targets, target, &mut cx); } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 819e5630561d..2304fb0ca63c 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -8,7 +8,7 @@ use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path, StmtKind, UnOp}; +use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, StmtKind, UnOp}; use rustc_ast_pretty::pprust; use rustc_errors::{Diag, PResult}; use rustc_hir::{self as hir, AttrPath}; @@ -252,22 +252,6 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { } } -impl<'a> MetaItemParser<'a> { - /// Create a new parser from a [`NormalAttr`], which is stored inside of any - /// [`ast::Attribute`](rustc_ast::Attribute) - pub fn from_attr<'sess>( - attr: &'a NormalAttr, - parts: &[Symbol], - psess: &'sess ParseSess, - should_emit: ShouldEmit, - ) -> Option { - Some(Self { - path: PathParser(Cow::Borrowed(&attr.item.path)), - args: ArgParser::from_attr_args(&attr.item.args, parts, psess, should_emit)?, - }) - } -} - impl<'a> MetaItemParser<'a> { pub fn span(&self) -> Span { if let Some(other) = self.args.span() { From 86a97c41cbfae596cad6e6e9191c414e7a77a520 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 8 Dec 2025 22:48:13 +0100 Subject: [PATCH 536/585] Remove lifetime param from parser types --- .../src/attributes/allow_unstable.rs | 8 +- .../rustc_attr_parsing/src/attributes/cfg.rs | 8 +- .../src/attributes/codegen_attrs.rs | 18 ++-- .../src/attributes/crate_level.rs | 12 +-- .../src/attributes/debugger.rs | 2 +- .../src/attributes/deprecation.rs | 4 +- .../src/attributes/dummy.rs | 2 +- .../src/attributes/inline.rs | 4 +- .../src/attributes/link_attrs.rs | 22 ++--- .../src/attributes/macro_attrs.rs | 2 +- .../rustc_attr_parsing/src/attributes/mod.rs | 8 +- .../src/attributes/must_use.rs | 2 +- .../rustc_attr_parsing/src/attributes/path.rs | 2 +- .../src/attributes/proc_macro_attrs.rs | 6 +- .../src/attributes/prototype.rs | 4 +- .../rustc_attr_parsing/src/attributes/repr.rs | 21 ++--- .../src/attributes/rustc_internal.rs | 8 +- .../src/attributes/stability.rs | 6 +- .../src/attributes/test_attrs.rs | 4 +- .../src/attributes/traits.rs | 2 +- .../src/attributes/transparency.rs | 2 +- .../rustc_attr_parsing/src/attributes/util.rs | 2 +- compiler/rustc_attr_parsing/src/context.rs | 6 +- compiler/rustc_attr_parsing/src/interface.rs | 9 +- compiler/rustc_attr_parsing/src/parser.rs | 83 ++++++++++--------- 25 files changed, 119 insertions(+), 128 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 088fa73d7427..faa366a62831 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -19,7 +19,7 @@ impl CombineAttributeParser for AllowInternalUnstableParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator { parse_unstable(cx, args, >::PATH[0]) .into_iter() @@ -41,7 +41,7 @@ impl CombineAttributeParser for UnstableFeatureBoundParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator { if !cx.features().staged_api() { cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span }); @@ -69,7 +69,7 @@ impl CombineAttributeParser for AllowConstFnUnstableParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { parse_unstable(cx, args, >::PATH[0]) } @@ -77,7 +77,7 @@ fn extend<'c>( fn parse_unstable( cx: &AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, symbol: Symbol, ) -> impl IntoIterator { let mut res = Vec::new(); diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 6ffe25098308..61c314b41b65 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -37,7 +37,7 @@ pub fn parse_cfg<'c, S: Stage>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> Option { let ArgParser::List(list) = args else { cx.expected_list(cx.attr_span); @@ -52,7 +52,7 @@ pub fn parse_cfg<'c, S: Stage>( pub fn parse_cfg_entry( cx: &mut AcceptContext<'_, '_, S>, - item: &MetaItemOrLitParser<'_>, + item: &MetaItemOrLitParser, ) -> Result { Ok(match item { MetaItemOrLitParser::MetaItemParser(meta) => match meta.args() { @@ -98,7 +98,7 @@ pub fn parse_cfg_entry( fn parse_cfg_entry_version( cx: &mut AcceptContext<'_, '_, S>, - list: &MetaItemListParser<'_>, + list: &MetaItemListParser, meta_span: Span, ) -> Result { try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option()); @@ -130,7 +130,7 @@ fn parse_cfg_entry_version( fn parse_cfg_entry_target( cx: &mut AcceptContext<'_, '_, S>, - list: &MetaItemListParser<'_>, + list: &MetaItemListParser, meta_span: Span, ) -> Result { if let Some(features) = cx.features_option() diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index b4ecbe6e4de6..ce208203ec5e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -23,7 +23,7 @@ impl SingleAttributeParser for OptimizeParser { ]); const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(list) = args.list() else { cx.expected_list(cx.attr_span); return None; @@ -84,7 +84,7 @@ impl SingleAttributeParser for CoverageParser { ]); const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(args) = args.list() else { cx.expected_specific_argument_and_list(cx.attr_span, &[sym::on, sym::off]); return None; @@ -135,7 +135,7 @@ impl SingleAttributeParser for ExportNameParser { ]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -164,7 +164,7 @@ impl SingleAttributeParser for ObjcClassParser { AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -196,7 +196,7 @@ impl SingleAttributeParser for ObjcSelectorParser { AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -474,7 +474,7 @@ fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { fn parse_tf_attribute<'c, S: Stage>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { let mut features = Vec::new(); let ArgParser::List(list) = args else { @@ -531,7 +531,7 @@ impl CombineAttributeParser for TargetFeatureParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { parse_tf_attribute(cx, args) } @@ -569,7 +569,7 @@ impl CombineAttributeParser for ForceTargetFeatureParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { parse_tf_attribute(cx, args) } @@ -599,7 +599,7 @@ impl SingleAttributeParser for SanitizeParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(list) = args.list() else { cx.expected_list(cx.attr_span); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 480a32658bc5..01c503357fc7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -11,7 +11,7 @@ impl SingleAttributeParser for CrateNameParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(n) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -35,7 +35,7 @@ impl SingleAttributeParser for RecursionLimitParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -58,7 +58,7 @@ impl SingleAttributeParser for MoveSizeLimitParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -81,7 +81,7 @@ impl SingleAttributeParser for TypeLengthLimitParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -104,7 +104,7 @@ impl SingleAttributeParser for PatternComplexityLimitParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -154,7 +154,7 @@ impl SingleAttributeParser for WindowsSubsystemParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value( args.span().unwrap_or(cx.inner_span), diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs index 56ff10be4264..dfb3b914e189 100644 --- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -18,7 +18,7 @@ impl CombineAttributeParser for DebuggerViualizerParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { let Some(l) = args.list() else { cx.expected_list(args.span().unwrap_or(cx.attr_span)); diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index f96477e28cd0..ad3e2ced60c7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -12,7 +12,7 @@ fn get( cx: &AcceptContext<'_, '_, S>, name: Symbol, param_span: Span, - arg: &ArgParser<'_>, + arg: &ArgParser, item: &Option, ) -> Option { if item.is_some() { @@ -68,7 +68,7 @@ impl SingleAttributeParser for DeprecationParser { NameValueStr: "reason" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let features = cx.features(); let mut since = None; diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index 7293cee842c2..0a7d95f31799 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -15,7 +15,7 @@ impl SingleAttributeParser for DummyParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really - fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser<'_>) -> Option { + fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser) -> Option { Some(AttributeKind::Dummy) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index fba1a663c057..f6aab9ea0ee2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -34,7 +34,7 @@ impl SingleAttributeParser for InlineParser { "https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { match args { ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)), ArgParser::List(list) => { @@ -77,7 +77,7 @@ impl SingleAttributeParser for RustcForceInlineParser { const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let reason = match args { ArgParser::NoArgs => None, ArgParser::List(list) => { diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 46fa8ee71343..67471e31b105 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -33,7 +33,7 @@ impl SingleAttributeParser for LinkNameParser { "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -64,7 +64,7 @@ impl CombineAttributeParser for LinkParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { let items = match args { ArgParser::List(list) => list, @@ -242,7 +242,7 @@ fn extend<'c>( impl LinkParser { fn parse_link_name( - item: &MetaItemParser<'_>, + item: &MetaItemParser, name: &mut Option<(Symbol, Span)>, cx: &mut AcceptContext<'_, '_, S>, ) -> bool { @@ -267,7 +267,7 @@ fn parse_link_name( } fn parse_link_kind( - item: &MetaItemParser<'_>, + item: &MetaItemParser, kind: &mut Option, cx: &mut AcceptContext<'_, '_, S>, sess: &Session, @@ -347,7 +347,7 @@ fn parse_link_kind( } fn parse_link_modifiers( - item: &MetaItemParser<'_>, + item: &MetaItemParser, modifiers: &mut Option<(Symbol, Span)>, cx: &mut AcceptContext<'_, '_, S>, ) -> bool { @@ -368,7 +368,7 @@ fn parse_link_modifiers( } fn parse_link_cfg( - item: &MetaItemParser<'_>, + item: &MetaItemParser, cfg: &mut Option, cx: &mut AcceptContext<'_, '_, S>, sess: &Session, @@ -400,7 +400,7 @@ fn parse_link_cfg( } fn parse_link_wasm_import_module( - item: &MetaItemParser<'_>, + item: &MetaItemParser, wasm_import_module: &mut Option<(Symbol, Span)>, cx: &mut AcceptContext<'_, '_, S>, ) -> bool { @@ -421,7 +421,7 @@ fn parse_link_wasm_import_module( } fn parse_link_import_name_type( - item: &MetaItemParser<'_>, + item: &MetaItemParser, import_name_type: &mut Option<(PeImportNameType, Span)>, cx: &mut AcceptContext<'_, '_, S>, ) -> bool { @@ -478,7 +478,7 @@ impl SingleAttributeParser for LinkSectionParser { "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -551,7 +551,7 @@ impl SingleAttributeParser for LinkOrdinalParser { "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ordinal = parse_single_integer(cx, args)?; // According to the table at @@ -607,7 +607,7 @@ impl SingleAttributeParser for LinkageParser { "weak_odr", ]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(name_value) = args.name_value() else { cx.expected_name_value(cx.attr_span, Some(sym::linkage)); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index d2fa1d440f40..e4209c3edd85 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -148,7 +148,7 @@ impl SingleAttributeParser for MacroExportParser { Error(Target::Crate), ]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let local_inner_macros = match args { ArgParser::NoArgs => false, ArgParser::List(list) => { diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 64bcb02b0b74..a26159cb09e7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -62,7 +62,7 @@ pub(crate) mod transparency; pub(crate) mod util; -type AcceptFn = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>); +type AcceptFn = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser); type AcceptMapping = &'static [(&'static [Symbol], AttributeTemplate, AcceptFn)]; /// An [`AttributeParser`] is a type which searches for syntactic attributes. @@ -133,7 +133,7 @@ pub(crate) trait SingleAttributeParser: 'static { const TEMPLATE: AttributeTemplate; /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option; + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option; } /// Use in combination with [`SingleAttributeParser`]. @@ -282,7 +282,7 @@ impl, S: Stage> SingleAttributeParser for Without const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { if let Err(span) = args.no_args() { cx.expected_no_args(span); } @@ -317,7 +317,7 @@ pub(crate) trait CombineAttributeParser: 'static { /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c; } diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index 51b43e96adf9..a27e1ecb707e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -29,7 +29,7 @@ impl SingleAttributeParser for MustUseParser { "https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { Some(AttributeKind::MustUse { span: cx.attr_span, reason: match args { diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs index e4cb806bb427..b60f8e315e5e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/path.rs +++ b/compiler/rustc_attr_parsing/src/attributes/path.rs @@ -13,7 +13,7 @@ impl SingleAttributeParser for PathParser { "https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index b9929d6f1f8e..e1762005d4c4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -30,7 +30,7 @@ impl SingleAttributeParser for ProcMacroDeriveParser { "https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let (trait_name, helper_attrs) = parse_derive_like(cx, args, true)?; Some(AttributeKind::ProcMacroDerive { trait_name: trait_name.expect("Trait name is mandatory, so it is present"), @@ -49,7 +49,7 @@ impl SingleAttributeParser for RustcBuiltinMacroParser { const TEMPLATE: AttributeTemplate = template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let (builtin_name, helper_attrs) = parse_derive_like(cx, args, false)?; Some(AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, span: cx.attr_span }) } @@ -57,7 +57,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option( cx: &mut AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, trait_name_mandatory: bool, ) -> Option<(Option, ThinVec)> { let Some(list) = args.list() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs index 80fe82bf5429..cd7c84f45fe5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs @@ -25,7 +25,7 @@ impl SingleAttributeParser for CustomMirParser { const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(list) = args.list() else { cx.expected_list(cx.attr_span); return None; @@ -70,7 +70,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option( cx: &mut AcceptContext<'_, '_, S>, key: Symbol, - arg: &ArgParser<'_>, + arg: &ArgParser, span: Span, out_val: &mut Option<(Symbol, Span)>, failed: &mut bool, diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 0330e2515c7d..c7320bf5d96f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -28,7 +28,7 @@ impl CombineAttributeParser for ReprParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { let mut reprs = Vec::new(); @@ -98,10 +98,7 @@ fn int_type_of_word(s: Symbol) -> Option { } } -fn parse_repr( - cx: &AcceptContext<'_, '_, S>, - param: &MetaItemParser<'_>, -) -> Option { +fn parse_repr(cx: &AcceptContext<'_, '_, S>, param: &MetaItemParser) -> Option { use ReprAttr::*; // FIXME(jdonszelmann): invert the parsing here to match on the word first and then the @@ -192,7 +189,7 @@ enum AlignKind { fn parse_repr_align( cx: &AcceptContext<'_, '_, S>, - list: &MetaItemListParser<'_>, + list: &MetaItemListParser, param_span: Span, align_kind: AlignKind, ) -> Option { @@ -278,11 +275,7 @@ impl AlignParser { const PATH: &'static [Symbol] = &[sym::rustc_align]; const TEMPLATE: AttributeTemplate = template!(List: &[""]); - fn parse<'c, S: Stage>( - &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, - ) { + fn parse<'c, S: Stage>(&mut self, cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser) { match args { ArgParser::NoArgs | ArgParser::NameValue(_) => { cx.expected_list(cx.attr_span); @@ -339,11 +332,7 @@ impl AlignStaticParser { const PATH: &'static [Symbol] = &[sym::rustc_align_static]; const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE; - fn parse<'c, S: Stage>( - &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, - ) { + fn parse<'c, S: Stage>(&mut self, cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser) { self.0.parse(cx, args) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 455c61097d78..d51fa2510b93 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -19,7 +19,7 @@ impl SingleAttributeParser for RustcLayoutScalarValidRangeStartPars const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(List: &["start"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { parse_single_integer(cx, args) .map(|n| AttributeKind::RustcLayoutScalarValidRangeStart(Box::new(n), cx.attr_span)) } @@ -34,7 +34,7 @@ impl SingleAttributeParser for RustcLayoutScalarValidRangeEndParser const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(List: &["end"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { parse_single_integer(cx, args) .map(|n| AttributeKind::RustcLayoutScalarValidRangeEnd(Box::new(n), cx.attr_span)) } @@ -49,7 +49,7 @@ impl SingleAttributeParser for RustcObjectLifetimeDefaultParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { if let Err(span) = args.no_args() { cx.expected_no_args(span); return None; @@ -68,7 +68,7 @@ impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index b94e23477ffe..b3ebb0f4fec1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -267,7 +267,7 @@ fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option /// `name = value` fn insert_value_into_option_or_error( cx: &AcceptContext<'_, '_, S>, - param: &MetaItemParser<'_>, + param: &MetaItemParser, item: &mut Option, name: Ident, ) -> Option<()> { @@ -289,7 +289,7 @@ fn insert_value_into_option_or_error( /// its stability information. pub(crate) fn parse_stability( cx: &AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, ) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; let mut since = None; @@ -365,7 +365,7 @@ pub(crate) fn parse_stability( /// attribute, and return the feature name and its stability information. pub(crate) fn parse_unstability( cx: &AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, ) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; let mut reason = None; diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index e0b006030758..7f25641b948e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -15,7 +15,7 @@ impl SingleAttributeParser for IgnoreParser { "https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { Some(AttributeKind::Ignore { span: cx.attr_span, reason: match args { @@ -49,7 +49,7 @@ impl SingleAttributeParser for ShouldPanicParser { "https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { Some(AttributeKind::ShouldPanic { span: cx.attr_span, reason: match args { diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index 753892d1e997..a9b76021a989 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -18,7 +18,7 @@ impl SingleAttributeParser for SkipDuringMethodDispatchParser { const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let mut array = false; let mut boxed_slice = false; let Some(args) = args.list() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index ea1f5549c4ec..52aa42b1085a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -17,7 +17,7 @@ impl SingleAttributeParser for TransparencyParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["transparent", "semitransparent", "opaque"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 105f7164bf3b..4e3478abbf4f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -40,7 +40,7 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool { /// `args` is the parser for the attribute arguments. pub(crate) fn parse_single_integer( cx: &mut AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, ) -> Option { let Some(list) = args.list() else { cx.expected_list(cx.attr_span); diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index f41ea3708788..074f3b4194ae 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -75,7 +75,7 @@ }; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; -use crate::parser::{ArgParser, PathParser}; +use crate::parser::{ArgParser, RefPathParser}; use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, ParsedDescription, UnknownMetaItem, }; @@ -95,7 +95,7 @@ pub(super) struct GroupTypeInnerAccept { } type AcceptFn = - Box Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser<'a>) + Send + Sync>; + Box Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>; type FinalizeFn = Box) -> Option>; @@ -713,7 +713,7 @@ pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> { /// /// Usually, you should use normal attribute parsing logic instead, /// especially when making a *denylist* of other attributes. - pub(crate) all_attrs: &'p [PathParser<'p>], + pub(crate) all_attrs: &'p [RefPathParser<'p>], } impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 45b46803419d..732f8d6e3a2a 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -1,4 +1,3 @@ -use std::borrow::Cow; use std::convert::identity; use rustc_ast as ast; @@ -14,7 +13,7 @@ use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage}; -use crate::parser::{ArgParser, PathParser}; +use crate::parser::{ArgParser, PathParser, RefPathParser}; use crate::session_diagnostics::ParsedDescription; use crate::{Early, Late, OmitDoc, ShouldEmit}; @@ -137,7 +136,7 @@ pub fn parse_single( target_node_id: NodeId, features: Option<&'sess Features>, emit_errors: ShouldEmit, - parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> Option, + parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option, template: &AttributeTemplate, ) -> Option { let ast::AttrKind::Normal(normal_attr) = &attr.kind else { @@ -269,7 +268,7 @@ pub fn parse_attribute_list( mut emit_lint: impl FnMut(AttributeLint), ) -> Vec { let mut attributes = Vec::new(); - let mut attr_paths = Vec::new(); + let mut attr_paths: Vec> = Vec::new(); for attr in attrs { // If we're only looking for a single attribute, skip all the ones we don't care about. @@ -303,7 +302,7 @@ pub fn parse_attribute_list( })) } ast::AttrKind::Normal(n) => { - attr_paths.push(PathParser(Cow::Borrowed(&n.item.path))); + attr_paths.push(PathParser(&n.item.path)); let attr_path = AttrPath::from_ast(&n.item.path, lower_span); self.check_attribute_safety( diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 2304fb0ca63c..09ecfaedb5ed 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -3,7 +3,7 @@ //! //! FIXME(jdonszelmann): delete `rustc_ast/attr/mod.rs` -use std::borrow::Cow; +use std::borrow::Borrow; use std::fmt::{Debug, Display}; use rustc_ast::token::{self, Delimiter, MetaVarKind}; @@ -26,9 +26,12 @@ }; #[derive(Clone, Debug)] -pub struct PathParser<'a>(pub Cow<'a, Path>); +pub struct PathParser>(pub P); -impl<'a> PathParser<'a> { +pub type OwnedPathParser = PathParser; +pub type RefPathParser<'p> = PathParser<&'p Path>; + +impl> PathParser

{ pub fn get_attribute_path(&self) -> hir::AttrPath { AttrPath { segments: self.segments().copied().collect::>().into_boxed_slice(), @@ -36,16 +39,16 @@ pub fn get_attribute_path(&self) -> hir::AttrPath { } } - pub fn segments(&'a self) -> impl Iterator { - self.0.segments.iter().map(|seg| &seg.ident) + pub fn segments(&self) -> impl Iterator { + self.0.borrow().segments.iter().map(|seg| &seg.ident) } pub fn span(&self) -> Span { - self.0.span + self.0.borrow().span } pub fn len(&self) -> usize { - self.0.segments.len() + self.0.borrow().segments.len() } pub fn segments_is(&self, segments: &[Symbol]) -> bool { @@ -76,21 +79,21 @@ pub fn starts_with(&self, segments: &[Symbol]) -> bool { } } -impl Display for PathParser<'_> { +impl> Display for PathParser

{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", pprust::path_to_string(&self.0)) + write!(f, "{}", pprust::path_to_string(self.0.borrow())) } } #[derive(Clone, Debug)] #[must_use] -pub enum ArgParser<'a> { +pub enum ArgParser { NoArgs, - List(MetaItemListParser<'a>), + List(MetaItemListParser), NameValue(NameValueParser), } -impl<'a> ArgParser<'a> { +impl ArgParser { pub fn span(&self) -> Option { match self { Self::NoArgs => None, @@ -100,7 +103,7 @@ pub fn span(&self) -> Option { } pub fn from_attr_args<'sess>( - value: &'a AttrArgs, + value: &AttrArgs, parts: &[Symbol], psess: &'sess ParseSess, should_emit: ShouldEmit, @@ -144,7 +147,7 @@ pub fn from_attr_args<'sess>( /// /// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list /// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list - pub fn list(&self) -> Option<&MetaItemListParser<'a>> { + pub fn list(&self) -> Option<&MetaItemListParser> { match self { Self::List(l) => Some(l), Self::NameValue(_) | Self::NoArgs => None, @@ -184,17 +187,17 @@ pub fn no_args(&self) -> Result<(), Span> { /// /// Choose which one you want using the provided methods. #[derive(Debug, Clone)] -pub enum MetaItemOrLitParser<'a> { - MetaItemParser(MetaItemParser<'a>), +pub enum MetaItemOrLitParser { + MetaItemParser(MetaItemParser), Lit(MetaItemLit), Err(Span, ErrorGuaranteed), } -impl<'sess> MetaItemOrLitParser<'sess> { - pub fn parse_single( +impl MetaItemOrLitParser { + pub fn parse_single<'sess>( parser: &mut Parser<'sess>, should_emit: ShouldEmit, - ) -> PResult<'sess, MetaItemOrLitParser<'static>> { + ) -> PResult<'sess, MetaItemOrLitParser> { let mut this = MetaItemListParserContext { parser, should_emit }; this.parse_meta_item_inner() } @@ -216,7 +219,7 @@ pub fn lit(&self) -> Option<&MetaItemLit> { } } - pub fn meta_item(&self) -> Option<&MetaItemParser<'sess>> { + pub fn meta_item(&self) -> Option<&MetaItemParser> { match self { MetaItemOrLitParser::MetaItemParser(parser) => Some(parser), _ => None, @@ -238,12 +241,12 @@ pub fn meta_item(&self) -> Option<&MetaItemParser<'sess>> { /// /// The syntax of MetaItems can be found at #[derive(Clone)] -pub struct MetaItemParser<'a> { - path: PathParser<'a>, - args: ArgParser<'a>, +pub struct MetaItemParser { + path: OwnedPathParser, + args: ArgParser, } -impl<'a> Debug for MetaItemParser<'a> { +impl Debug for MetaItemParser { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MetaItemParser") .field("path", &self.path) @@ -252,12 +255,12 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { } } -impl<'a> MetaItemParser<'a> { +impl MetaItemParser { pub fn span(&self) -> Span { if let Some(other) = self.args.span() { - self.path.span().with_hi(other.hi()) + self.path.borrow().span().with_hi(other.hi()) } else { - self.path.span() + self.path.borrow().span() } } @@ -266,12 +269,12 @@ pub fn span(&self) -> Span { /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path /// - `#[inline]`: `inline` is a single segment path - pub fn path(&self) -> &PathParser<'a> { + pub fn path(&self) -> &OwnedPathParser { &self.path } /// Gets just the args parser, without caring about the path. - pub fn args(&self) -> &ArgParser<'a> { + pub fn args(&self) -> &ArgParser { &self.args } @@ -281,7 +284,7 @@ pub fn args(&self) -> &ArgParser<'a> { /// - `#[inline]`: `inline` is a word /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path, /// and not a word and should instead be parsed using [`path`](Self::path) - pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> { + pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser> { self.path().word_is(sym).then(|| self.args()) } } @@ -405,7 +408,7 @@ fn unsuffixed_meta_item_from_lit( Ok(lit) } - fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser<'static>> { + fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser> { if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() { return if has_meta_form { let attr_item = self @@ -441,10 +444,10 @@ fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser<'static>> { ArgParser::NoArgs }; - Ok(MetaItemParser { path: PathParser(Cow::Owned(path)), args }) + Ok(MetaItemParser { path: PathParser(path), args }) } - fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser<'static>> { + fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> { if let Some(token_lit) = self.parser.eat_token_lit() { // If a literal token is parsed, we commit to parsing a MetaItemLit for better errors Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?)) @@ -531,7 +534,7 @@ fn parse( psess: &'sess ParseSess, span: Span, should_emit: ShouldEmit, - ) -> PResult<'sess, MetaItemListParser<'static>> { + ) -> PResult<'sess, MetaItemListParser> { let mut parser = Parser::new(psess, tokens, None); let mut this = MetaItemListParserContext { parser: &mut parser, should_emit }; @@ -554,14 +557,14 @@ fn parse( } #[derive(Debug, Clone)] -pub struct MetaItemListParser<'a> { - sub_parsers: ThinVec>, +pub struct MetaItemListParser { + sub_parsers: ThinVec, pub span: Span, } -impl<'a> MetaItemListParser<'a> { +impl MetaItemListParser { pub(crate) fn new<'sess>( - tokens: &'a TokenStream, + tokens: &TokenStream, span: Span, psess: &'sess ParseSess, should_emit: ShouldEmit, @@ -570,7 +573,7 @@ pub(crate) fn new<'sess>( } /// Lets you pick and choose as what you want to parse each element in the list - pub fn mixed(&self) -> impl Iterator> { + pub fn mixed(&self) -> impl Iterator { self.sub_parsers.iter() } @@ -585,7 +588,7 @@ pub fn is_empty(&self) -> bool { /// Returns Some if the list contains only a single element. /// /// Inside the Some is the parser to parse this single element. - pub fn single(&self) -> Option<&MetaItemOrLitParser<'a>> { + pub fn single(&self) -> Option<&MetaItemOrLitParser> { let mut iter = self.mixed(); iter.next().filter(|_| iter.next().is_none()) } From aa6db80ab20f8b3b0a8bb51217b412ec4f426b3b Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 8 Dec 2025 22:56:09 +0100 Subject: [PATCH 537/585] Remove lifetime param from parser functions --- .../src/attributes/allow_unstable.rs | 20 +++--- .../rustc_attr_parsing/src/attributes/cfg.rs | 6 +- .../src/attributes/codegen_attrs.rs | 24 +++---- .../src/attributes/debugger.rs | 8 +-- .../rustc_attr_parsing/src/attributes/doc.rs | 62 +++++++++---------- .../src/attributes/link_attrs.rs | 8 +-- .../rustc_attr_parsing/src/attributes/mod.rs | 8 +-- .../rustc_attr_parsing/src/attributes/repr.rs | 12 ++-- compiler/rustc_attr_parsing/src/interface.rs | 2 +- 9 files changed, 73 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index faa366a62831..79f7171cc0c8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -17,9 +17,9 @@ impl CombineAttributeParser for AllowInternalUnstableParser { ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, ) -> impl IntoIterator { parse_unstable(cx, args, >::PATH[0]) .into_iter() @@ -39,9 +39,9 @@ impl CombineAttributeParser for UnstableFeatureBoundParser { ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, ) -> impl IntoIterator { if !cx.features().staged_api() { cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span }); @@ -67,10 +67,10 @@ impl CombineAttributeParser for AllowConstFnUnstableParser { ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { parse_unstable(cx, args, >::PATH[0]) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 61c314b41b65..8c3896975201 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -35,9 +35,9 @@ "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute" ); -pub fn parse_cfg<'c, S: Stage>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, +pub fn parse_cfg( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, ) -> Option { let ArgParser::List(list) = args else { cx.expected_list(cx.attr_span); diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index ce208203ec5e..7d3a7418f06c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -472,10 +472,10 @@ fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { } } -fn parse_tf_attribute<'c, S: Stage>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, -) -> impl IntoIterator + 'c { +fn parse_tf_attribute( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, +) -> impl IntoIterator { let mut features = Vec::new(); let ArgParser::List(list) = args else { cx.expected_list(cx.attr_span); @@ -529,10 +529,10 @@ impl CombineAttributeParser for TargetFeatureParser { }; const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { parse_tf_attribute(cx, args) } @@ -567,10 +567,10 @@ impl CombineAttributeParser for ForceTargetFeatureParser { Allow(Target::Method(MethodKind::TraitImpl)), ]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { parse_tf_attribute(cx, args) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs index dfb3b914e189..c88b795aab03 100644 --- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -16,10 +16,10 @@ impl CombineAttributeParser for DebuggerViualizerParser { type Item = DebugVisualizer; const CONVERT: ConvertFn = |v, _| AttributeKind::DebuggerVisualizer(v); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { let Some(l) = args.list() else { cx.expected_list(args.span().unwrap_or(cx.attr_span)); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 547f00d14041..b6fea37c92aa 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -10,7 +10,7 @@ use super::prelude::{ALL_TARGETS, AllowedTargets}; use super::{AcceptMapping, AttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; -use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, PathParser}; +use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser}; use crate::session_diagnostics::{ DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttributeNotAttribute, DocKeywordNotKeyword, @@ -43,10 +43,10 @@ fn check_attribute( false } -fn parse_keyword_and_attribute<'c, S, F>( - cx: &'c mut AcceptContext<'_, '_, S>, - path: &PathParser<'_>, - args: &ArgParser<'_>, +fn parse_keyword_and_attribute( + cx: &mut AcceptContext<'_, '_, S>, + path: &OwnedPathParser, + args: &ArgParser, attr_value: &mut Option<(Symbol, Span)>, callback: F, ) where @@ -82,10 +82,10 @@ pub(crate) struct DocParser { } impl DocParser { - fn parse_single_test_doc_attr_item<'c, S: Stage>( + fn parse_single_test_doc_attr_item( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - mip: &'c MetaItemParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + mip: &MetaItemParser, ) { let path = mip.path(); let args = mip.args(); @@ -132,9 +132,9 @@ fn parse_single_test_doc_attr_item<'c, S: Stage>( } } - fn add_alias<'c, S: Stage>( + fn add_alias( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, + cx: &mut AcceptContext<'_, '_, S>, alias: Symbol, span: Span, ) { @@ -167,11 +167,11 @@ fn add_alias<'c, S: Stage>( self.attribute.aliases.insert(alias, span); } - fn parse_alias<'c, S: Stage>( + fn parse_alias( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - path: &PathParser<'_>, - args: &ArgParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + path: &OwnedPathParser, + args: &ArgParser, ) { match args { ArgParser::NoArgs => { @@ -197,11 +197,11 @@ fn parse_alias<'c, S: Stage>( } } - fn parse_inline<'c, S: Stage>( + fn parse_inline( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - path: &PathParser<'_>, - args: &ArgParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + path: &OwnedPathParser, + args: &ArgParser, inline: DocInline, ) { if let Err(span) = args.no_args() { @@ -212,11 +212,7 @@ fn parse_inline<'c, S: Stage>( self.attribute.inline.push((inline, path.span())); } - fn parse_cfg<'c, S: Stage>( - &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, - ) { + fn parse_cfg(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) { // This function replaces cases like `cfg(all())` with `true`. fn simplify_cfg(cfg_entry: &mut CfgEntry) { match cfg_entry { @@ -236,11 +232,11 @@ fn simplify_cfg(cfg_entry: &mut CfgEntry) { } } - fn parse_auto_cfg<'c, S: Stage>( + fn parse_auto_cfg( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - path: &PathParser<'_>, - args: &ArgParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + path: &OwnedPathParser, + args: &ArgParser, ) { match args { ArgParser::NoArgs => { @@ -343,10 +339,10 @@ fn parse_auto_cfg<'c, S: Stage>( } } - fn parse_single_doc_attr_item<'c, S: Stage>( + fn parse_single_doc_attr_item( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - mip: &MetaItemParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + mip: &MetaItemParser, ) { let path = mip.path(); let args = mip.args(); @@ -506,10 +502,10 @@ macro_rules! string_arg { } } - fn accept_single_doc_attr<'c, S: Stage>( + fn accept_single_doc_attr( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, ) { match args { ArgParser::NoArgs => { diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 67471e31b105..fe8f3578fe14 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -62,10 +62,10 @@ impl CombineAttributeParser for LinkParser { ], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { let items = match args { ArgParser::List(list) => list, // This is an edgecase added because making this a hard error would break too many crates diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index a26159cb09e7..bd58c44214a2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -315,10 +315,10 @@ pub(crate) trait CombineAttributeParser: 'static { const TEMPLATE: AttributeTemplate; /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c; + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator; } /// Use in combination with [`CombineAttributeParser`]. diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index c7320bf5d96f..4520e4f5dbac 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -26,10 +26,10 @@ impl CombineAttributeParser for ReprParser { "https://doc.rust-lang.org/reference/type-layout.html#representations" ); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { let mut reprs = Vec::new(); let Some(list) = args.list() else { @@ -275,7 +275,7 @@ impl AlignParser { const PATH: &'static [Symbol] = &[sym::rustc_align]; const TEMPLATE: AttributeTemplate = template!(List: &[""]); - fn parse<'c, S: Stage>(&mut self, cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser) { + fn parse(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) { match args { ArgParser::NoArgs | ArgParser::NameValue(_) => { cx.expected_list(cx.attr_span); @@ -332,7 +332,7 @@ impl AlignStaticParser { const PATH: &'static [Symbol] = &[sym::rustc_align_static]; const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE; - fn parse<'c, S: Stage>(&mut self, cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser) { + fn parse(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) { self.0.parse(cx, args) } } diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 732f8d6e3a2a..91596ff0de60 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -342,7 +342,7 @@ pub fn parse_attribute_list( // blob // a if is_doc_attribute - && let ArgParser::NameValue(nv) = args + && let ArgParser::NameValue(nv) = &args // If not a string key/value, it should emit an error, but to make // things simpler, it's handled in `DocParser` because it's simpler to // emit an error with `AcceptContext`. From 04fedf71738c44e716b01480550787d99c47a254 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 12 Dec 2025 09:12:31 +0100 Subject: [PATCH 538/585] Remove unused code in `cfg_old` --- compiler/rustc_attr_parsing/messages.ftl | 10 - .../rustc_attr_parsing/src/attributes/cfg.rs | 22 +- .../src/attributes/cfg_old.rs | 210 ------------------ .../rustc_attr_parsing/src/attributes/mod.rs | 1 - .../src/attributes/stability.rs | 4 +- compiler/rustc_attr_parsing/src/lib.rs | 1 - .../src/session_diagnostics.rs | 37 +-- 7 files changed, 22 insertions(+), 263 deletions(-) delete mode 100644 compiler/rustc_attr_parsing/src/attributes/cfg_old.rs diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index f2642838b3c8..deebc25c8259 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -6,9 +6,6 @@ attr_parsing_bundle_needs_static = attr_parsing_cfg_attr_bad_delim = wrong `cfg_attr` delimiters -attr_parsing_cfg_predicate_identifier = - `cfg` predicate key must be an identifier - attr_parsing_deprecated_item_suggestion = suggestions on deprecated items are unstable .help = add `#![feature(deprecated_suggestion)]` to the crate root @@ -41,9 +38,6 @@ attr_parsing_empty_link_name = link name must not be empty .label = empty link name -attr_parsing_expected_one_cfg_pattern = - expected 1 cfg-pattern - attr_parsing_expected_single_version_literal = expected single version literal @@ -241,10 +235,6 @@ attr_parsing_unstable_cfg_target_compact = attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable .help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` -attr_parsing_unsupported_literal_cfg_boolean = - literal in `cfg` predicate value must be a boolean -attr_parsing_unsupported_literal_cfg_string = - literal in `cfg` predicate value must be a string attr_parsing_unsupported_literal_generic = unsupported literal attr_parsing_unsupported_literal_suggestion = diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 6ffe25098308..93f425530941 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -4,7 +4,9 @@ use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token}; use rustc_errors::{Applicability, PResult}; -use rustc_feature::{AttrSuggestionStyle, AttributeTemplate, Features, template}; +use rustc_feature::{ + AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template, +}; use rustc_hir::attrs::CfgEntry; use rustc_hir::lints::AttributeLintKind; use rustc_hir::{AttrPath, RustcVersion}; @@ -23,7 +25,7 @@ AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg, ParsedDescription, }; -use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics, try_gate_cfg}; +use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics}; pub const CFG_TEMPLATE: AttributeTemplate = template!( List: &["predicate"], @@ -410,3 +412,19 @@ fn parse_cfg_attr_internal<'a>( Ok((cfg_predicate, expanded_attrs)) } + +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(); + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs deleted file mode 100644 index acb234480d5d..000000000000 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ /dev/null @@ -1,210 +0,0 @@ -use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId}; -use rustc_ast_pretty::pprust; -use rustc_feature::{Features, GatedCfg, find_gated_cfg}; -use rustc_hir::RustcVersion; -use rustc_session::Session; -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, -} - -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 - || cfg.path.segments[0].ident.is_path_segment_keyword() => - { - 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 64bcb02b0b74..385003a35927 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -32,7 +32,6 @@ pub(crate) mod allow_unstable; pub(crate) mod body; pub(crate) mod cfg; -pub(crate) mod cfg_old; pub(crate) mod cfg_select; pub(crate) mod codegen_attrs; pub(crate) mod confusables; diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index b94e23477ffe..b97095893b8e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -8,7 +8,7 @@ use super::prelude::*; use super::util::parse_version; -use crate::session_diagnostics::{self, UnsupportedLiteralReason}; +use crate::session_diagnostics::{self}; macro_rules! reject_outside_std { ($cx: ident) => { @@ -304,7 +304,6 @@ pub(crate) fn parse_stability( let Some(param) = param.meta_item() else { cx.emit_err(session_diagnostics::UnsupportedLiteral { span: param_span, - reason: UnsupportedLiteralReason::Generic, is_bytestr: false, start_point_span: cx.sess().source_map().start_point(param_span), }); @@ -384,7 +383,6 @@ pub(crate) fn parse_unstability( let Some(param) = param.meta_item() else { cx.emit_err(session_diagnostics::UnsupportedLiteral { span: param.span(), - reason: UnsupportedLiteralReason::Generic, is_bytestr: false, start_point_span: cx.sess().source_map().start_point(param.span()), }); diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index cb02bb9d501f..411b4dd75e66 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -107,7 +107,6 @@ pub use attributes::cfg::{ CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry, }; -pub use attributes::cfg_old::*; pub use attributes::cfg_select::*; pub use attributes::util::{is_builtin_attr, parse_version}; pub use context::{Early, Late, OmitDoc, ShouldEmit}; diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 7bb55d2a6de5..df555a33f816 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -12,19 +12,6 @@ use crate::fluent_generated as fluent; -pub(crate) enum UnsupportedLiteralReason { - Generic, - CfgString, - CfgBoolean, -} - -#[derive(Diagnostic)] -#[diag(attr_parsing_expected_one_cfg_pattern, code = E0536)] -pub(crate) struct ExpectedOneCfgPattern { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(attr_parsing_invalid_predicate, code = E0537)] pub(crate) struct InvalidPredicate { @@ -234,28 +221,13 @@ pub(crate) struct InvalidReprHintNoValue { // FIXME(jdonszelmann): slowly phased out pub(crate) struct UnsupportedLiteral { pub span: Span, - pub reason: UnsupportedLiteralReason, pub is_bytestr: bool, pub start_point_span: Span, } impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { - let mut diag = Diag::new( - dcx, - level, - match self.reason { - UnsupportedLiteralReason::Generic => { - fluent::attr_parsing_unsupported_literal_generic - } - UnsupportedLiteralReason::CfgString => { - fluent::attr_parsing_unsupported_literal_cfg_string - } - UnsupportedLiteralReason::CfgBoolean => { - fluent::attr_parsing_unsupported_literal_cfg_boolean - } - }, - ); + let mut diag = Diag::new(dcx, level, fluent::attr_parsing_unsupported_literal_generic); diag.span(self.span); diag.code(E0565); if self.is_bytestr { @@ -375,13 +347,6 @@ pub(crate) struct RustcAllowedUnstablePairing { pub span: Span, } -#[derive(Diagnostic)] -#[diag(attr_parsing_cfg_predicate_identifier)] -pub(crate) struct CfgPredicateIdentifier { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(attr_parsing_deprecated_item_suggestion)] pub(crate) struct DeprecatedItemSuggestion { From acea7df0b4fdba04f94528f19ea1333cd68d2670 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 12 Dec 2025 09:24:49 +0100 Subject: [PATCH 539/585] Remove last remaining usages of `UnsupportedLiteral` --- compiler/rustc_attr_parsing/messages.ftl | 2 -- .../src/attributes/stability.rs | 12 ++------- .../src/session_diagnostics.rs | 25 ------------------- 3 files changed, 2 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index deebc25c8259..61f816f0baf8 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -235,8 +235,6 @@ attr_parsing_unstable_cfg_target_compact = attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable .help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` -attr_parsing_unsupported_literal_generic = - unsupported literal attr_parsing_unsupported_literal_suggestion = consider removing the prefix diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index b97095893b8e..fede424c3af7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -302,11 +302,7 @@ pub(crate) fn parse_stability( for param in list.mixed() { let param_span = param.span(); let Some(param) = param.meta_item() else { - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: param_span, - is_bytestr: false, - start_point_span: cx.sess().source_map().start_point(param_span), - }); + cx.unexpected_literal(param.span()); return None; }; @@ -381,11 +377,7 @@ pub(crate) fn parse_unstability( for param in list.mixed() { let Some(param) = param.meta_item() else { - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: param.span(), - is_bytestr: false, - start_point_span: cx.sess().source_map().start_point(param.span()), - }); + cx.unexpected_literal(param.span()); return None; }; diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index df555a33f816..3adbe115b23b 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -217,31 +217,6 @@ pub(crate) struct InvalidReprHintNoValue { pub name: Symbol, } -/// Error code: E0565 -// FIXME(jdonszelmann): slowly phased out -pub(crate) struct UnsupportedLiteral { - pub span: Span, - pub is_bytestr: bool, - pub start_point_span: Span, -} - -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral { - fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { - let mut diag = Diag::new(dcx, level, fluent::attr_parsing_unsupported_literal_generic); - diag.span(self.span); - diag.code(E0565); - if self.is_bytestr { - diag.span_suggestion( - self.start_point_span, - fluent::attr_parsing_unsupported_literal_suggestion, - "", - Applicability::MaybeIncorrect, - ); - } - diag - } -} - #[derive(Diagnostic)] #[diag(attr_parsing_invalid_repr_align_need_arg, code = E0589)] pub(crate) struct InvalidReprAlignNeedArg { From 0ac215aabefcc1e5b782caf788b061d8ae8b9e5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 28 Jul 2025 10:35:42 +0200 Subject: [PATCH 540/585] EII tests --- tests/ui/eii/auxiliary/codegen1.rs | 18 +++ tests/ui/eii/auxiliary/codegen2.rs | 6 + tests/ui/eii/auxiliary/codegen3.rs | 22 ++++ .../auxiliary/cross_crate_eii_declaration.rs | 16 +++ tests/ui/eii/codegen_cross_crate.rs | 21 ++++ tests/ui/eii/codegen_cross_crate.run.stdout | 2 + tests/ui/eii/codegen_single_crate.rs | 20 ++++ tests/ui/eii/codegen_single_crate.run.stdout | 2 + tests/ui/eii/cross_crate.rs | 19 +++ tests/ui/eii/cross_crate_wrong_ty.rs | 19 +++ tests/ui/eii/cross_crate_wrong_ty.stderr | 16 +++ .../default/auxiliary/decl_with_default.rs | 8 ++ tests/ui/eii/default/auxiliary/impl1.rs | 12 ++ tests/ui/eii/default/call_default.rs | 13 +++ tests/ui/eii/default/call_default.run.stdout | 1 + tests/ui/eii/default/call_impl.rs | 16 +++ tests/ui/eii/default/call_impl.run.stdout | 1 + tests/ui/eii/default/local_crate.rs | 14 +++ tests/ui/eii/default/local_crate.run.stdout | 1 + tests/ui/eii/default/local_crate_explicit.rs | 20 ++++ .../default/local_crate_explicit.run.stdout | 1 + .../eii/default/local_crate_explicit.stderr | 10 ++ tests/ui/eii/duplicate/auxiliary/decl.rs | 6 + tests/ui/eii/duplicate/auxiliary/impl1.rs | 12 ++ tests/ui/eii/duplicate/auxiliary/impl2.rs | 12 ++ tests/ui/eii/duplicate/auxiliary/impl3.rs | 12 ++ tests/ui/eii/duplicate/auxiliary/impl4.rs | 12 ++ tests/ui/eii/duplicate/duplicate1.rs | 13 +++ tests/ui/eii/duplicate/duplicate1.stderr | 15 +++ tests/ui/eii/duplicate/duplicate2.rs | 15 +++ tests/ui/eii/duplicate/duplicate2.stderr | 16 +++ tests/ui/eii/duplicate/duplicate3.rs | 17 +++ tests/ui/eii/duplicate/duplicate3.stderr | 16 +++ tests/ui/eii/errors.rs | 45 +++++++ tests/ui/eii/errors.stderr | 98 ++++++++++++++++ tests/ui/eii/privacy1.rs | 31 +++++ tests/ui/eii/privacy1.run.stdout | 4 + tests/ui/eii/privacy2.rs | 27 +++++ tests/ui/eii/privacy2.stderr | 38 ++++++ tests/ui/eii/subtype_1.rs | 27 +++++ tests/ui/eii/subtype_1.stderr | 13 +++ tests/ui/eii/subtype_2.rs | 27 +++++ tests/ui/eii/subtype_2.stderr | 13 +++ tests/ui/eii/subtype_3.rs | 27 +++++ tests/ui/eii/subtype_4.rs | 27 +++++ tests/ui/eii/unsafe_impl_err.rs | 25 ++++ tests/ui/eii/unsafe_impl_err.stderr | 13 +++ tests/ui/eii/unsafe_impl_ok.rs | 27 +++++ tests/ui/eii/wrong_ret_ty.rs | 26 +++++ tests/ui/eii/wrong_ret_ty.stderr | 26 +++++ tests/ui/eii/wrong_target.rs | 63 ++++++++++ tests/ui/eii/wrong_target.stderr | 110 ++++++++++++++++++ tests/ui/eii/wrong_ty.rs | 26 +++++ tests/ui/eii/wrong_ty.stderr | 27 +++++ tests/ui/eii/wrong_ty_2.rs | 26 +++++ tests/ui/eii/wrong_ty_2.stderr | 14 +++ 56 files changed, 1164 insertions(+) create mode 100644 tests/ui/eii/auxiliary/codegen1.rs create mode 100644 tests/ui/eii/auxiliary/codegen2.rs create mode 100644 tests/ui/eii/auxiliary/codegen3.rs create mode 100644 tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs create mode 100644 tests/ui/eii/codegen_cross_crate.rs create mode 100644 tests/ui/eii/codegen_cross_crate.run.stdout create mode 100644 tests/ui/eii/codegen_single_crate.rs create mode 100644 tests/ui/eii/codegen_single_crate.run.stdout create mode 100644 tests/ui/eii/cross_crate.rs create mode 100644 tests/ui/eii/cross_crate_wrong_ty.rs create mode 100644 tests/ui/eii/cross_crate_wrong_ty.stderr create mode 100644 tests/ui/eii/default/auxiliary/decl_with_default.rs create mode 100644 tests/ui/eii/default/auxiliary/impl1.rs create mode 100644 tests/ui/eii/default/call_default.rs create mode 100644 tests/ui/eii/default/call_default.run.stdout create mode 100644 tests/ui/eii/default/call_impl.rs create mode 100644 tests/ui/eii/default/call_impl.run.stdout create mode 100644 tests/ui/eii/default/local_crate.rs create mode 100644 tests/ui/eii/default/local_crate.run.stdout create mode 100644 tests/ui/eii/default/local_crate_explicit.rs create mode 100644 tests/ui/eii/default/local_crate_explicit.run.stdout create mode 100644 tests/ui/eii/default/local_crate_explicit.stderr create mode 100644 tests/ui/eii/duplicate/auxiliary/decl.rs create mode 100644 tests/ui/eii/duplicate/auxiliary/impl1.rs create mode 100644 tests/ui/eii/duplicate/auxiliary/impl2.rs create mode 100644 tests/ui/eii/duplicate/auxiliary/impl3.rs create mode 100644 tests/ui/eii/duplicate/auxiliary/impl4.rs create mode 100644 tests/ui/eii/duplicate/duplicate1.rs create mode 100644 tests/ui/eii/duplicate/duplicate1.stderr create mode 100644 tests/ui/eii/duplicate/duplicate2.rs create mode 100644 tests/ui/eii/duplicate/duplicate2.stderr create mode 100644 tests/ui/eii/duplicate/duplicate3.rs create mode 100644 tests/ui/eii/duplicate/duplicate3.stderr create mode 100644 tests/ui/eii/errors.rs create mode 100644 tests/ui/eii/errors.stderr create mode 100644 tests/ui/eii/privacy1.rs create mode 100644 tests/ui/eii/privacy1.run.stdout create mode 100644 tests/ui/eii/privacy2.rs create mode 100644 tests/ui/eii/privacy2.stderr create mode 100644 tests/ui/eii/subtype_1.rs create mode 100644 tests/ui/eii/subtype_1.stderr create mode 100644 tests/ui/eii/subtype_2.rs create mode 100644 tests/ui/eii/subtype_2.stderr create mode 100644 tests/ui/eii/subtype_3.rs create mode 100644 tests/ui/eii/subtype_4.rs create mode 100644 tests/ui/eii/unsafe_impl_err.rs create mode 100644 tests/ui/eii/unsafe_impl_err.stderr create mode 100644 tests/ui/eii/unsafe_impl_ok.rs create mode 100644 tests/ui/eii/wrong_ret_ty.rs create mode 100644 tests/ui/eii/wrong_ret_ty.stderr create mode 100644 tests/ui/eii/wrong_target.rs create mode 100644 tests/ui/eii/wrong_target.stderr create mode 100644 tests/ui/eii/wrong_ty.rs create mode 100644 tests/ui/eii/wrong_ty.stderr create mode 100644 tests/ui/eii/wrong_ty_2.rs create mode 100644 tests/ui/eii/wrong_ty_2.stderr diff --git a/tests/ui/eii/auxiliary/codegen1.rs b/tests/ui/eii/auxiliary/codegen1.rs new file mode 100644 index 000000000000..93c5df2d41c0 --- /dev/null +++ b/tests/ui/eii/auxiliary/codegen1.rs @@ -0,0 +1,18 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(eii)] + +#[eii(eii1)] +fn decl1(x: u64); + +mod private { + #[eii(eii2)] + pub fn decl2(x: u64); +} + +pub use private::eii2 as eii3; +pub use private::decl2 as decl3; + +pub fn local_call_decl1(x: u64) { + decl1(x) +} diff --git a/tests/ui/eii/auxiliary/codegen2.rs b/tests/ui/eii/auxiliary/codegen2.rs new file mode 100644 index 000000000000..9545ad007c57 --- /dev/null +++ b/tests/ui/eii/auxiliary/codegen2.rs @@ -0,0 +1,6 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(eii)] + +#[eii(eii1)] +pub fn decl1(x: u64); diff --git a/tests/ui/eii/auxiliary/codegen3.rs b/tests/ui/eii/auxiliary/codegen3.rs new file mode 100644 index 000000000000..2b882c48d829 --- /dev/null +++ b/tests/ui/eii/auxiliary/codegen3.rs @@ -0,0 +1,22 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(eii)] + +// does have an impl but can't be called +#[eii(eii1)] +fn decl1(x: u64); + +#[eii(eii2)] +pub fn decl2(x: u64); + +mod private { + #[eii(eii3)] + pub fn decl3(x: u64); +} + +pub use private::eii3 as eii4; +pub use private::decl3 as decl4; + +pub fn local_call_decl1(x: u64) { + decl1(x) +} diff --git a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs new file mode 100644 index 000000000000..36a42ad199b0 --- /dev/null +++ b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs @@ -0,0 +1,16 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +pub macro foo() { + +} + +unsafe extern "Rust" { + pub safe fn bar(x: u64) -> u64; +} diff --git a/tests/ui/eii/codegen_cross_crate.rs b/tests/ui/eii/codegen_cross_crate.rs new file mode 100644 index 000000000000..b5b2d940b730 --- /dev/null +++ b/tests/ui/eii/codegen_cross_crate.rs @@ -0,0 +1,21 @@ +//@ run-pass +//@ check-run-results +//@ aux-build: codegen2.rs +//@ compile-flags: -O +// Tests whether calling EIIs works with the declaration in another crate. +#![feature(eii)] + +extern crate codegen2 as codegen; + +#[codegen::eii1] +fn eii1_impl(x: u64) { + println!("{x:?}") +} + +// what you would write: +fn main() { + // directly + eii1_impl(21); + // through the alias + codegen::decl1(42); +} diff --git a/tests/ui/eii/codegen_cross_crate.run.stdout b/tests/ui/eii/codegen_cross_crate.run.stdout new file mode 100644 index 000000000000..960b54672100 --- /dev/null +++ b/tests/ui/eii/codegen_cross_crate.run.stdout @@ -0,0 +1,2 @@ +21 +42 diff --git a/tests/ui/eii/codegen_single_crate.rs b/tests/ui/eii/codegen_single_crate.rs new file mode 100644 index 000000000000..c2d986d12c1a --- /dev/null +++ b/tests/ui/eii/codegen_single_crate.rs @@ -0,0 +1,20 @@ +//@ run-pass +//@ check-run-results +// Tests whether calling EIIs works with the declaration in the same crate. +#![feature(eii)] + +#[eii] +fn hello(x: u64); + +#[hello] +fn hello_impl(x: u64) { + println!("{x:?}") +} + +// what you would write: +fn main() { + // directly + hello_impl(21); + // through the alias + hello(42); +} diff --git a/tests/ui/eii/codegen_single_crate.run.stdout b/tests/ui/eii/codegen_single_crate.run.stdout new file mode 100644 index 000000000000..960b54672100 --- /dev/null +++ b/tests/ui/eii/codegen_single_crate.run.stdout @@ -0,0 +1,2 @@ +21 +42 diff --git a/tests/ui/eii/cross_crate.rs b/tests/ui/eii/cross_crate.rs new file mode 100644 index 000000000000..72f1533587bf --- /dev/null +++ b/tests/ui/eii/cross_crate.rs @@ -0,0 +1,19 @@ +//@ compile-flags: --crate-type rlib +//@ check-pass +//@ aux-build: cross_crate_eii_declaration.rs +// Tests whether calling EIIs works with the declaration in another crate. +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +extern crate cross_crate_eii_declaration; + +#[unsafe(cross_crate_eii_declaration::foo)] +fn other(x: u64) -> u64 { + x +} + +fn main() { + cross_crate_eii_declaration::bar(0); +} diff --git a/tests/ui/eii/cross_crate_wrong_ty.rs b/tests/ui/eii/cross_crate_wrong_ty.rs new file mode 100644 index 000000000000..f99b812b6c50 --- /dev/null +++ b/tests/ui/eii/cross_crate_wrong_ty.rs @@ -0,0 +1,19 @@ +//@ compile-flags: --crate-type rlib +//@ aux-build: cross_crate_eii_declaration.rs +// Tests whether the type checking still works properly when the declaration is in another crate. +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +extern crate cross_crate_eii_declaration; + +#[unsafe(cross_crate_eii_declaration::foo)] +fn other() -> u64 { +//~^ ERROR `other` has 0 parameters but #[foo] requires it to have 1 + 0 +} + +fn main() { + cross_crate_eii_declaration::bar(0); +} diff --git a/tests/ui/eii/cross_crate_wrong_ty.stderr b/tests/ui/eii/cross_crate_wrong_ty.stderr new file mode 100644 index 000000000000..c85974f78206 --- /dev/null +++ b/tests/ui/eii/cross_crate_wrong_ty.stderr @@ -0,0 +1,16 @@ +error[E0050]: `other` has 0 parameters but #[foo] requires it to have 1 + --> $DIR/cross_crate_wrong_ty.rs:12:1 + | +LL | #[unsafe(cross_crate_eii_declaration::foo)] + | ------------------------------------------- required because of this attribute +LL | fn other() -> u64 { + | ^^^^^^^^^^^^^^^^^ expected 1 parameter, found 0 + | + ::: $DIR/auxiliary/cross_crate_eii_declaration.rs:15:5 + | +LL | pub safe fn bar(x: u64) -> u64; + | ------------------------------- requires 1 parameter + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0050`. diff --git a/tests/ui/eii/default/auxiliary/decl_with_default.rs b/tests/ui/eii/default/auxiliary/decl_with_default.rs new file mode 100644 index 000000000000..b1811b07eb17 --- /dev/null +++ b/tests/ui/eii/default/auxiliary/decl_with_default.rs @@ -0,0 +1,8 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(eii)] + +#[eii(eii1)] +pub fn decl1(x: u64) { + println!("default {x}"); +} diff --git a/tests/ui/eii/default/auxiliary/impl1.rs b/tests/ui/eii/default/auxiliary/impl1.rs new file mode 100644 index 000000000000..4d627a5f68a6 --- /dev/null +++ b/tests/ui/eii/default/auxiliary/impl1.rs @@ -0,0 +1,12 @@ +//@ no-prefer-dynamic +//@ aux-build: decl_with_default.rs +#![crate_type = "rlib"] +#![feature(eii)] + +extern crate decl_with_default as decl; + + +#[unsafe(decl::eii1)] //~ ERROR multiple implementations of `#[eii1]` +fn other(x: u64) { + println!("1{x}"); +} diff --git a/tests/ui/eii/default/call_default.rs b/tests/ui/eii/default/call_default.rs new file mode 100644 index 000000000000..520863f1d3e9 --- /dev/null +++ b/tests/ui/eii/default/call_default.rs @@ -0,0 +1,13 @@ +//@ no-prefer-dynamic +//@ aux-build: decl_with_default.rs +//@ run-pass +//@ check-run-results +// Tests EIIs with default implementations. +// When there's no explicit declaration, the default should be called from the declaring crate. +#![feature(eii)] + +extern crate decl_with_default; + +fn main() { + decl_with_default::decl1(10); +} diff --git a/tests/ui/eii/default/call_default.run.stdout b/tests/ui/eii/default/call_default.run.stdout new file mode 100644 index 000000000000..1e49486f6aaf --- /dev/null +++ b/tests/ui/eii/default/call_default.run.stdout @@ -0,0 +1 @@ +default 10 diff --git a/tests/ui/eii/default/call_impl.rs b/tests/ui/eii/default/call_impl.rs new file mode 100644 index 000000000000..b81e604238ec --- /dev/null +++ b/tests/ui/eii/default/call_impl.rs @@ -0,0 +1,16 @@ +//@ no-prefer-dynamic +//@ aux-build: decl_with_default.rs +//@ aux-build: impl1.rs +//@ run-pass +//@ check-run-results +// Tests EIIs with default implementations. +// When an explicit implementation is given in one dependency, and the declaration is in another, +// the explicit implementation is preferred. +#![feature(eii)] + +extern crate decl_with_default; +extern crate impl1; + +fn main() { + decl_with_default::decl1(10); +} diff --git a/tests/ui/eii/default/call_impl.run.stdout b/tests/ui/eii/default/call_impl.run.stdout new file mode 100644 index 000000000000..bc6298e80ad4 --- /dev/null +++ b/tests/ui/eii/default/call_impl.run.stdout @@ -0,0 +1 @@ +110 diff --git a/tests/ui/eii/default/local_crate.rs b/tests/ui/eii/default/local_crate.rs new file mode 100644 index 000000000000..9ae471d90cbc --- /dev/null +++ b/tests/ui/eii/default/local_crate.rs @@ -0,0 +1,14 @@ +//@ run-pass +//@ check-run-results +// Tests EIIs with default implementations. +// In the same crate, when there's no explicit declaration, the default should be called. +#![feature(eii)] + +#[eii(eii1)] +pub fn decl1(x: u64) { + println!("default {x}"); +} + +fn main() { + decl1(4); +} diff --git a/tests/ui/eii/default/local_crate.run.stdout b/tests/ui/eii/default/local_crate.run.stdout new file mode 100644 index 000000000000..032082d92b72 --- /dev/null +++ b/tests/ui/eii/default/local_crate.run.stdout @@ -0,0 +1 @@ +default 4 diff --git a/tests/ui/eii/default/local_crate_explicit.rs b/tests/ui/eii/default/local_crate_explicit.rs new file mode 100644 index 000000000000..844d1d2911af --- /dev/null +++ b/tests/ui/eii/default/local_crate_explicit.rs @@ -0,0 +1,20 @@ +//@ run-pass +//@ check-run-results +// Tests EIIs with default implementations. +// In the same crate, the explicit implementation should get priority. +#![feature(eii)] + +#[eii(eii1)] +pub fn decl1(x: u64) { + //~^ WARN function `decl1` is never used + println!("default {x}"); +} + +#[eii1] +pub fn decl2(x: u64) { + println!("explicit {x}"); +} + +fn main() { + decl1(4); +} diff --git a/tests/ui/eii/default/local_crate_explicit.run.stdout b/tests/ui/eii/default/local_crate_explicit.run.stdout new file mode 100644 index 000000000000..d7ce3a9fb8ba --- /dev/null +++ b/tests/ui/eii/default/local_crate_explicit.run.stdout @@ -0,0 +1 @@ +explicit 4 diff --git a/tests/ui/eii/default/local_crate_explicit.stderr b/tests/ui/eii/default/local_crate_explicit.stderr new file mode 100644 index 000000000000..4102b35bcb5e --- /dev/null +++ b/tests/ui/eii/default/local_crate_explicit.stderr @@ -0,0 +1,10 @@ +warning: function `decl1` is never used + --> $DIR/local_crate_explicit.rs:9:8 + | +LL | pub fn decl1(x: u64) { + | ^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default + +warning: 1 warning emitted + diff --git a/tests/ui/eii/duplicate/auxiliary/decl.rs b/tests/ui/eii/duplicate/auxiliary/decl.rs new file mode 100644 index 000000000000..81557fa6891b --- /dev/null +++ b/tests/ui/eii/duplicate/auxiliary/decl.rs @@ -0,0 +1,6 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(eii)] + +#[eii(eii1)] +fn decl1(x: u64); diff --git a/tests/ui/eii/duplicate/auxiliary/impl1.rs b/tests/ui/eii/duplicate/auxiliary/impl1.rs new file mode 100644 index 000000000000..d7c27f4dfde9 --- /dev/null +++ b/tests/ui/eii/duplicate/auxiliary/impl1.rs @@ -0,0 +1,12 @@ +//@ no-prefer-dynamic +//@ aux-build: decl.rs +#![crate_type = "rlib"] +#![feature(eii)] + +extern crate decl; + + +#[unsafe(decl::eii1)] +fn other(x: u64) { + println!("1{x}"); +} diff --git a/tests/ui/eii/duplicate/auxiliary/impl2.rs b/tests/ui/eii/duplicate/auxiliary/impl2.rs new file mode 100644 index 000000000000..bce6f11b89c4 --- /dev/null +++ b/tests/ui/eii/duplicate/auxiliary/impl2.rs @@ -0,0 +1,12 @@ +//@ no-prefer-dynamic +//@ aux-build: decl.rs +#![crate_type = "rlib"] +#![feature(eii)] + +extern crate decl; + + +#[unsafe(decl::eii1)] +fn other(x: u64) { + println!("2{x}"); +} diff --git a/tests/ui/eii/duplicate/auxiliary/impl3.rs b/tests/ui/eii/duplicate/auxiliary/impl3.rs new file mode 100644 index 000000000000..82ba5af09863 --- /dev/null +++ b/tests/ui/eii/duplicate/auxiliary/impl3.rs @@ -0,0 +1,12 @@ +//@ no-prefer-dynamic +//@ aux-build: decl.rs +#![crate_type = "rlib"] +#![feature(eii)] + +extern crate decl; + + +#[unsafe(decl::eii1)] +fn other(x: u64) { + println!("3{x}"); +} diff --git a/tests/ui/eii/duplicate/auxiliary/impl4.rs b/tests/ui/eii/duplicate/auxiliary/impl4.rs new file mode 100644 index 000000000000..5275da1b1433 --- /dev/null +++ b/tests/ui/eii/duplicate/auxiliary/impl4.rs @@ -0,0 +1,12 @@ +//@ no-prefer-dynamic +//@ aux-build: decl.rs +#![crate_type = "rlib"] +#![feature(eii)] + +extern crate decl; + + +#[unsafe(decl::eii1)] +fn other(x: u64) { + println!("4{x}"); +} diff --git a/tests/ui/eii/duplicate/duplicate1.rs b/tests/ui/eii/duplicate/duplicate1.rs new file mode 100644 index 000000000000..921270fe3d48 --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate1.rs @@ -0,0 +1,13 @@ +//@ no-prefer-dynamic +//@ aux-build: impl1.rs +//@ aux-build: impl2.rs +// tests that EIIs error properly, even if the conflicting implementations live in another crate. +#![feature(eii)] + +// has a span but in the other crate +//~? ERROR multiple implementations of `#[eii1]` + +extern crate impl1; +extern crate impl2; + +fn main() {} diff --git a/tests/ui/eii/duplicate/duplicate1.stderr b/tests/ui/eii/duplicate/duplicate1.stderr new file mode 100644 index 000000000000..54cc141f8869 --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate1.stderr @@ -0,0 +1,15 @@ +error: multiple implementations of `#[eii1]` + --> $DIR/auxiliary/impl1.rs:10:1 + | +LL | fn other(x: u64) { + | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` + | + ::: $DIR/auxiliary/impl2.rs:10:1 + | +LL | fn other(x: u64) { + | ---------------- also implemented here in crate `impl2` + | + = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/duplicate/duplicate2.rs b/tests/ui/eii/duplicate/duplicate2.rs new file mode 100644 index 000000000000..8355b8f7bc70 --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate2.rs @@ -0,0 +1,15 @@ +//@ no-prefer-dynamic +//@ aux-build: impl1.rs +//@ aux-build: impl2.rs +//@ aux-build: impl3.rs +// Tests the error message when there are multiple implementations of an EII in many crates. +#![feature(eii)] + +// has a span but in the other crate +//~? ERROR multiple implementations of `#[eii1]` + +extern crate impl1; +extern crate impl2; +extern crate impl3; + +fn main() {} diff --git a/tests/ui/eii/duplicate/duplicate2.stderr b/tests/ui/eii/duplicate/duplicate2.stderr new file mode 100644 index 000000000000..033e43c8b2fb --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate2.stderr @@ -0,0 +1,16 @@ +error: multiple implementations of `#[eii1]` + --> $DIR/auxiliary/impl1.rs:10:1 + | +LL | fn other(x: u64) { + | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` + | + ::: $DIR/auxiliary/impl2.rs:10:1 + | +LL | fn other(x: u64) { + | ---------------- also implemented here in crate `impl2` + | + = note: in addition to these two, another implementation was found in crate `impl3` + = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/duplicate/duplicate3.rs b/tests/ui/eii/duplicate/duplicate3.rs new file mode 100644 index 000000000000..b967fb8b4903 --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate3.rs @@ -0,0 +1,17 @@ +//@ no-prefer-dynamic +//@ aux-build: impl1.rs +//@ aux-build: impl2.rs +//@ aux-build: impl3.rs +//@ aux-build: impl4.rs +// Tests the error message when there are multiple implementations of an EII in many crates. +#![feature(eii)] + +// has a span but in the other crate +//~? ERROR multiple implementations of `#[eii1]` + +extern crate impl1; +extern crate impl2; +extern crate impl3; +extern crate impl4; + +fn main() {} diff --git a/tests/ui/eii/duplicate/duplicate3.stderr b/tests/ui/eii/duplicate/duplicate3.stderr new file mode 100644 index 000000000000..801d40e69c55 --- /dev/null +++ b/tests/ui/eii/duplicate/duplicate3.stderr @@ -0,0 +1,16 @@ +error: multiple implementations of `#[eii1]` + --> $DIR/auxiliary/impl1.rs:10:1 + | +LL | fn other(x: u64) { + | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` + | + ::: $DIR/auxiliary/impl2.rs:10:1 + | +LL | fn other(x: u64) { + | ---------------- also implemented here in crate `impl2` + | + = note: in addition to these two, more implementations were also found in the following crates: `impl3`, `impl4` + = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/errors.rs b/tests/ui/eii/errors.rs new file mode 100644 index 000000000000..920ed1a529d5 --- /dev/null +++ b/tests/ui/eii/errors.rs @@ -0,0 +1,45 @@ +//@ compile-flags: --crate-type rlib +// Tests all the kinds of errors when EII attributes are used with wrong syntax. +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[eii_macro_for(bar)] //~ ERROR `#[eii_macro_for(...)]` is only valid on macros +fn hello() { + #[eii_macro_for(bar)] //~ ERROR `#[eii_macro_for(...)]` is only valid on macros + let x = 3 + 3; +} + +#[eii_macro_for] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[eii_macro_for()] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[eii_macro_for(bar, hello)] //~ ERROR expected this argument to be "unsafe" +#[eii_macro_for(bar, "unsafe", hello)] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[eii_macro_for(bar, hello, "unsafe")] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[eii_macro_for = "unsafe"] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements +#[eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() {} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[foo] //~ ERROR `#[foo]` is only valid on functions +static X: u64 = 4; +#[foo] //~ ERROR `#[foo]` is only valid on functions +const Y: u64 = 4; +#[foo] //~ ERROR `#[foo]` is only valid on functions +macro bar() {} + +#[foo()] +//~^ ERROR `#[foo]` expected no arguments or a single argument: `#[foo(default)]` +#[foo(default, bar)] +//~^ ERROR `#[foo]` expected no arguments or a single argument: `#[foo(default)]` +#[foo("default")] +//~^ ERROR `#[foo]` expected no arguments or a single argument: `#[foo(default)]` +#[foo = "default"] +//~^ ERROR `#[foo]` expected no arguments or a single argument: `#[foo(default)]` +fn other(x: u64) -> u64 { + x +} diff --git a/tests/ui/eii/errors.stderr b/tests/ui/eii/errors.stderr new file mode 100644 index 000000000000..d02c862ce8fa --- /dev/null +++ b/tests/ui/eii/errors.stderr @@ -0,0 +1,98 @@ +error: `#[eii_extern_target(...)]` is only valid on macros + --> $DIR/errors.rs:8:1 + | +LL | #[eii_macro_for(bar)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: `#[eii_extern_target(...)]` is only valid on macros + --> $DIR/errors.rs:10:5 + | +LL | #[eii_macro_for(bar)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: `#[eii_macro_for(...)]` expects a list of one or two elements + --> $DIR/errors.rs:14:1 + | +LL | #[eii_macro_for] + | ^^^^^^^^^^^^^^^^ + +error: `#[eii_extern_target(...)]` expects a list of one or two elements + --> $DIR/errors.rs:15:1 + | +LL | #[eii_macro_for()] + | ^^^^^^^^^^^^^^^^^^ + +error: expected this argument to be "unsafe" + --> $DIR/errors.rs:15:22 + | +LL | #[eii_macro_for(bar, hello)] + | ^^^^^ + | +note: the second argument is optional + --> $DIR/errors.rs:15:22 + | +LL | #[eii_macro_for(bar, hello)] + | ^^^^^ + +error: `#[eii_macro_for(...)]` expects a list of one or two elements + --> $DIR/errors.rs:17:1 + | +LL | #[eii_macro_for(bar, "unsafe", hello)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[eii_macro_for(...)]` expects a list of one or two elements + --> $DIR/errors.rs:18:1 + | +LL | #[eii_macro_for(bar, hello, "unsafe")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[eii_extern_target(...)]` expects a list of one or two elements + --> $DIR/errors.rs:19:1 + | +LL | #[eii_macro_for = "unsafe"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/errors.rs:28:1 + | +LL | #[foo] + | ^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/errors.rs:30:1 + | +LL | #[foo] + | ^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/errors.rs:32:1 + | +LL | #[foo] + | ^^^^^^ + +error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]` + --> $DIR/errors.rs:35:1 + | +LL | #[foo()] + | ^^^^^^^^ + +error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]` + --> $DIR/errors.rs:37:1 + | +LL | #[foo(default, bar)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]` + --> $DIR/errors.rs:39:1 + | +LL | #[foo("default")] + | ^^^^^^^^^^^^^^^^^ + +error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]` + --> $DIR/errors.rs:41:1 + | +LL | #[foo = "default"] + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 15 previous errors + diff --git a/tests/ui/eii/privacy1.rs b/tests/ui/eii/privacy1.rs new file mode 100644 index 000000000000..7dd87a5b7ce4 --- /dev/null +++ b/tests/ui/eii/privacy1.rs @@ -0,0 +1,31 @@ +//@ run-pass +//@ check-run-results +//@ aux-build: codegen1.rs +// Tests whether re-exports work. +#![feature(eii)] + +extern crate codegen1 as codegen; + +#[codegen::eii1] +fn eii1_impl(x: u64) { + println!("{x:?}") +} + + +#[codegen::eii3] +fn eii3_impl(x: u64) { + println!("{x:?}") +} + +// what you would write: +fn main() { + // directly + eii1_impl(21); + // through the alias + codegen::local_call_decl1(42); + + // directly + eii3_impl(12); + // through the alias + codegen::decl3(24); +} diff --git a/tests/ui/eii/privacy1.run.stdout b/tests/ui/eii/privacy1.run.stdout new file mode 100644 index 000000000000..c76239918563 --- /dev/null +++ b/tests/ui/eii/privacy1.run.stdout @@ -0,0 +1,4 @@ +21 +42 +12 +24 diff --git a/tests/ui/eii/privacy2.rs b/tests/ui/eii/privacy2.rs new file mode 100644 index 000000000000..702773fb5c78 --- /dev/null +++ b/tests/ui/eii/privacy2.rs @@ -0,0 +1,27 @@ +//@ aux-build:codegen3.rs +// Tests whether name resulution respects privacy properly. +#![feature(eii)] + +extern crate codegen3 as codegen; + +// has a span but in the other crate +//~? ERROR `#[eii2]` required, but not found +//~? ERROR `#[eii3]` required, but not found + +#[codegen::eii1] +fn eii1_impl(x: u64) { + println!("{x:?}") +} + +#[codegen::eii3] //~ ERROR failed to resolve: could not find `eii3` in `codegen` +fn eii3_impl(x: u64) { + println!("{x:?}") +} + +// what you would write: +fn main() { + // directly + eii1_impl(21); + // through the alias + codegen::decl1(42); //~ ERROR function `decl1` is private +} diff --git a/tests/ui/eii/privacy2.stderr b/tests/ui/eii/privacy2.stderr new file mode 100644 index 000000000000..0d44604567e4 --- /dev/null +++ b/tests/ui/eii/privacy2.stderr @@ -0,0 +1,38 @@ +error[E0433]: failed to resolve: could not find `eii3` in `codegen` + --> $DIR/privacy2.rs:16:12 + | +LL | #[codegen::eii3] + | ^^^^ could not find `eii3` in `codegen` + +error[E0603]: function `decl1` is private + --> $DIR/privacy2.rs:26:14 + | +LL | codegen::decl1(42); + | ^^^^^ private function + | +note: the function `decl1` is defined here + --> $DIR/auxiliary/codegen3.rs:7:1 + | +LL | fn decl1(x: u64); + | ^^^^^^^^^^^^^^^^^ + +error: `#[eii2]` required, but not found + --> $DIR/auxiliary/codegen3.rs:9:1 + | +LL | #[eii(eii2)] + | ^^^^^^^^^^^^ expected because `#[eii2]` was declared here in crate `codegen3` + | + = help: expected at least one implementation in crate `privacy2` or any of its dependencies + +error: `#[eii3]` required, but not found + --> $DIR/auxiliary/codegen3.rs:13:5 + | +LL | #[eii(eii3)] + | ^^^^^^^^^^^^ expected because `#[eii3]` was declared here in crate `codegen3` + | + = help: expected at least one implementation in crate `privacy2` or any of its dependencies + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0433, E0603. +For more information about an error, try `rustc --explain E0433`. diff --git a/tests/ui/eii/subtype_1.rs b/tests/ui/eii/subtype_1.rs new file mode 100644 index 000000000000..d19d586d1868 --- /dev/null +++ b/tests/ui/eii/subtype_1.rs @@ -0,0 +1,27 @@ +//@ compile-flags: --crate-type rlib +// Uses manual desugaring of EII internals: +// Tests whether it's not ok when the lifetimes are different between the decl and impl. +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar<'a, 'b>(x: &'b u64) -> &'a u64; +} + +#[foo] +fn other<'a, 'b>(x: &'b u64) -> &'b u64 { +//~^ ERROR lifetime parameters or bounds of `other` do not match the declaration + &0 +} + +fn main() { + bar(&0); +} diff --git a/tests/ui/eii/subtype_1.stderr b/tests/ui/eii/subtype_1.stderr new file mode 100644 index 000000000000..6a4ef6e16f9d --- /dev/null +++ b/tests/ui/eii/subtype_1.stderr @@ -0,0 +1,13 @@ +error: lifetime parameters or bounds of `other` do not match the declaration + --> $DIR/subtype_1.rs:18:9 + | +LL | safe fn bar<'a, 'b>(x: &'b u64) -> &'a u64; + | -------- lifetimes in impl do not match this signature +... +LL | #[foo] + | ------ required because of this attribute +LL | fn other<'a, 'b>(x: &'b u64) -> &'b u64 { + | ^^^^^^^^ lifetimes do not match + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/subtype_2.rs b/tests/ui/eii/subtype_2.rs new file mode 100644 index 000000000000..d518143ef99b --- /dev/null +++ b/tests/ui/eii/subtype_2.rs @@ -0,0 +1,27 @@ +//@ compile-flags: --crate-type rlib +// Uses manual desugaring of EII internals: +// Tests whether it's not ok when the implementation is less general. +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar<'a>(x: &'static u64) -> &'a u64; +} + +#[foo] +fn other<'a>(x: &'a u64) -> &'static u64 { +//~^ ERROR lifetime parameters or bounds of `other` do not match the declaration + &0 +} + +fn main() { + bar(&0); +} diff --git a/tests/ui/eii/subtype_2.stderr b/tests/ui/eii/subtype_2.stderr new file mode 100644 index 000000000000..5c925ca380e0 --- /dev/null +++ b/tests/ui/eii/subtype_2.stderr @@ -0,0 +1,13 @@ +error: lifetime parameters or bounds of `other` do not match the declaration + --> $DIR/subtype_2.rs:18:9 + | +LL | safe fn bar<'a>(x: &'static u64) -> &'a u64; + | ---- lifetimes in impl do not match this signature +... +LL | #[foo] + | ------ required because of this attribute +LL | fn other<'a>(x: &'a u64) -> &'static u64 { + | ^^^^ lifetimes do not match + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/subtype_3.rs b/tests/ui/eii/subtype_3.rs new file mode 100644 index 000000000000..5d73e63781d0 --- /dev/null +++ b/tests/ui/eii/subtype_3.rs @@ -0,0 +1,27 @@ +//@ compile-flags: --crate-type rlib +//@ check-pass +// Uses manual desugaring of EII internals: +// Tests whether it's ok when the implementation is more general. +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar<'a>(x: &'a u64) -> &'a u64; +} + +#[foo] +fn other<'a>(x: &'a u64) -> &'static u64 { + &0 +} + +fn main() { + bar(&0); +} diff --git a/tests/ui/eii/subtype_4.rs b/tests/ui/eii/subtype_4.rs new file mode 100644 index 000000000000..7207a6d73b6a --- /dev/null +++ b/tests/ui/eii/subtype_4.rs @@ -0,0 +1,27 @@ +//@ compile-flags: --crate-type rlib +//@ check-pass +// Uses manual desugaring of EII internals: +// Tests whether it's ok when giving the right types. +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[foo] +fn other(x: u64) -> u64 { + x +} + +fn main() { + bar(0); +} diff --git a/tests/ui/eii/unsafe_impl_err.rs b/tests/ui/eii/unsafe_impl_err.rs new file mode 100644 index 000000000000..347bd67f838d --- /dev/null +++ b/tests/ui/eii/unsafe_impl_err.rs @@ -0,0 +1,25 @@ +//@ compile-flags: --crate-type rlib +// Tests whether it's an error to implement an unsafe EII safely. +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[eii_macro_for(bar, "unsafe")] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[foo] //~ ERROR `#[foo]` is unsafe to implement +fn other(x: u64) -> u64 { + x +} + +fn main() { + bar(0); +} diff --git a/tests/ui/eii/unsafe_impl_err.stderr b/tests/ui/eii/unsafe_impl_err.stderr new file mode 100644 index 000000000000..6badcbe17f16 --- /dev/null +++ b/tests/ui/eii/unsafe_impl_err.stderr @@ -0,0 +1,13 @@ +error: `#[foo]` is unsafe to implement + --> $DIR/unsafe_impl_err.rs:17:1 + | +LL | #[foo] + | ^^^^^^ + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(foo)] + | +++++++ + + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/unsafe_impl_ok.rs b/tests/ui/eii/unsafe_impl_ok.rs new file mode 100644 index 000000000000..4281ce2feea7 --- /dev/null +++ b/tests/ui/eii/unsafe_impl_ok.rs @@ -0,0 +1,27 @@ +//@ compile-flags: --crate-type rlib +//@ check-pass +// Uses manual desugaring of EII internals: +// Tests whether it's okay to implement an unsafe EII with an unsafe implementation. +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[eii_macro_for(bar, "unsafe")] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[unsafe(foo)] +fn other(x: u64) -> u64 { + x +} + +fn main() { + bar(0); +} diff --git a/tests/ui/eii/wrong_ret_ty.rs b/tests/ui/eii/wrong_ret_ty.rs new file mode 100644 index 000000000000..a9d4c475a70a --- /dev/null +++ b/tests/ui/eii/wrong_ret_ty.rs @@ -0,0 +1,26 @@ +//@ compile-flags: --crate-type rlib +// Uses manual desugaring of EII internals: tests whether the return type matches. +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[foo] +fn other(_x: u64) { +//~^ ERROR function `other` has a type that is incompatible with the declaration + +} + +fn main() { + bar(0); +} diff --git a/tests/ui/eii/wrong_ret_ty.stderr b/tests/ui/eii/wrong_ret_ty.stderr new file mode 100644 index 000000000000..2cdd69bbdbdf --- /dev/null +++ b/tests/ui/eii/wrong_ret_ty.stderr @@ -0,0 +1,26 @@ +error[E0053]: function `other` has a type that is incompatible with the declaration of `#[foo]` + --> $DIR/wrong_ret_ty.rs:18:18 + | +LL | fn other(_x: u64) { + | ^ expected `u64`, found `()` + | +note: expected this because of this attribute + --> $DIR/wrong_ret_ty.rs:17:1 + | +LL | #[foo] + | ^^^^^^ +note: type in declaration + --> $DIR/wrong_ret_ty.rs:14:28 + | +LL | safe fn bar(x: u64) -> u64; + | ^^^ + = note: expected signature `fn(_) -> u64` + found signature `fn(_) -> ()` +help: change the output type to match the declaration + | +LL | fn other(_x: u64) -> u64 { + | ++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/eii/wrong_target.rs b/tests/ui/eii/wrong_target.rs new file mode 100644 index 000000000000..2a7fc4420943 --- /dev/null +++ b/tests/ui/eii/wrong_target.rs @@ -0,0 +1,63 @@ +#![feature(eii)] +// Check whether the EII attributes do target checking properly. + +#[eii] +fn foo() {} + +#[foo] +//~^ ERROR `#[foo]` is only valid on functions +#[eii] +//~^ ERROR `#[eii]` is only valid on functions +const A: usize = 3; + +#[foo] +//~^ ERROR `#[foo]` is only valid on functions +#[eii] +//~^ ERROR `#[eii]` is only valid on functions +macro_rules! foo_impl { + () => {}; +} + +#[foo] +//~^ ERROR `#[foo]` is only valid on functions +#[eii] +//~^ ERROR `#[eii]` is only valid on functions +struct Foo; + +#[foo] +//~^ ERROR `#[foo]` is only valid on functions +#[eii] +//~^ ERROR `#[eii]` is only valid on functions +impl Foo { + #[foo] + //~^ ERROR `#[foo]` is only valid on functions + #[eii] + //~^ ERROR `#[eii]` is only valid on functions + fn foo_impl() {} +} + +#[foo] +//~^ ERROR `#[foo]` is only valid on functions +#[eii] +//~^ ERROR `#[eii]` is only valid on functions +trait Bar { + #[foo] + //~^ ERROR `#[foo]` is only valid on functions + #[eii] + //~^ ERROR `#[eii]` is only valid on functions + fn foo_impl(); +} + +#[foo] +//~^ ERROR `#[foo]` is only valid on functions +#[eii] +//~^ ERROR `#[eii]` is only valid on functions +impl Bar for Foo { + #[foo] + //~^ ERROR `#[foo]` is only valid on functions + #[eii] + //~^ ERROR `#[eii]` is only valid on functions + fn foo_impl() {} +} + +fn main() {} diff --git a/tests/ui/eii/wrong_target.stderr b/tests/ui/eii/wrong_target.stderr new file mode 100644 index 000000000000..9b27f49fb302 --- /dev/null +++ b/tests/ui/eii/wrong_target.stderr @@ -0,0 +1,110 @@ +error: `#[foo]` is only valid on functions + --> $DIR/wrong_target.rs:7:1 + | +LL | #[foo] + | ^^^^^^ + +error: `#[eii]` is only valid on functions + --> $DIR/wrong_target.rs:9:1 + | +LL | #[eii] + | ^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/wrong_target.rs:13:1 + | +LL | #[foo] + | ^^^^^^ + +error: `#[eii]` is only valid on functions + --> $DIR/wrong_target.rs:15:1 + | +LL | #[eii] + | ^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/wrong_target.rs:21:1 + | +LL | #[foo] + | ^^^^^^ + +error: `#[eii]` is only valid on functions + --> $DIR/wrong_target.rs:23:1 + | +LL | #[eii] + | ^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/wrong_target.rs:27:1 + | +LL | #[foo] + | ^^^^^^ + +error: `#[eii]` is only valid on functions + --> $DIR/wrong_target.rs:29:1 + | +LL | #[eii] + | ^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/wrong_target.rs:32:5 + | +LL | #[foo] + | ^^^^^^ + +error: `#[eii]` is only valid on functions + --> $DIR/wrong_target.rs:34:5 + | +LL | #[eii] + | ^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/wrong_target.rs:39:1 + | +LL | #[foo] + | ^^^^^^ + +error: `#[eii]` is only valid on functions + --> $DIR/wrong_target.rs:41:1 + | +LL | #[eii] + | ^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/wrong_target.rs:44:5 + | +LL | #[foo] + | ^^^^^^ + +error: `#[eii]` is only valid on functions + --> $DIR/wrong_target.rs:46:5 + | +LL | #[eii] + | ^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/wrong_target.rs:51:1 + | +LL | #[foo] + | ^^^^^^ + +error: `#[eii]` is only valid on functions + --> $DIR/wrong_target.rs:53:1 + | +LL | #[eii] + | ^^^^^^ + +error: `#[foo]` is only valid on functions + --> $DIR/wrong_target.rs:56:5 + | +LL | #[foo] + | ^^^^^^ + +error: `#[eii]` is only valid on functions + --> $DIR/wrong_target.rs:58:5 + | +LL | #[eii] + | ^^^^^^ + +error: aborting due to 18 previous errors + diff --git a/tests/ui/eii/wrong_ty.rs b/tests/ui/eii/wrong_ty.rs new file mode 100644 index 000000000000..45f95c4380d6 --- /dev/null +++ b/tests/ui/eii/wrong_ty.rs @@ -0,0 +1,26 @@ +//@ compile-flags: --crate-type rlib +// Uses manual desugaring of EII internals: tests whether the types of parameters match. +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[foo] +fn other(x: usize) -> u64 { +//~^ ERROR function `other` has a type that is incompatible with the declaration + 3 +} + +fn main() { + bar(0); +} diff --git a/tests/ui/eii/wrong_ty.stderr b/tests/ui/eii/wrong_ty.stderr new file mode 100644 index 000000000000..fae713a35aa9 --- /dev/null +++ b/tests/ui/eii/wrong_ty.stderr @@ -0,0 +1,27 @@ +error[E0053]: function `other` has a type that is incompatible with the declaration of `#[foo]` + --> $DIR/wrong_ty.rs:18:13 + | +LL | fn other(x: usize) -> u64 { + | ^^^^^ expected `u64`, found `usize` + | +note: expected this because of this attribute + --> $DIR/wrong_ty.rs:17:1 + | +LL | #[foo] + | ^^^^^^ +note: type in declaration + --> $DIR/wrong_ty.rs:14:20 + | +LL | safe fn bar(x: u64) -> u64; + | ^^^ + = note: expected signature `fn(u64) -> _` + found signature `fn(usize) -> _` +help: change the parameter type to match the declaration + | +LL - fn other(x: usize) -> u64 { +LL + fn other(x: u64) -> u64 { + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/eii/wrong_ty_2.rs b/tests/ui/eii/wrong_ty_2.rs new file mode 100644 index 000000000000..a3d6d7e72774 --- /dev/null +++ b/tests/ui/eii/wrong_ty_2.rs @@ -0,0 +1,26 @@ +//@ compile-flags: --crate-type rlib +// Uses manual desugaring of EII internals: tests whether the number of parameters matches. +#![feature(eii)] +#![feature(decl_macro)] +#![feature(rustc_attrs)] +#![feature(eii_internals)] + +#[eii_macro_for(bar)] +#[rustc_builtin_macro(eii_macro)] +macro foo() { + +} + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} + +#[foo] +fn other() -> u64 { +//~^ ERROR `other` has 0 parameters but #[foo] requires it to have + 3 +} + +fn main() { + bar(0); +} diff --git a/tests/ui/eii/wrong_ty_2.stderr b/tests/ui/eii/wrong_ty_2.stderr new file mode 100644 index 000000000000..2ed00f9e55ee --- /dev/null +++ b/tests/ui/eii/wrong_ty_2.stderr @@ -0,0 +1,14 @@ +error[E0050]: `other` has 0 parameters but #[foo] requires it to have 1 + --> $DIR/wrong_ty_2.rs:18:1 + | +LL | safe fn bar(x: u64) -> u64; + | --- requires 1 parameter +... +LL | #[foo] + | ------ required because of this attribute +LL | fn other() -> u64 { + | ^^^^^^^^^^^^^^^^^ expected 1 parameter, found 0 + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0050`. From be9844363902f95a8868aa5b9a35aa7be3c64e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 25 Aug 2025 13:43:55 +0200 Subject: [PATCH 541/585] TEMP: fixes error codes in non-codegen tests. those work after the type checking --- .../auxiliary/cross_crate_eii_declaration.rs | 6 +-- tests/ui/eii/cross_crate_wrong_ty.stderr | 6 +-- tests/ui/eii/errors.rs | 14 +++---- tests/ui/eii/errors.stderr | 40 +++++++++---------- tests/ui/eii/unsafe_impl_err.stderr | 2 +- tests/ui/eii/wrong_ret_ty.stderr | 10 ++--- tests/ui/eii/wrong_ty.stderr | 10 ++--- tests/ui/eii/wrong_ty_2.stderr | 6 +-- 8 files changed, 46 insertions(+), 48 deletions(-) diff --git a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs index 36a42ad199b0..bda5c95f512d 100644 --- a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs +++ b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs @@ -5,11 +5,9 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_macro_for(bar)] +#[eii_extern_target(bar)] #[rustc_builtin_macro(eii_macro)] -pub macro foo() { - -} +pub macro foo() {} unsafe extern "Rust" { pub safe fn bar(x: u64) -> u64; diff --git a/tests/ui/eii/cross_crate_wrong_ty.stderr b/tests/ui/eii/cross_crate_wrong_ty.stderr index c85974f78206..b2190a075b63 100644 --- a/tests/ui/eii/cross_crate_wrong_ty.stderr +++ b/tests/ui/eii/cross_crate_wrong_ty.stderr @@ -1,4 +1,4 @@ -error[E0050]: `other` has 0 parameters but #[foo] requires it to have 1 +error[E0806]: `other` has 0 parameters but #[foo] requires it to have 1 --> $DIR/cross_crate_wrong_ty.rs:12:1 | LL | #[unsafe(cross_crate_eii_declaration::foo)] @@ -6,11 +6,11 @@ LL | #[unsafe(cross_crate_eii_declaration::foo)] LL | fn other() -> u64 { | ^^^^^^^^^^^^^^^^^ expected 1 parameter, found 0 | - ::: $DIR/auxiliary/cross_crate_eii_declaration.rs:15:5 + ::: $DIR/auxiliary/cross_crate_eii_declaration.rs:13:5 | LL | pub safe fn bar(x: u64) -> u64; | ------------------------------- requires 1 parameter error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0050`. +For more information about this error, try `rustc --explain E0806`. diff --git a/tests/ui/eii/errors.rs b/tests/ui/eii/errors.rs index 920ed1a529d5..587c4e02ce72 100644 --- a/tests/ui/eii/errors.rs +++ b/tests/ui/eii/errors.rs @@ -11,13 +11,13 @@ fn hello() { let x = 3 + 3; } -#[eii_macro_for] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements -#[eii_macro_for()] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements -#[eii_macro_for(bar, hello)] //~ ERROR expected this argument to be "unsafe" -#[eii_macro_for(bar, "unsafe", hello)] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements -#[eii_macro_for(bar, hello, "unsafe")] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements -#[eii_macro_for = "unsafe"] //~ ERROR `#[eii_macro_for(...)]` expects a list of one or two elements -#[eii_macro_for(bar)] +#[eii_extern_target] //~ ERROR `#[eii_extern_target(...)]` expects a list of one or two elements +#[eii_extern_target()] //~ ERROR `#[eii_extern_target(...)]` expects a list of one or two elements +#[eii_extern_target(bar, hello)] //~ ERROR expected this argument to be "unsafe" +#[eii_extern_target(bar, "unsafe", hello)] //~ ERROR `#[eii_extern_target(...)]` expects a list of one or two elements +#[eii_extern_target(bar, hello, "unsafe")] //~ ERROR `#[eii_extern_target(...)]` expects a list of one or two elements +#[eii_extern_target = "unsafe"] //~ ERROR `#[eii_extern_target(...)]` expects a list of one or two elements +#[eii_extern_target(bar)] #[rustc_builtin_macro(eii_macro)] macro foo() {} diff --git a/tests/ui/eii/errors.stderr b/tests/ui/eii/errors.stderr index d02c862ce8fa..c8bdce559722 100644 --- a/tests/ui/eii/errors.stderr +++ b/tests/ui/eii/errors.stderr @@ -1,56 +1,56 @@ error: `#[eii_extern_target(...)]` is only valid on macros --> $DIR/errors.rs:8:1 | -LL | #[eii_macro_for(bar)] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_extern_target(bar)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[eii_extern_target(...)]` is only valid on macros --> $DIR/errors.rs:10:5 | -LL | #[eii_macro_for(bar)] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_extern_target(bar)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[eii_macro_for(...)]` expects a list of one or two elements --> $DIR/errors.rs:14:1 | -LL | #[eii_macro_for] - | ^^^^^^^^^^^^^^^^ +LL | #[eii_extern_target] + | ^^^^^^^^^^^^^^^^^^^^ error: `#[eii_extern_target(...)]` expects a list of one or two elements --> $DIR/errors.rs:15:1 | -LL | #[eii_macro_for()] - | ^^^^^^^^^^^^^^^^^^ +LL | #[eii_extern_target()] + | ^^^^^^^^^^^^^^^^^^^^^^ error: expected this argument to be "unsafe" - --> $DIR/errors.rs:15:22 + --> $DIR/errors.rs:16:26 | -LL | #[eii_macro_for(bar, hello)] - | ^^^^^ +LL | #[eii_extern_target(bar, hello)] + | ^^^^^ | note: the second argument is optional - --> $DIR/errors.rs:15:22 + --> $DIR/errors.rs:16:26 | -LL | #[eii_macro_for(bar, hello)] - | ^^^^^ +LL | #[eii_extern_target(bar, hello)] + | ^^^^^ error: `#[eii_macro_for(...)]` expects a list of one or two elements --> $DIR/errors.rs:17:1 | -LL | #[eii_macro_for(bar, "unsafe", hello)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_extern_target(bar, "unsafe", hello)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[eii_macro_for(...)]` expects a list of one or two elements --> $DIR/errors.rs:18:1 | -LL | #[eii_macro_for(bar, hello, "unsafe")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_extern_target(bar, hello, "unsafe")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[eii_extern_target(...)]` expects a list of one or two elements --> $DIR/errors.rs:19:1 | -LL | #[eii_macro_for = "unsafe"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_extern_target = "unsafe"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[foo]` is only valid on functions --> $DIR/errors.rs:28:1 diff --git a/tests/ui/eii/unsafe_impl_err.stderr b/tests/ui/eii/unsafe_impl_err.stderr index 6badcbe17f16..eb917a65bb52 100644 --- a/tests/ui/eii/unsafe_impl_err.stderr +++ b/tests/ui/eii/unsafe_impl_err.stderr @@ -1,5 +1,5 @@ error: `#[foo]` is unsafe to implement - --> $DIR/unsafe_impl_err.rs:17:1 + --> $DIR/unsafe_impl_err.rs:16:1 | LL | #[foo] | ^^^^^^ diff --git a/tests/ui/eii/wrong_ret_ty.stderr b/tests/ui/eii/wrong_ret_ty.stderr index 2cdd69bbdbdf..0f7e9580aa37 100644 --- a/tests/ui/eii/wrong_ret_ty.stderr +++ b/tests/ui/eii/wrong_ret_ty.stderr @@ -1,16 +1,16 @@ -error[E0053]: function `other` has a type that is incompatible with the declaration of `#[foo]` - --> $DIR/wrong_ret_ty.rs:18:18 +error[E0806]: function `other` has a type that is incompatible with the declaration of `#[foo]` + --> $DIR/wrong_ret_ty.rs:17:18 | LL | fn other(_x: u64) { | ^ expected `u64`, found `()` | note: expected this because of this attribute - --> $DIR/wrong_ret_ty.rs:17:1 + --> $DIR/wrong_ret_ty.rs:16:1 | LL | #[foo] | ^^^^^^ note: type in declaration - --> $DIR/wrong_ret_ty.rs:14:28 + --> $DIR/wrong_ret_ty.rs:13:28 | LL | safe fn bar(x: u64) -> u64; | ^^^ @@ -23,4 +23,4 @@ LL | fn other(_x: u64) -> u64 { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0053`. +For more information about this error, try `rustc --explain E0806`. diff --git a/tests/ui/eii/wrong_ty.stderr b/tests/ui/eii/wrong_ty.stderr index fae713a35aa9..0513cec97fae 100644 --- a/tests/ui/eii/wrong_ty.stderr +++ b/tests/ui/eii/wrong_ty.stderr @@ -1,16 +1,16 @@ -error[E0053]: function `other` has a type that is incompatible with the declaration of `#[foo]` - --> $DIR/wrong_ty.rs:18:13 +error[E0806]: function `other` has a type that is incompatible with the declaration of `#[foo]` + --> $DIR/wrong_ty.rs:17:13 | LL | fn other(x: usize) -> u64 { | ^^^^^ expected `u64`, found `usize` | note: expected this because of this attribute - --> $DIR/wrong_ty.rs:17:1 + --> $DIR/wrong_ty.rs:16:1 | LL | #[foo] | ^^^^^^ note: type in declaration - --> $DIR/wrong_ty.rs:14:20 + --> $DIR/wrong_ty.rs:13:20 | LL | safe fn bar(x: u64) -> u64; | ^^^ @@ -24,4 +24,4 @@ LL + fn other(x: u64) -> u64 { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0053`. +For more information about this error, try `rustc --explain E0806`. diff --git a/tests/ui/eii/wrong_ty_2.stderr b/tests/ui/eii/wrong_ty_2.stderr index 2ed00f9e55ee..327d28e41370 100644 --- a/tests/ui/eii/wrong_ty_2.stderr +++ b/tests/ui/eii/wrong_ty_2.stderr @@ -1,5 +1,5 @@ -error[E0050]: `other` has 0 parameters but #[foo] requires it to have 1 - --> $DIR/wrong_ty_2.rs:18:1 +error[E0806]: `other` has 0 parameters but #[foo] requires it to have 1 + --> $DIR/wrong_ty_2.rs:17:1 | LL | safe fn bar(x: u64) -> u64; | --- requires 1 parameter @@ -11,4 +11,4 @@ LL | fn other() -> u64 { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0050`. +For more information about this error, try `rustc --explain E0806`. From 615acd8b4d7b854588ba5a4c4132bd39a78e0a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 27 Oct 2025 14:54:54 +0100 Subject: [PATCH 542/585] add tests for using a single impl for two EIIs --- tests/ui/eii/multiple_decls.rs | 17 +++++++++++++++++ tests/ui/eii/multiple_decls.stderr | 14 ++++++++++++++ tests/ui/eii/multiple_impls.rs | 23 +++++++++++++++++++++++ tests/ui/eii/multiple_impls.run.stdout | 2 ++ 4 files changed, 56 insertions(+) create mode 100644 tests/ui/eii/multiple_decls.rs create mode 100644 tests/ui/eii/multiple_decls.stderr create mode 100644 tests/ui/eii/multiple_impls.rs create mode 100644 tests/ui/eii/multiple_impls.run.stdout diff --git a/tests/ui/eii/multiple_decls.rs b/tests/ui/eii/multiple_decls.rs new file mode 100644 index 000000000000..63ef269d7818 --- /dev/null +++ b/tests/ui/eii/multiple_decls.rs @@ -0,0 +1,17 @@ +// Tests whether only one EII attribute cane be applied to a signature. +#![feature(eii)] + +#[eii(a)] +#[eii(b)] +//~^ ERROR `#[eii]` can only be specified once +fn a(x: u64); + +#[a] +fn implementation(x: u64) { + println!("{x:?}") +} + +// what you would write: +fn main() { + a(42); +} diff --git a/tests/ui/eii/multiple_decls.stderr b/tests/ui/eii/multiple_decls.stderr new file mode 100644 index 000000000000..e9e68ea74629 --- /dev/null +++ b/tests/ui/eii/multiple_decls.stderr @@ -0,0 +1,14 @@ +error: `#[eii]` can only be specified once + --> $DIR/multiple_decls.rs:5:1 + | +LL | #[eii(b)] + | ^^^^^^^^^ + | +note: specified again here + --> $DIR/multiple_decls.rs:4:1 + | +LL | #[eii(a)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/multiple_impls.rs b/tests/ui/eii/multiple_impls.rs new file mode 100644 index 000000000000..7f6691791410 --- /dev/null +++ b/tests/ui/eii/multiple_impls.rs @@ -0,0 +1,23 @@ +//@ run-pass +//@ check-run-results +//@ ignore-backends: gcc +// Tests whether one function could implement two EIIs. +#![feature(eii)] + +#[eii] +fn a(x: u64); + +#[eii] +fn b(x: u64); + +#[a] +#[b] +fn implementation(x: u64) { + println!("{x:?}") +} + +// what you would write: +fn main() { + a(42); + b(42); +} diff --git a/tests/ui/eii/multiple_impls.run.stdout b/tests/ui/eii/multiple_impls.run.stdout new file mode 100644 index 000000000000..daaac9e30302 --- /dev/null +++ b/tests/ui/eii/multiple_impls.run.stdout @@ -0,0 +1,2 @@ +42 +42 From 2de02ac86e02eaf0b5979ecbb0531db68910d0c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 28 Jul 2025 10:40:21 +0200 Subject: [PATCH 543/585] EII ast changes --- compiler/rustc_ast/src/ast.rs | 30 ++++++++++++++++++- compiler/rustc_ast/src/visit.rs | 9 ++++-- compiler/rustc_ast_lowering/src/item.rs | 8 +++-- .../rustc_ast_passes/src/ast_validation.rs | 5 ++++ compiler/rustc_ast_pretty/src/pprust/state.rs | 26 ++++++++++++++++ .../rustc_ast_pretty/src/pprust/state/item.rs | 19 ++++++++++-- .../src/alloc_error_handler.rs | 1 + compiler/rustc_builtin_macros/src/autodiff.rs | 1 + .../src/deriving/generic/mod.rs | 1 + .../src/global_allocator.rs | 1 + .../rustc_builtin_macros/src/test_harness.rs | 1 + compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 11 +++++-- .../clippy/clippy_utils/src/ast_utils/mod.rs | 6 ++++ 14 files changed, 110 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e348cc1ab281..ae0ecaccea22 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2109,6 +2109,19 @@ pub struct MacroDef { pub body: Box, /// `true` if macro was defined with `macro_rules`. pub macro_rules: bool, + + /// If this is a macro used for externally implementable items, + /// it refers to an extern item which is its "target". This requires + /// name resolution so can't just be an attribute, so we store it in this field. + pub eii_extern_target: Option, +} + +#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)] +pub struct EiiExternTarget { + /// path to the extern item we're targetting + pub extern_item_path: Path, + pub impl_unsafe: bool, + pub span: Span, } #[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)] @@ -3748,6 +3761,21 @@ pub struct Fn { pub contract: Option>, pub define_opaque: Option>, pub body: Option>, + + /// This function is an implementation of an externally implementable item (EII). + /// This means, there was an EII declared somewhere and this function is the + /// implementation that should be run when the declaration is called. + pub eii_impls: ThinVec, +} + +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub struct EiiImpl { + pub node_id: NodeId, + pub eii_macro_path: Path, + pub impl_safety: Safety, + pub span: Span, + pub inner_span: Span, + pub is_default: bool, } #[derive(Clone, Encodable, Decodable, Debug, Walkable)] @@ -4114,7 +4142,7 @@ mod size_asserts { static_assert_size!(Block, 32); static_assert_size!(Expr, 72); static_assert_size!(ExprKind, 40); - static_assert_size!(Fn, 184); + static_assert_size!(Fn, 192); static_assert_size!(ForeignItem, 80); static_assert_size!(ForeignItemKind, 16); static_assert_size!(GenericArg, 24); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 7a0424d39575..c7156da84dec 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -393,6 +393,7 @@ pub fn ctxt(&self) -> Option { ThinVec, ThinVec>, ThinVec, + ThinVec, ); // This macro generates `impl Visitable` and `impl MutVisitable` that forward to `Walkable` @@ -485,6 +486,8 @@ pub fn ctxt(&self) -> Option { WhereEqPredicate, WhereRegionPredicate, YieldKind, + EiiExternTarget, + EiiImpl, ); /// Each method of this trait is a hook to be potentially @@ -919,13 +922,13 @@ pub fn walk_fn<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, kind: FnKind<$($lt)? _ctxt, // Visibility is visited as a part of the item. _vis, - Fn { defaultness, ident, sig, generics, contract, body, define_opaque }, + Fn { defaultness, ident, sig, generics, contract, body, define_opaque, eii_impls }, ) => { let FnSig { header, decl, span } = sig; visit_visitable!($($mut)? vis, defaultness, ident, header, generics, decl, - contract, body, span, define_opaque - ) + contract, body, span, define_opaque, eii_impls + ); } FnKind::Closure(binder, coroutine_kind, decl, body) => visit_visitable!($($mut)? vis, binder, coroutine_kind, decl, body), diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f5b7065247a0..1db6a31e305d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -435,7 +435,7 @@ fn lower_item_kind( ); hir::ItemKind::TraitAlias(constness, ident, generics, bounds) } - ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => { + ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_extern_target: _ }) => { let ident = self.lower_ident(*ident); let body = Box::new(self.lower_delim_args(body)); let def_id = self.local_def_id(id); @@ -446,7 +446,11 @@ fn lower_item_kind( def_kind.descr(def_id.to_def_id()) ); }; - let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules }); + let macro_def = self.arena.alloc(ast::MacroDef { + body, + macro_rules: *macro_rules, + eii_extern_target: None, + }); hir::ItemKind::Macro(ident, macro_def, macro_kinds) } ItemKind::Delegation(box delegation) => { diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ddb19f5e7915..0d34ba6c2ca8 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1179,11 +1179,16 @@ fn visit_item(&mut self, item: &'a Item) { contract: _, body, define_opaque: _, + eii_impls, }, ) => { self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); self.check_defaultness(item.span, *defaultness); + for EiiImpl { eii_macro_path, .. } in eii_impls { + self.visit_path(eii_macro_path); + } + let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)); if body.is_none() && !is_intrinsic && !self.is_sdylib_interface { self.dcx().emit_err(errors::FnWithoutBody { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 35e47fed9f7a..1aa08dfd3d5e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -865,6 +865,17 @@ fn print_mac_def( sp: Span, print_visibility: impl FnOnce(&mut Self), ) { + if let Some(eii_extern_target) = ¯o_def.eii_extern_target { + self.word("#[eii_extern_target("); + self.print_path(&eii_extern_target.extern_item_path, false, 0); + if eii_extern_target.impl_unsafe { + self.word(","); + self.space(); + self.word("unsafe"); + } + self.word(")]"); + self.hardbreak(); + } let (kw, has_bang) = if macro_def.macro_rules { ("macro_rules", true) } else { @@ -2162,6 +2173,15 @@ fn print_meta_list_item(&mut self, item: &ast::MetaItemInner) { fn print_meta_item(&mut self, item: &ast::MetaItem) { let ib = self.ibox(INDENT_UNIT); + + match item.unsafety { + ast::Safety::Unsafe(_) => { + self.word("unsafe"); + self.popen(); + } + ast::Safety::Default | ast::Safety::Safe(_) => {} + } + match &item.kind { ast::MetaItemKind::Word => self.print_path(&item.path, false, 0), ast::MetaItemKind::NameValue(value) => { @@ -2177,6 +2197,12 @@ fn print_meta_item(&mut self, item: &ast::MetaItem) { self.pclose(); } } + + match item.unsafety { + ast::Safety::Unsafe(_) => self.pclose(), + ast::Safety::Default | ast::Safety::Safe(_) => {} + } + self.end(ib); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index c7cbf34dedb9..3233d8c2c251 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -1,6 +1,6 @@ use ast::StaticItem; use itertools::{Itertools, Position}; -use rustc_ast::{self as ast, ModKind, TraitAlias}; +use rustc_ast::{self as ast, EiiImpl, ModKind, Safety, TraitAlias}; use rustc_span::Ident; use crate::pp::BoxMarker; @@ -671,10 +671,25 @@ fn print_delegation( } fn print_fn_full(&mut self, vis: &ast::Visibility, attrs: &[ast::Attribute], func: &ast::Fn) { - let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque } = func; + let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque, eii_impls } = + func; self.print_define_opaques(define_opaque.as_deref()); + for EiiImpl { eii_macro_path, impl_safety, .. } in eii_impls { + self.word("#["); + if let Safety::Unsafe(..) = impl_safety { + self.word("unsafe"); + self.popen(); + } + self.print_path(eii_macro_path, false, 0); + if let Safety::Unsafe(..) = impl_safety { + self.pclose(); + } + self.word("]"); + self.hardbreak(); + } + let body_cb_ib = body.as_ref().map(|body| (body, self.head(""))); self.print_visibility(vis); diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index e5d9d2080c08..12ccc4a6de04 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -90,6 +90,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span contract: None, body, define_opaque: None, + eii_impls: ThinVec::new(), })); let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)]; diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index ddc59bfe1414..7839a75636b6 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -346,6 +346,7 @@ pub(crate) fn expand_with_mode( contract: None, body: Some(d_body), define_opaque: None, + eii_impls: ThinVec::new(), }); let mut rustc_ad_attr = Box::new(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_autodiff))); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index baffc525d95a..bb6557802ece 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1092,6 +1092,7 @@ fn create_method( contract: None, body: Some(body_block), define_opaque: None, + eii_impls: ThinVec::new(), })), tokens: None, }) diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index e69f0838f22e..bb031dafdcfd 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -84,6 +84,7 @@ fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt { contract: None, body, define_opaque: None, + eii_impls: ThinVec::new(), })); let item = self.cx.item(self.span, self.attrs(method), kind); self.cx.stmt_item(self.ty_span, item) diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 2a6ac5754bfa..8d6969b0ca12 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -345,6 +345,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box { contract: None, body: Some(main_body), define_opaque: None, + eii_impls: ThinVec::new(), })); let main = Box::new(ast::Item { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 65cbdc675962..76438f046dd5 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1530,7 +1530,7 @@ fn get_macro(self, tcx: TyCtxt<'_>, id: DefIndex) -> ast::MacroDef { .get((self, tcx), id) .unwrap() .decode((self, tcx)); - ast::MacroDef { macro_rules, body: Box::new(body) } + ast::MacroDef { macro_rules, body: Box::new(body), eii_extern_target: None } } _ => bug!(), } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index abc0ffa87d3d..f9b95ba192d4 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -227,6 +227,7 @@ fn parse_item_kind( contract, body, define_opaque: None, + eii_impls: ThinVec::new(), })) } else if self.eat_keyword_case(exp!(Extern), case) { if self.eat_keyword_case(exp!(Crate), case) { @@ -2200,7 +2201,10 @@ fn parse_item_decl_macro(&mut self, lo: Span) -> PResult<'a, ItemKind> { }; self.psess.gated_spans.gate(sym::decl_macro, lo.to(self.prev_token.span)); - Ok(ItemKind::MacroDef(ident, ast::MacroDef { body, macro_rules: false })) + Ok(ItemKind::MacroDef( + ident, + ast::MacroDef { body, macro_rules: false, eii_extern_target: None }, + )) } /// Is this a possibly malformed start of a `macro_rules! foo` item definition? @@ -2247,7 +2251,10 @@ fn parse_item_macro_rules( self.eat_semi_for_macro_if_needed(&body); self.complain_if_pub_macro(vis, true); - Ok(ItemKind::MacroDef(ident, ast::MacroDef { body, macro_rules: true })) + Ok(ItemKind::MacroDef( + ident, + ast::MacroDef { body, macro_rules: true, eii_extern_target: None }, + )) } /// Item macro invocations or `macro_rules!` definitions need inherited visibility. diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 08663782a1d5..432d7a251a21 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -382,6 +382,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { contract: lc, body: lb, define_opaque: _, + eii_impls: _, }), Fn(box ast::Fn { defaultness: rd, @@ -391,6 +392,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { contract: rc, body: rb, define_opaque: _, + eii_impls: _, }), ) => { eq_defaultness(*ld, *rd) @@ -554,6 +556,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { contract: lc, body: lb, define_opaque: _, + eii_impls: _, }), Fn(box ast::Fn { defaultness: rd, @@ -563,6 +566,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { contract: rc, body: rb, define_opaque: _, + eii_impls: _, }), ) => { eq_defaultness(*ld, *rd) @@ -638,6 +642,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { contract: lc, body: lb, define_opaque: _, + eii_impls: _, }), Fn(box ast::Fn { defaultness: rd, @@ -647,6 +652,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { contract: rc, body: rb, define_opaque: _, + eii_impls: _, }), ) => { eq_defaultness(*ld, *rd) From 92c03a26fd68a87f72f0b89b387ca0548ab7f1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 28 Jul 2025 12:46:03 +0200 Subject: [PATCH 544/585] EII (builtin) macros in std --- compiler/rustc_builtin_macros/messages.ftl | 11 + compiler/rustc_builtin_macros/src/eii.rs | 429 ++++++++++++++++++ compiler/rustc_builtin_macros/src/errors.rs | 48 ++ compiler/rustc_builtin_macros/src/lib.rs | 5 + compiler/rustc_span/src/symbol.rs | 6 + library/core/src/macros/mod.rs | 25 + library/core/src/prelude/v1.rs | 13 + library/std/src/prelude/v1.rs | 6 + .../auxiliary/cross_crate_eii_declaration.rs | 2 +- tests/ui/eii/errors.rs | 6 +- tests/ui/eii/errors.stderr | 6 +- tests/ui/eii/subtype_1.rs | 10 +- tests/ui/eii/subtype_2.rs | 10 +- tests/ui/eii/subtype_3.rs | 8 +- tests/ui/eii/subtype_4.rs | 8 +- tests/ui/eii/unsafe_impl_err.rs | 8 +- tests/ui/eii/unsafe_impl_ok.rs | 8 +- tests/ui/eii/wrong_ret_ty.rs | 11 +- tests/ui/eii/wrong_ty.rs | 10 +- tests/ui/eii/wrong_ty_2.rs | 10 +- 20 files changed, 582 insertions(+), 58 deletions(-) create mode 100644 compiler/rustc_builtin_macros/src/eii.rs diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 86671d0326da..542f34d9d831 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -152,6 +152,17 @@ builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept builtin_macros_duplicate_macro_attribute = duplicated attribute +builtin_macros_eii_extern_target_expected_list = `#[eii_extern_target(...)]` expects a list of one or two elements +builtin_macros_eii_extern_target_expected_macro = `#[eii_extern_target(...)]` is only valid on macros +builtin_macros_eii_extern_target_expected_unsafe = expected this argument to be "unsafe" + .note = the second argument is optional + +builtin_macros_eii_only_once = `#[{$name}]` can only be specified once + .note = specified again here + +builtin_macros_eii_shared_macro_expected_function = `#[{$name}]` is only valid on functions +builtin_macros_eii_shared_macro_expected_max_one_argument = `#[{$name}]` expected no arguments or a single argument: `#[{$name}(default)]` + builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead .cargo_typo = there is a similar Cargo environment variable: `{$suggested_var}` diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs new file mode 100644 index 000000000000..f1161c644ef5 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -0,0 +1,429 @@ +use rustc_ast::token::{Delimiter, TokenKind}; +use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; +use rustc_ast::{ + DUMMY_NODE_ID, EiiExternTarget, EiiImpl, ItemKind, Stmt, StmtKind, ast, token, tokenstream, +}; +use rustc_ast_pretty::pprust::path_to_string; +use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_span::{Ident, Span, kw, sym}; +use thin_vec::{ThinVec, thin_vec}; + +use crate::errors::{ + EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe, + EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroExpectedFunction, +}; + +/// ```rust +/// #[eii] +/// fn panic_handler(); +/// +/// // or: +/// +/// #[eii(panic_handler)] +/// fn panic_handler(); +/// +/// // expansion: +/// +/// extern "Rust" { +/// fn panic_handler(); +/// } +/// +/// #[rustc_builtin_macro(eii_shared_macro)] +/// #[eii_extern_target(panic_handler)] +/// macro panic_handler() {} +/// ``` +pub(crate) fn eii( + ecx: &mut ExtCtxt<'_>, + span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, +) -> Vec { + eii_(ecx, span, meta_item, item, false) +} + +pub(crate) fn unsafe_eii( + ecx: &mut ExtCtxt<'_>, + span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, +) -> Vec { + eii_(ecx, span, meta_item, item, true) +} + +fn eii_( + ecx: &mut ExtCtxt<'_>, + span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, + impl_unsafe: bool, +) -> Vec { + let span = ecx.with_def_site_ctxt(span); + + let (item, stmt) = if let Annotatable::Item(item) = item { + (item, false) + } else if let Annotatable::Stmt(ref stmt) = item + && let StmtKind::Item(ref item) = stmt.kind + { + (item.clone(), true) + } else { + ecx.dcx().emit_err(EiiSharedMacroExpectedFunction { + span, + name: path_to_string(&meta_item.path), + }); + return vec![item]; + }; + + let orig_item = item.clone(); + + let item = *item; + + let ast::Item { attrs, id: _, span: item_span, vis, kind: ItemKind::Fn(mut func), tokens: _ } = + item + else { + ecx.dcx().emit_err(EiiSharedMacroExpectedFunction { + span, + name: path_to_string(&meta_item.path), + }); + return vec![Annotatable::Item(Box::new(item))]; + }; + + // Detect when this is the *second* eii attribute on an item. + let mut new_attrs = ThinVec::new(); + for i in attrs { + if i.has_name(sym::eii) { + ecx.dcx().emit_err(EiiOnlyOnce { + span: i.span, + first_span: span, + name: path_to_string(&meta_item.path), + }); + } else { + new_attrs.push(i); + } + } + let attrs = new_attrs; + + let macro_name = if meta_item.is_word() { + func.ident + } else if let Some([first]) = meta_item.meta_item_list() + && let Some(m) = first.meta_item() + && m.path.segments.len() == 1 + { + m.path.segments[0].ident + } else { + ecx.dcx().emit_err(EiiMacroExpectedMaxOneArgument { + span: meta_item.span, + name: path_to_string(&meta_item.path), + }); + return vec![Annotatable::Item(orig_item)]; + }; + + let mut return_items = Vec::new(); + + if func.body.is_some() { + let mut default_func = func.clone(); + func.body = None; + default_func.eii_impls.push(ast::EiiImpl { + node_id: DUMMY_NODE_ID, + eii_macro_path: ast::Path::from_ident(macro_name), + impl_safety: if impl_unsafe { ast::Safety::Unsafe(span) } else { ast::Safety::Default }, + span, + inner_span: macro_name.span, + is_default: true, // important! + }); + + return_items.push(Box::new(ast::Item { + attrs: ThinVec::new(), + id: ast::DUMMY_NODE_ID, + span, + vis: ast::Visibility { span, kind: ast::VisibilityKind::Inherited, tokens: None }, + kind: ast::ItemKind::Const(Box::new(ast::ConstItem { + ident: Ident { name: kw::Underscore, span }, + defaultness: ast::Defaultness::Final, + generics: ast::Generics::default(), + ty: Box::new(ast::Ty { + id: DUMMY_NODE_ID, + kind: ast::TyKind::Tup(ThinVec::new()), + span, + tokens: None, + }), + rhs: Some(ast::ConstItemRhs::Body(Box::new(ast::Expr { + id: DUMMY_NODE_ID, + kind: ast::ExprKind::Block( + Box::new(ast::Block { + stmts: thin_vec![ast::Stmt { + id: DUMMY_NODE_ID, + kind: ast::StmtKind::Item(Box::new(ast::Item { + attrs: thin_vec![], // FIXME: re-add some original attrs + id: DUMMY_NODE_ID, + span: item_span, + vis: ast::Visibility { + span, + kind: ast::VisibilityKind::Inherited, + tokens: None + }, + kind: ItemKind::Fn(default_func), + tokens: None, + })), + span + }], + id: DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Default, + span, + tokens: None, + }), + None, + ), + span, + attrs: ThinVec::new(), + tokens: None, + }))), + define_opaque: None, + })), + tokens: None, + })) + } + + let decl_span = span.to(func.sig.span); + + let abi = match func.sig.header.ext { + // extern "X" fn => extern "X" {} + ast::Extern::Explicit(lit, _) => Some(lit), + // extern fn => extern {} + ast::Extern::Implicit(_) => None, + // fn => extern "Rust" {} + ast::Extern::None => Some(ast::StrLit { + symbol: sym::Rust, + suffix: None, + symbol_unescaped: sym::Rust, + style: ast::StrStyle::Cooked, + span, + }), + }; + + // ABI has been moved to the extern {} block, so we remove it from the fn item. + func.sig.header.ext = ast::Extern::None; + + // And mark safe functions explicitly as `safe fn`. + if func.sig.header.safety == ast::Safety::Default { + func.sig.header.safety = ast::Safety::Safe(func.sig.span); + } + + // extern "…" { safe fn item(); } + let extern_block = Box::new(ast::Item { + attrs: ast::AttrVec::default(), + id: ast::DUMMY_NODE_ID, + span, + vis: ast::Visibility { span, kind: ast::VisibilityKind::Inherited, tokens: None }, + kind: ast::ItemKind::ForeignMod(ast::ForeignMod { + extern_span: span, + safety: ast::Safety::Unsafe(span), + abi, + items: From::from([Box::new(ast::ForeignItem { + attrs: attrs.clone(), + id: ast::DUMMY_NODE_ID, + span: item_span, + vis, + kind: ast::ForeignItemKind::Fn(func.clone()), + tokens: None, + })]), + }), + tokens: None, + }); + + let mut macro_attrs = attrs.clone(); + macro_attrs.push( + // #[builtin_macro(eii_shared_macro)] + ast::Attribute { + kind: ast::AttrKind::Normal(Box::new(ast::NormalAttr { + item: ast::AttrItem { + unsafety: ast::Safety::Default, + path: ast::Path::from_ident(Ident::new(sym::rustc_builtin_macro, span)), + args: ast::AttrArgs::Delimited(ast::DelimArgs { + dspan: DelimSpan::from_single(span), + delim: Delimiter::Parenthesis, + tokens: TokenStream::new(vec![tokenstream::TokenTree::token_alone( + token::TokenKind::Ident(sym::eii_shared_macro, token::IdentIsRaw::No), + span, + )]), + }), + tokens: None, + }, + tokens: None, + })), + id: ecx.sess.psess.attr_id_generator.mk_attr_id(), + style: ast::AttrStyle::Outer, + span, + }, + ); + + let macro_def = Box::new(ast::Item { + attrs: macro_attrs, + id: ast::DUMMY_NODE_ID, + span, + // pub + vis: ast::Visibility { span, kind: ast::VisibilityKind::Public, tokens: None }, + kind: ast::ItemKind::MacroDef( + // macro macro_name + macro_name, + ast::MacroDef { + // { () => {} } + body: Box::new(ast::DelimArgs { + dspan: DelimSpan::from_single(span), + delim: Delimiter::Brace, + tokens: TokenStream::from_iter([ + TokenTree::Delimited( + DelimSpan::from_single(span), + DelimSpacing::new(Spacing::Alone, Spacing::Alone), + Delimiter::Parenthesis, + TokenStream::default(), + ), + TokenTree::token_alone(TokenKind::FatArrow, span), + TokenTree::Delimited( + DelimSpan::from_single(span), + DelimSpacing::new(Spacing::Alone, Spacing::Alone), + Delimiter::Brace, + TokenStream::default(), + ), + ]), + }), + macro_rules: false, + // #[eii_extern_target(func.ident)] + eii_extern_target: Some(ast::EiiExternTarget { + extern_item_path: ast::Path::from_ident(func.ident), + impl_unsafe, + span: decl_span, + }), + }, + ), + tokens: None, + }); + + return_items.push(extern_block); + return_items.push(macro_def); + + if stmt { + return_items + .into_iter() + .map(|i| { + Annotatable::Stmt(Box::new(Stmt { + id: DUMMY_NODE_ID, + kind: StmtKind::Item(i), + span, + })) + }) + .collect() + } else { + return_items.into_iter().map(|i| Annotatable::Item(i)).collect() + } +} + +pub(crate) fn eii_extern_target( + ecx: &mut ExtCtxt<'_>, + span: Span, + meta_item: &ast::MetaItem, + mut item: Annotatable, +) -> Vec { + let i = if let Annotatable::Item(ref mut item) = item { + item + } else if let Annotatable::Stmt(ref mut stmt) = item + && let StmtKind::Item(ref mut item) = stmt.kind + { + item + } else { + ecx.dcx().emit_err(EiiExternTargetExpectedMacro { span }); + return vec![item]; + }; + + let ItemKind::MacroDef(_, d) = &mut i.kind else { + ecx.dcx().emit_err(EiiExternTargetExpectedMacro { span }); + return vec![item]; + }; + + let Some(list) = meta_item.meta_item_list() else { + ecx.dcx().emit_err(EiiExternTargetExpectedList { span: meta_item.span }); + return vec![item]; + }; + + if list.len() > 2 { + ecx.dcx().emit_err(EiiExternTargetExpectedList { span: meta_item.span }); + return vec![item]; + } + + let Some(extern_item_path) = list.get(0).and_then(|i| i.meta_item()).map(|i| i.path.clone()) + else { + ecx.dcx().emit_err(EiiExternTargetExpectedList { span: meta_item.span }); + return vec![item]; + }; + + let impl_unsafe = if let Some(i) = list.get(1) { + if i.lit().and_then(|i| i.kind.str()).is_some_and(|i| i == kw::Unsafe) { + true + } else { + ecx.dcx().emit_err(EiiExternTargetExpectedUnsafe { span: i.span() }); + return vec![item]; + } + } else { + false + }; + + d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe, span }); + + // Return the original item and the new methods. + vec![item] +} + +/// all Eiis share this function as the implementation for their attribute. +pub(crate) fn eii_shared_macro( + ecx: &mut ExtCtxt<'_>, + span: Span, + meta_item: &ast::MetaItem, + mut item: Annotatable, +) -> Vec { + let i = if let Annotatable::Item(ref mut item) = item { + item + } else if let Annotatable::Stmt(ref mut stmt) = item + && let StmtKind::Item(ref mut item) = stmt.kind + { + item + } else { + ecx.dcx().emit_err(EiiSharedMacroExpectedFunction { + span, + name: path_to_string(&meta_item.path), + }); + return vec![item]; + }; + + let ItemKind::Fn(f) = &mut i.kind else { + ecx.dcx().emit_err(EiiSharedMacroExpectedFunction { + span, + name: path_to_string(&meta_item.path), + }); + return vec![item]; + }; + + let is_default = if meta_item.is_word() { + false + } else if let Some([first]) = meta_item.meta_item_list() + && let Some(m) = first.meta_item() + && m.path.segments.len() == 1 + { + m.path.segments[0].ident.name == kw::Default + } else { + ecx.dcx().emit_err(EiiMacroExpectedMaxOneArgument { + span: meta_item.span, + name: path_to_string(&meta_item.path), + }); + return vec![item]; + }; + + f.eii_impls.push(EiiImpl { + node_id: DUMMY_NODE_ID, + eii_macro_path: meta_item.path.clone(), + impl_safety: meta_item.unsafety, + span, + inner_span: meta_item.path.span, + is_default, + }); + + vec![item] +} diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index dd6a5a20cceb..2a4c499349ad 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1010,3 +1010,51 @@ pub(crate) struct CfgSelectUnreachable { #[label] pub wildcard_span: Span, } + +#[derive(Diagnostic)] +#[diag(builtin_macros_eii_extern_target_expected_macro)] +pub(crate) struct EiiExternTargetExpectedMacro { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_eii_extern_target_expected_list)] +pub(crate) struct EiiExternTargetExpectedList { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_eii_extern_target_expected_unsafe)] +pub(crate) struct EiiExternTargetExpectedUnsafe { + #[primary_span] + #[note] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_eii_shared_macro_expected_function)] +pub(crate) struct EiiSharedMacroExpectedFunction { + #[primary_span] + pub span: Span, + pub name: String, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_eii_only_once)] +pub(crate) struct EiiOnlyOnce { + #[primary_span] + pub span: Span, + #[note] + pub first_span: Span, + pub name: String, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_eii_shared_macro_expected_max_one_argument)] +pub(crate) struct EiiMacroExpectedMaxOneArgument { + #[primary_span] + pub span: Span, + pub name: String, +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 221e7c3d553a..89ac8db76063 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -38,6 +38,7 @@ mod derive; mod deriving; mod edition_panic; +mod eii; mod env; mod errors; mod format; @@ -117,9 +118,13 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { define_opaque: define_opaque::expand, derive: derive::Expander { is_const: false }, derive_const: derive::Expander { is_const: true }, + eii: eii::eii, + eii_extern_target: eii::eii_extern_target, + eii_shared_macro: eii::eii_shared_macro, global_allocator: global_allocator::expand, test: test::expand_test, test_case: test::expand_test_case, + unsafe_eii: eii::unsafe_eii, // tidy-alphabetical-end } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c9aaba6cce3b..984ecc772d81 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -929,6 +929,11 @@ effects, eh_catch_typeinfo, eh_personality, + eii, + eii_extern_target, + eii_impl, + eii_internals, + eii_shared_macro, emit, emit_enum, emit_enum_variant, @@ -2386,6 +2391,7 @@ unsafe_block_in_unsafe_fn, unsafe_cell, unsafe_cell_raw_get, + unsafe_eii, unsafe_extern_blocks, unsafe_fields, unsafe_no_drop_flag, diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index f3386985bdf1..68b5b2d1efc6 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1890,4 +1890,29 @@ macro_rules! trace_macros { pub macro From($item: item) { /* compiler built-in */ } + + /// Externally Implementable Item: Defines an attribute macro that can override the item + /// this is applied to. + #[unstable(feature = "eii", issue = "125418")] + #[rustc_builtin_macro] + #[allow_internal_unstable(eii_internals, decl_macro, rustc_attrs)] + pub macro eii($item:item) { + /* compiler built-in */ + } + + /// Unsafely Externally Implementable Item: Defines an unsafe attribute macro that can override + /// the item this is applied to. + #[unstable(feature = "eii", issue = "125418")] + #[rustc_builtin_macro] + #[allow_internal_unstable(eii_internals, decl_macro, rustc_attrs)] + pub macro unsafe_eii($item:item) { + /* compiler built-in */ + } + + /// Impl detail of EII + #[unstable(feature = "eii_internals", issue = "none")] + #[rustc_builtin_macro] + pub macro eii_extern_target($item:item) { + /* compiler built-in */ + } } diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index a4be66b90cab..3446f04a6429 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -117,3 +117,16 @@ reason = "`type_alias_impl_trait` has open design concerns" )] pub use crate::macros::builtin::define_opaque; + +#[unstable( + feature = "derive_from", + issue = "144889", + reason = "`derive(From)` is unstable" +)] +pub use crate::macros::builtin::From; + +#[unstable(feature = "eii", issue = "125418")] +pub use crate::macros::builtin::{eii, unsafe_eii}; + +#[unstable(feature = "eii_internals", issue = "none")] +pub use crate::macros::builtin::eii_extern_target; diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 70c111315565..6c2f5f108f1a 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -110,6 +110,12 @@ )] pub use core::prelude::v1::define_opaque; +#[unstable(feature = "eii", issue = "125418")] +pub use core::prelude::v1::{eii, unsafe_eii}; + +#[unstable(feature = "eii_internals", issue = "none")] +pub use core::prelude::v1::eii_extern_target; + // The file so far is equivalent to core/src/prelude/v1.rs. It is duplicated // rather than glob imported because we want docs to show these re-exports as // pointing to within `std`. diff --git a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs index bda5c95f512d..3147d91bbee8 100644 --- a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs +++ b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs @@ -6,7 +6,7 @@ #![feature(eii_internals)] #[eii_extern_target(bar)] -#[rustc_builtin_macro(eii_macro)] +#[rustc_builtin_macro(eii_shared_macro)] pub macro foo() {} unsafe extern "Rust" { diff --git a/tests/ui/eii/errors.rs b/tests/ui/eii/errors.rs index 587c4e02ce72..ec365b0e9d16 100644 --- a/tests/ui/eii/errors.rs +++ b/tests/ui/eii/errors.rs @@ -5,9 +5,9 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_macro_for(bar)] //~ ERROR `#[eii_macro_for(...)]` is only valid on macros +#[eii_extern_target(bar)] //~ ERROR `#[eii_extern_target(...)]` is only valid on macros fn hello() { - #[eii_macro_for(bar)] //~ ERROR `#[eii_macro_for(...)]` is only valid on macros + #[eii_extern_target(bar)] //~ ERROR `#[eii_extern_target(...)]` is only valid on macros let x = 3 + 3; } @@ -18,7 +18,7 @@ fn hello() { #[eii_extern_target(bar, hello, "unsafe")] //~ ERROR `#[eii_extern_target(...)]` expects a list of one or two elements #[eii_extern_target = "unsafe"] //~ ERROR `#[eii_extern_target(...)]` expects a list of one or two elements #[eii_extern_target(bar)] -#[rustc_builtin_macro(eii_macro)] +#[rustc_builtin_macro(eii_shared_macro)] macro foo() {} unsafe extern "Rust" { diff --git a/tests/ui/eii/errors.stderr b/tests/ui/eii/errors.stderr index c8bdce559722..c3b51421f295 100644 --- a/tests/ui/eii/errors.stderr +++ b/tests/ui/eii/errors.stderr @@ -10,7 +10,7 @@ error: `#[eii_extern_target(...)]` is only valid on macros LL | #[eii_extern_target(bar)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `#[eii_macro_for(...)]` expects a list of one or two elements +error: `#[eii_extern_target(...)]` expects a list of one or two elements --> $DIR/errors.rs:14:1 | LL | #[eii_extern_target] @@ -34,13 +34,13 @@ note: the second argument is optional LL | #[eii_extern_target(bar, hello)] | ^^^^^ -error: `#[eii_macro_for(...)]` expects a list of one or two elements +error: `#[eii_extern_target(...)]` expects a list of one or two elements --> $DIR/errors.rs:17:1 | LL | #[eii_extern_target(bar, "unsafe", hello)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `#[eii_macro_for(...)]` expects a list of one or two elements +error: `#[eii_extern_target(...)]` expects a list of one or two elements --> $DIR/errors.rs:18:1 | LL | #[eii_extern_target(bar, hello, "unsafe")] diff --git a/tests/ui/eii/subtype_1.rs b/tests/ui/eii/subtype_1.rs index d19d586d1868..8c58a5d7fac2 100644 --- a/tests/ui/eii/subtype_1.rs +++ b/tests/ui/eii/subtype_1.rs @@ -6,11 +6,9 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_macro_for(bar)] -#[rustc_builtin_macro(eii_macro)] -macro foo() { - -} +#[eii_extern_target(bar)] +#[rustc_builtin_macro(eii_shared_macro)] +macro foo() {} unsafe extern "Rust" { safe fn bar<'a, 'b>(x: &'b u64) -> &'a u64; @@ -18,7 +16,7 @@ #[foo] fn other<'a, 'b>(x: &'b u64) -> &'b u64 { -//~^ ERROR lifetime parameters or bounds of `other` do not match the declaration + //~^ ERROR lifetime parameters or bounds of `other` do not match the declaration &0 } diff --git a/tests/ui/eii/subtype_2.rs b/tests/ui/eii/subtype_2.rs index d518143ef99b..0453286a19c5 100644 --- a/tests/ui/eii/subtype_2.rs +++ b/tests/ui/eii/subtype_2.rs @@ -6,11 +6,9 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_macro_for(bar)] -#[rustc_builtin_macro(eii_macro)] -macro foo() { - -} +#[eii_extern_target(bar)] +#[rustc_builtin_macro(eii_shared_macro)] +macro foo() {} unsafe extern "Rust" { safe fn bar<'a>(x: &'static u64) -> &'a u64; @@ -18,7 +16,7 @@ #[foo] fn other<'a>(x: &'a u64) -> &'static u64 { -//~^ ERROR lifetime parameters or bounds of `other` do not match the declaration + //~^ ERROR lifetime parameters or bounds of `other` do not match the declaration &0 } diff --git a/tests/ui/eii/subtype_3.rs b/tests/ui/eii/subtype_3.rs index 5d73e63781d0..39d232e27c5b 100644 --- a/tests/ui/eii/subtype_3.rs +++ b/tests/ui/eii/subtype_3.rs @@ -7,11 +7,9 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_macro_for(bar)] -#[rustc_builtin_macro(eii_macro)] -macro foo() { - -} +#[eii_extern_target(bar)] +#[rustc_builtin_macro(eii_shared_macro)] +macro foo() {} unsafe extern "Rust" { safe fn bar<'a>(x: &'a u64) -> &'a u64; diff --git a/tests/ui/eii/subtype_4.rs b/tests/ui/eii/subtype_4.rs index 7207a6d73b6a..c55030238e75 100644 --- a/tests/ui/eii/subtype_4.rs +++ b/tests/ui/eii/subtype_4.rs @@ -7,11 +7,9 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_macro_for(bar)] -#[rustc_builtin_macro(eii_macro)] -macro foo() { - -} +#[eii_extern_target(bar)] +#[rustc_builtin_macro(eii_shared_macro)] +macro foo() {} unsafe extern "Rust" { safe fn bar(x: u64) -> u64; diff --git a/tests/ui/eii/unsafe_impl_err.rs b/tests/ui/eii/unsafe_impl_err.rs index 347bd67f838d..cb3eb5a27c63 100644 --- a/tests/ui/eii/unsafe_impl_err.rs +++ b/tests/ui/eii/unsafe_impl_err.rs @@ -5,11 +5,9 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_macro_for(bar, "unsafe")] -#[rustc_builtin_macro(eii_macro)] -macro foo() { - -} +#[eii_extern_target(bar, "unsafe")] +#[rustc_builtin_macro(eii_shared_macro)] +macro foo() {} unsafe extern "Rust" { safe fn bar(x: u64) -> u64; diff --git a/tests/ui/eii/unsafe_impl_ok.rs b/tests/ui/eii/unsafe_impl_ok.rs index 4281ce2feea7..5ffd1ef1321b 100644 --- a/tests/ui/eii/unsafe_impl_ok.rs +++ b/tests/ui/eii/unsafe_impl_ok.rs @@ -7,11 +7,9 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_macro_for(bar, "unsafe")] -#[rustc_builtin_macro(eii_macro)] -macro foo() { - -} +#[eii_extern_target(bar, "unsafe")] +#[rustc_builtin_macro(eii_shared_macro)] +macro foo() {} unsafe extern "Rust" { safe fn bar(x: u64) -> u64; diff --git a/tests/ui/eii/wrong_ret_ty.rs b/tests/ui/eii/wrong_ret_ty.rs index a9d4c475a70a..4a268ca675bc 100644 --- a/tests/ui/eii/wrong_ret_ty.rs +++ b/tests/ui/eii/wrong_ret_ty.rs @@ -5,11 +5,9 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_macro_for(bar)] -#[rustc_builtin_macro(eii_macro)] -macro foo() { - -} +#[eii_extern_target(bar)] +#[rustc_builtin_macro(eii_shared_macro)] +macro foo() {} unsafe extern "Rust" { safe fn bar(x: u64) -> u64; @@ -17,8 +15,7 @@ #[foo] fn other(_x: u64) { -//~^ ERROR function `other` has a type that is incompatible with the declaration - + //~^ ERROR function `other` has a type that is incompatible with the declaration } fn main() { diff --git a/tests/ui/eii/wrong_ty.rs b/tests/ui/eii/wrong_ty.rs index 45f95c4380d6..4fb81734c74a 100644 --- a/tests/ui/eii/wrong_ty.rs +++ b/tests/ui/eii/wrong_ty.rs @@ -5,11 +5,9 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_macro_for(bar)] -#[rustc_builtin_macro(eii_macro)] -macro foo() { - -} +#[eii_extern_target(bar)] +#[rustc_builtin_macro(eii_shared_macro)] +macro foo() {} unsafe extern "Rust" { safe fn bar(x: u64) -> u64; @@ -17,7 +15,7 @@ #[foo] fn other(x: usize) -> u64 { -//~^ ERROR function `other` has a type that is incompatible with the declaration + //~^ ERROR function `other` has a type that is incompatible with the declaration 3 } diff --git a/tests/ui/eii/wrong_ty_2.rs b/tests/ui/eii/wrong_ty_2.rs index a3d6d7e72774..085b9184caf0 100644 --- a/tests/ui/eii/wrong_ty_2.rs +++ b/tests/ui/eii/wrong_ty_2.rs @@ -5,11 +5,9 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_macro_for(bar)] -#[rustc_builtin_macro(eii_macro)] -macro foo() { - -} +#[eii_extern_target(bar)] +#[rustc_builtin_macro(eii_shared_macro)] +macro foo() {} unsafe extern "Rust" { safe fn bar(x: u64) -> u64; @@ -17,7 +15,7 @@ #[foo] fn other() -> u64 { -//~^ ERROR `other` has 0 parameters but #[foo] requires it to have + //~^ ERROR `other` has 0 parameters but #[foo] requires it to have 3 } From 3d38d9fdba183c780d89d5197aaaa66b47927ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 25 Aug 2025 16:50:35 +0200 Subject: [PATCH 545/585] EII add feature gate --- compiler/rustc_feature/src/unstable.rs | 4 ++++ compiler/rustc_span/src/symbol.rs | 1 + .../feature-gate-eii-internals.rs | 11 +++++++++++ .../feature-gate-eii-internals.stderr | 18 ++++++++++++++++++ tests/ui/feature-gates/feature-gate-eii.rs | 9 +++++++++ tests/ui/feature-gates/feature-gate-eii.stderr | 13 +++++++++++++ 6 files changed, 56 insertions(+) create mode 100644 tests/ui/feature-gates/feature-gate-eii-internals.rs create mode 100644 tests/ui/feature-gates/feature-gate-eii-internals.stderr create mode 100644 tests/ui/feature-gates/feature-gate-eii.rs create mode 100644 tests/ui/feature-gates/feature-gate-eii.stderr diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index ac01d98b4d1a..1568edd275bb 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -221,6 +221,8 @@ pub fn internal(&self, feature: Symbol) -> bool { (internal, compiler_builtins, "1.13.0", None), /// Allows writing custom MIR (internal, custom_mir, "1.65.0", None), + /// Implementation details of externally implementatble items + (internal, eii_internals, "CURRENT_RUSTC_VERSION", None), /// Outputs useful `assert!` messages (unstable, generic_assert, "1.63.0", None), /// Allows using the #[rustc_intrinsic] attribute. @@ -491,6 +493,8 @@ pub fn internal(&self, feature: Symbol) -> bool { (unstable, doc_masked, "1.21.0", Some(44027)), /// Allows features to allow target_feature to better interact with traits. (incomplete, effective_target_features, "1.91.0", Some(143352)), + /// Externally implementatble items + (unstable, extern_item_impls, "CURRENT_RUSTC_VERSION", Some(125418)), /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }` (incomplete, ergonomic_clones, "1.87.0", Some(132290)), /// Allows exhaustive pattern matching on types that contain uninhabited types. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 984ecc772d81..c609e00b8df7 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -933,6 +933,7 @@ eii_extern_target, eii_impl, eii_internals, + extern_item_impls, eii_shared_macro, emit, emit_enum, diff --git a/tests/ui/feature-gates/feature-gate-eii-internals.rs b/tests/ui/feature-gates/feature-gate-eii-internals.rs new file mode 100644 index 000000000000..b70e007ed798 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-eii-internals.rs @@ -0,0 +1,11 @@ +#![crate_type = "rlib"] +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[eii_extern_target(bar)] //~ ERROR use of unstable library feature `eii_internals` +#[rustc_builtin_macro(eii_macro)] +macro foo() {} //~ ERROR: cannot find a built-in macro with name `foo` + +unsafe extern "Rust" { + safe fn bar(x: u64) -> u64; +} diff --git a/tests/ui/feature-gates/feature-gate-eii-internals.stderr b/tests/ui/feature-gates/feature-gate-eii-internals.stderr new file mode 100644 index 000000000000..f08f0a5e65b3 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-eii-internals.stderr @@ -0,0 +1,18 @@ +error[E0658]: use of unstable library feature `eii_internals` + --> $DIR/feature-gate-eii-internals.rs:5:3 + | +LL | #[eii_extern_target(bar)] + | ^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(eii_internals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: cannot find a built-in macro with name `foo` + --> $DIR/feature-gate-eii-internals.rs:7:1 + | +LL | macro foo() {} + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-eii.rs b/tests/ui/feature-gates/feature-gate-eii.rs new file mode 100644 index 000000000000..3a51c3dd2eae --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-eii.rs @@ -0,0 +1,9 @@ +#![crate_type = "rlib"] + +#[eii] //~ ERROR use of unstable library feature `eii` +fn hello(x: u64); + +#[hello] +fn hello_impl(x: u64) { + println!("{x:?}") +} diff --git a/tests/ui/feature-gates/feature-gate-eii.stderr b/tests/ui/feature-gates/feature-gate-eii.stderr new file mode 100644 index 000000000000..6ec231257ba7 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-eii.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `eii` + --> $DIR/feature-gate-eii.rs:3:3 + | +LL | #[eii] + | ^^^ + | + = note: see issue #125418 for more information + = help: add `#![feature(eii)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 59d50cd2ad461996d6c9e1c424392235f5e9aca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 21 Aug 2025 15:13:01 +0200 Subject: [PATCH 546/585] EII nameres changes --- compiler/rustc_resolve/src/ident.rs | 1 - compiler/rustc_resolve/src/late.rs | 29 +++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e38d4370d5d2..9253879d2885 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -314,7 +314,6 @@ pub(crate) fn resolve_ident_in_lexical_scope( ignore_binding: Option>, diag_metadata: Option<&DiagMetadata<'_>>, ) -> Option> { - assert!(ns == TypeNS || ns == ValueNS); let orig_ident = ident; let (general_span, normalized_span) = if ident.name == kw::SelfUpper { // FIXME(jseyfried) improve `Self` hygiene diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f1a03d5a0610..7a8cd43b0425 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -447,6 +447,8 @@ pub(crate) enum PathSource<'a, 'ast, 'ra> { ReturnTypeNotation, /// Paths from `#[define_opaque]` attributes DefineOpaques, + /// Resolving a macro + Macro, } impl PathSource<'_, '_, '_> { @@ -463,6 +465,7 @@ fn namespace(self) -> Namespace { | PathSource::ReturnTypeNotation => ValueNS, PathSource::TraitItem(ns, _) => ns, PathSource::PreciseCapturingArg(ns) => ns, + PathSource::Macro => MacroNS, } } @@ -478,7 +481,8 @@ fn defer_to_typeck(self) -> bool { | PathSource::TraitItem(..) | PathSource::DefineOpaques | PathSource::Delegation - | PathSource::PreciseCapturingArg(..) => false, + | PathSource::PreciseCapturingArg(..) + | PathSource::Macro => false, } } @@ -520,6 +524,7 @@ fn descr_expected(self) -> &'static str { }, PathSource::ReturnTypeNotation | PathSource::Delegation => "function", PathSource::PreciseCapturingArg(..) => "type or const parameter", + PathSource::Macro => "macro", } } @@ -614,6 +619,7 @@ pub(crate) fn is_expected(self, res: Res) -> bool { Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } ), PathSource::PreciseCapturingArg(MacroNS) => false, + PathSource::Macro => matches!(res, Res::Def(DefKind::Macro(_), _)), } } @@ -633,6 +639,7 @@ fn error_code(self, has_unexpected_resolution: bool) -> ErrCode { (PathSource::TraitItem(..) | PathSource::ReturnTypeNotation, false) => E0576, (PathSource::PreciseCapturingArg(..), true) => E0799, (PathSource::PreciseCapturingArg(..), false) => E0800, + (PathSource::Macro, _) => E0425, } } } @@ -1058,6 +1065,12 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, _: &AttrVec, sp: Span, fn_id: Node }; debug!("(resolving function) entering function"); + if let FnKind::Fn(_, _, f) = fn_kind { + for EiiImpl { node_id, eii_macro_path, .. } in &f.eii_impls { + self.smart_resolve_path(*node_id, &None, &eii_macro_path, PathSource::Macro); + } + } + // Create a value rib for the function. self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { // Create a label rib for the function. @@ -2130,7 +2143,8 @@ fn resolve_elided_lifetimes_in_path( | PathSource::TraitItem(..) | PathSource::Type | PathSource::PreciseCapturingArg(..) - | PathSource::ReturnTypeNotation => false, + | PathSource::ReturnTypeNotation + | PathSource::Macro => false, PathSource::Expr(..) | PathSource::Pat | PathSource::Struct(_) @@ -2887,6 +2901,17 @@ fn resolve_item(&mut self, item: &'ast Item) { let def_id = self.r.local_def_id(item.id); self.parent_scope.macro_rules = self.r.macro_rules_scopes[&def_id]; } + + if let Some(EiiExternTarget { extern_item_path, impl_unsafe: _, span: _ }) = + ¯o_def.eii_extern_target + { + self.smart_resolve_path( + item.id, + &None, + extern_item_path, + PathSource::Expr(None), + ); + } } ItemKind::ForeignMod(_) | ItemKind::GlobalAsm(_) => { From 33df6ccb21679fc3bfe479d8a3b7b8301bee4231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 12 Aug 2025 12:26:18 +0200 Subject: [PATCH 547/585] EII lowering --- compiler/rustc_ast_lowering/src/item.rs | 97 ++++++++++++++++++- compiler/rustc_ast_lowering/src/lib.rs | 16 ++- .../rustc_hir/src/attrs/data_structures.rs | 23 +++++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 2 + .../rustc_hir/src/attrs/pretty_printing.rs | 2 + compiler/rustc_passes/messages.ftl | 15 +++ compiler/rustc_passes/src/check_attr.rs | 45 ++++++++- compiler/rustc_passes/src/errors.rs | 39 ++++++++ 8 files changed, 232 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 1db6a31e305d..0e0ded0b27a0 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -2,7 +2,7 @@ use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; -use rustc_hir::attrs::AttributeKind; +use rustc_hir::attrs::{AttributeKind, EiiDecl}; use rustc_hir::def::{DefKind, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{ @@ -11,6 +11,7 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; +use rustc_span::def_id::DefId; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; @@ -133,10 +134,92 @@ pub(super) fn lower_mod( } } + fn generate_extra_attrs_for_item_kind( + &mut self, + id: NodeId, + i: &ItemKind, + ) -> Vec { + match i { + ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(), + ItemKind::Fn(box Fn { eii_impls, .. }) => { + vec![hir::Attribute::Parsed(AttributeKind::EiiImpls( + eii_impls + .iter() + .flat_map( + |EiiImpl { + node_id, + eii_macro_path, + impl_safety, + span, + inner_span, + is_default, + }| { + self.lower_path_simple_eii(*node_id, eii_macro_path).map(|did| { + hir::attrs::EiiImpl { + eii_macro: did, + span: self.lower_span(*span), + inner_span: self.lower_span(*inner_span), + impl_marked_unsafe: self + .lower_safety(*impl_safety, hir::Safety::Safe) + .is_unsafe(), + is_default: *is_default, + } + }) + }, + ) + .collect(), + ))] + } + ItemKind::MacroDef( + _, + MacroDef { + eii_extern_target: Some(EiiExternTarget { extern_item_path, impl_unsafe, span }), + .. + }, + ) => self + .lower_path_simple_eii(id, extern_item_path) + .map(|did| { + vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(EiiDecl { + eii_extern_target: did, + impl_unsafe: *impl_unsafe, + span: self.lower_span(*span), + }))] + }) + .unwrap_or_default(), + ItemKind::ExternCrate(..) + | ItemKind::Use(..) + | ItemKind::Static(..) + | ItemKind::Const(..) + | ItemKind::Mod(..) + | ItemKind::ForeignMod(..) + | ItemKind::GlobalAsm(..) + | ItemKind::TyAlias(..) + | ItemKind::Enum(..) + | ItemKind::Struct(..) + | ItemKind::Union(..) + | ItemKind::Trait(..) + | ItemKind::TraitAlias(..) + | ItemKind::Impl(..) + | ItemKind::MacCall(..) + | ItemKind::MacroDef(..) + | ItemKind::Delegation(..) + | ItemKind::DelegationMac(..) => Vec::new(), + } + } + fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> { let vis_span = self.lower_span(i.vis.span); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, Target::from_ast_item(i)); + + let extra_hir_attributes = self.generate_extra_attrs_for_item_kind(i.id, &i.kind); + let attrs = self.lower_attrs_with_extra( + hir_id, + &i.attrs, + i.span, + Target::from_ast_item(i), + &extra_hir_attributes, + ); + let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind); let item = hir::Item { owner_id: hir_id.expect_owner(), @@ -469,6 +552,16 @@ fn lower_item_kind( } } + fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> Option { + let res = self.resolver.get_partial_res(id)?; + let Some(did) = res.expect_full_res().opt_def_id() else { + self.dcx().span_delayed_bug(path.span, "should have errored in resolve"); + return None; + }; + + Some(did) + } + #[instrument(level = "debug", skip(self))] fn lower_use_tree( &mut self, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c20bbcca44f7..a84e795af1be 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -971,11 +971,23 @@ fn lower_attrs( target_span: Span, target: Target, ) -> &'hir [hir::Attribute] { - if attrs.is_empty() { + self.lower_attrs_with_extra(id, attrs, target_span, target, &[]) + } + + fn lower_attrs_with_extra( + &mut self, + id: HirId, + attrs: &[Attribute], + target_span: Span, + target: Target, + extra_hir_attributes: &[hir::Attribute], + ) -> &'hir [hir::Attribute] { + if attrs.is_empty() && extra_hir_attributes.is_empty() { &[] } else { - let lowered_attrs = + let mut lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target); + lowered_attrs.extend(extra_hir_attributes.iter().cloned()); assert_eq!(id.owner, self.current_hir_id_owner); let ret = self.arena.alloc_from_iter(lowered_attrs); diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index b7f8be3ec88f..28433f261220 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -19,6 +19,23 @@ use crate::limit::Limit; use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability}; +#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub struct EiiImpl { + pub eii_macro: DefId, + pub impl_marked_unsafe: bool, + pub span: Span, + pub inner_span: Span, + pub is_default: bool, +} + +#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub struct EiiDecl { + pub eii_extern_target: DefId, + /// whether or not it is unsafe to implement this EII + pub impl_unsafe: bool, + pub span: Span, +} + #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)] pub enum InlineAttr { None, @@ -692,6 +709,12 @@ pub enum AttributeKind { /// Represents `#[rustc_dummy]`. Dummy, + /// Implementation detail of `#[eii]` + EiiExternTarget(EiiDecl), + + /// Implementation detail of `#[eii]` + EiiImpls(ThinVec), + /// Represents [`#[export_name]`](https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute). ExportName { /// The name to export this item with. diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index ad120648c1ee..e42d511da695 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -43,6 +43,8 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate { Doc(_) => Yes, DocComment { .. } => Yes, Dummy => No, + EiiExternTarget(_) => Yes, + EiiImpls(..) => No, ExportName { .. } => Yes, ExportStable => No, FfiConst(..) => No, diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs index 29df586ed296..0ad486cef43d 100644 --- a/compiler/rustc_hir/src/attrs/pretty_printing.rs +++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs @@ -5,6 +5,7 @@ use rustc_ast::{AttrStyle, IntTy, UintTy}; use rustc_ast_pretty::pp::Printer; use rustc_data_structures::fx::FxIndexMap; +use rustc_span::def_id::DefId; use rustc_span::hygiene::Transparency; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; use rustc_target::spec::SanitizerSet; @@ -170,4 +171,5 @@ fn print_attribute(&self, p: &mut Printer) { DocFragmentKind, Transparency, SanitizerSet, + DefId, ); diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 4e8973e4928b..43c3b3fb3619 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -590,3 +590,18 @@ passes_useless_stability = this stability annotation is useless .label = useless stability annotation .item = the stability attribute annotates this item + +passes_eii_fn_with_target_feature = + `#[{$name}]` is not allowed to have `#[target_feature]` + .label = `#[{$name}]` is not allowed to have `#[target_feature]` + +passes_eii_fn_with_track_caller = + `#[{$name}]` is not allowed to have `#[track_caller]` + .label = `#[{$name}]` is not allowed to have `#[track_caller]` + +passes_eii_impl_not_function = + `eii_macro_for` is only valid on functions + +passes_eii_impl_requires_unsafe = + `#[{$name}]` is unsafe to implement +passes_eii_impl_requires_unsafe_suggestion = wrap the attribute in `unsafe(...)` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 030839baad9b..d5d2d64ffaf7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -19,8 +19,8 @@ BuiltinAttribute, }; use rustc_hir::attrs::{ - AttributeKind, DocAttribute, DocInline, InlineAttr, MirDialect, MirPhase, ReprAttr, - SanitizerSet, + AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, InlineAttr, MirDialect, MirPhase, + ReprAttr, SanitizerSet, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModDefId; @@ -212,8 +212,12 @@ fn check_attributes( self.check_macro_export(hir_id, *span, target) }, Attribute::Parsed(AttributeKind::Doc(attr)) => self.check_doc_attrs(attr, hir_id, target), + Attribute::Parsed(AttributeKind::EiiImpls(impls)) => { + self.check_eii_impl(impls, target) + }, Attribute::Parsed( - AttributeKind::BodyStability { .. } + AttributeKind::EiiExternTarget { .. } + | AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect | AttributeKind::MacroTransparency(_) | AttributeKind::Pointee(..) @@ -459,6 +463,30 @@ fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr_span: Span, s ); } + fn check_eii_impl(&self, impls: &[EiiImpl], target: Target) { + for EiiImpl { span, inner_span, eii_macro, impl_marked_unsafe, is_default: _ } in impls { + match target { + Target::Fn => {} + _ => { + self.dcx().emit_err(errors::EiiImplNotFunction { span: *span }); + } + } + + if find_attr!(self.tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl { impl_unsafe, .. }) if *impl_unsafe) + && !impl_marked_unsafe + { + self.dcx().emit_err(errors::EiiImplRequiresUnsafe { + span: *span, + name: self.tcx.item_name(*eii_macro), + suggestion: errors::EiiImplRequiresUnsafeSuggestion { + left: inner_span.shrink_to_lo(), + right: inner_span.shrink_to_hi(), + }, + }); + } + } + } + /// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl and that it has no /// arguments. fn check_do_not_recommend( @@ -684,6 +712,17 @@ fn check_track_caller( sig_span: sig.span, }); } + + if let Some(impls) = find_attr!(attrs, AttributeKind::EiiImpls(impls) => impls) { + let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); + for i in impls { + self.dcx().emit_err(errors::EiiWithTrackCaller { + attr_span, + name: self.tcx.item_name(i.eii_macro), + sig_span: sig.span, + }); + } + } } _ => {} } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 3a2908d14184..c8db9efe4773 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1305,3 +1305,42 @@ pub(crate) struct CustomMirIncompatibleDialectAndPhase { #[label] pub phase_span: Span, } + +#[derive(Diagnostic)] +#[diag(passes_eii_impl_not_function)] +pub(crate) struct EiiImplNotFunction { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_eii_impl_requires_unsafe)] +pub(crate) struct EiiImplRequiresUnsafe { + #[primary_span] + pub span: Span, + pub name: Symbol, + #[subdiagnostic] + pub suggestion: EiiImplRequiresUnsafeSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + passes_eii_impl_requires_unsafe_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct EiiImplRequiresUnsafeSuggestion { + #[suggestion_part(code = "unsafe(")] + pub left: Span, + #[suggestion_part(code = ")")] + pub right: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_eii_fn_with_track_caller)] +pub(crate) struct EiiWithTrackCaller { + #[primary_span] + pub attr_span: Span, + pub name: Symbol, + #[label] + pub sig_span: Span, +} From 1cbdaf246bd4d785bab19666e02f9fd4352771a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 12 Aug 2025 14:39:53 +0200 Subject: [PATCH 548/585] EII collection queries EII collection queries --- compiler/rustc_interface/src/passes.rs | 3 + compiler/rustc_metadata/src/eii.rs | 48 ++++++ compiler/rustc_metadata/src/lib.rs | 1 + compiler/rustc_metadata/src/rmeta/decoder.rs | 8 + .../src/rmeta/decoder/cstore_impl.rs | 16 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 14 ++ compiler/rustc_metadata/src/rmeta/mod.rs | 2 + .../rustc_metadata/src/rmeta/parameterized.rs | 2 + compiler/rustc_middle/src/query/erase.rs | 2 + compiler/rustc_middle/src/query/mod.rs | 13 +- compiler/rustc_passes/messages.ftl | 42 +++-- compiler/rustc_passes/src/eii.rs | 158 ++++++++++++++++++ compiler/rustc_passes/src/errors.rs | 38 +++++ compiler/rustc_passes/src/lib.rs | 2 + 14 files changed, 332 insertions(+), 17 deletions(-) create mode 100644 compiler/rustc_metadata/src/eii.rs create mode 100644 compiler/rustc_passes/src/eii.rs diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index ddfec9f886a6..fe28e5e591e2 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1061,6 +1061,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { parallel!( { sess.time("looking_for_entry_point", || tcx.ensure_ok().entry_fn(())); + sess.time("check_externally_implementable_items", || { + tcx.ensure_ok().check_externally_implementable_items(()) + }); sess.time("looking_for_derive_registrar", || { tcx.ensure_ok().proc_macro_decls_static(()) diff --git a/compiler/rustc_metadata/src/eii.rs b/compiler/rustc_metadata/src/eii.rs new file mode 100644 index 000000000000..2d99ba516ad4 --- /dev/null +++ b/compiler/rustc_metadata/src/eii.rs @@ -0,0 +1,48 @@ +use rustc_data_structures::fx::FxIndexMap; +use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl}; +use rustc_hir::def_id::DefId; +use rustc_hir::find_attr; +use rustc_middle::query::LocalCrate; +use rustc_middle::ty::TyCtxt; + +// basically the map below but flattened out +pub(crate) type EiiMapEncodedKeyValue = (DefId, (EiiDecl, Vec<(DefId, EiiImpl)>)); + +pub(crate) type EiiMap = FxIndexMap< + DefId, // the defid of the macro that declared the eii + ( + // the corresponding declaration + EiiDecl, + // all the given implementations, indexed by defid. + // We expect there to be only one, but collect them all to give errors if there are more + // (or if there are none) in the final crate we build. + FxIndexMap, + ), +>; + +pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap { + let mut eiis = EiiMap::default(); + + // iterate over all items in the current crate + // FIXME(speed up) + for id in tcx.hir_crate_items(()).definitions() { + for i in + find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiImpls(e) => e).into_iter().flatten() + { + eiis.entry(i.eii_macro) + .or_insert_with(|| { + // find the decl for this one if it wasn't in yet (maybe it's from the local crate? not very useful but not illegal) + (find_attr!(tcx.get_all_attrs(i.eii_macro), AttributeKind::EiiExternTarget(d) => *d).unwrap(), Default::default()) + }).1.insert(id.into(), *i); + } + + // if we find a new declaration, add it to the list without a known implementation + if let Some(decl) = + find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiExternTarget(d) => *d) + { + eiis.entry(id.into()).or_insert((decl, Default::default())); + } + } + + eiis +} diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 114301083883..f31c4938e118 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -16,6 +16,7 @@ pub use rmeta::provide; mod dependency_format; +mod eii; mod foreign_modules; mod native_libs; mod rmeta; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 76438f046dd5..1b9c7b1d8e75 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -39,6 +39,7 @@ use tracing::debug; use crate::creader::CStore; +use crate::eii::EiiMapEncodedKeyValue; use crate::rmeta::table::IsDefault; use crate::rmeta::*; @@ -1487,6 +1488,13 @@ fn get_dylib_dependency_formats<'tcx>( ) } + fn get_externally_implementable_items( + self, + tcx: TyCtxt<'_>, + ) -> impl Iterator { + self.root.externally_implementable_items.decode((self, tcx)) + } + fn get_missing_lang_items<'tcx>(self, tcx: TyCtxt<'tcx>) -> &'tcx [LangItem] { tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode((self, tcx))) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index c48cf36930f4..f441788fdcb6 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -25,7 +25,7 @@ use crate::creader::{CStore, LoadedMacro}; use crate::rmeta::AttrFlags; use crate::rmeta::table::IsDefault; -use crate::{foreign_modules, native_libs}; +use crate::{eii, foreign_modules, native_libs}; trait ProcessQueryValue<'tcx, T> { fn process_decoded(self, _tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> T; @@ -330,9 +330,22 @@ fn into_args(self) -> (DefId, SimplifiedType) { is_private_dep => { cdata.private_dep } is_panic_runtime => { cdata.root.panic_runtime } is_compiler_builtins => { cdata.root.compiler_builtins } + + // FIXME: to be replaced with externally_implementable_items below has_global_allocator => { cdata.root.has_global_allocator } + // FIXME: to be replaced with externally_implementable_items below has_alloc_error_handler => { cdata.root.has_alloc_error_handler } + // FIXME: to be replaced with externally_implementable_items below has_panic_handler => { cdata.root.has_panic_handler } + + externally_implementable_items => { + cdata.get_externally_implementable_items(tcx) + .map(|(decl_did, (decl, impls))| ( + decl_did, + (decl, impls.into_iter().collect()) + )).collect() + } + is_profiler_runtime => { cdata.root.profiler_runtime } required_panic_strategy => { cdata.root.required_panic_strategy } panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy } @@ -430,6 +443,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { }, native_libraries: native_libs::collect, foreign_modules: foreign_modules::collect, + externally_implementable_items: eii::collect, // Returns a map from a sufficiently visible external item (i.e., an // external item that is visible from at least one local module) to a diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 2069c06c3f77..a72e8e514292 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -35,6 +35,7 @@ }; use tracing::{debug, instrument, trace}; +use crate::eii::EiiMapEncodedKeyValue; use crate::errors::{FailCreateFileEncoder, FailWriteFile}; use crate::rmeta::*; @@ -620,6 +621,9 @@ macro_rules! stat { // We have already encoded some things. Get their combined size from the current position. stats.push(("preamble", self.position())); + let externally_implementable_items = stat!("externally-implementable-items", || self + .encode_externally_implementable_items()); + let (crate_deps, dylib_dependency_formats) = stat!("dep", || (self.encode_crate_deps(), self.encode_dylib_dependency_formats())); @@ -738,6 +742,7 @@ macro_rules! stat { attrs, sym::default_lib_allocator, ), + externally_implementable_items, proc_macro_data, debugger_visualizers, compiler_builtins: ast::attr::contains_name(attrs, sym::compiler_builtins), @@ -1649,6 +1654,15 @@ fn encode_def_ids(&mut self) { } } + fn encode_externally_implementable_items(&mut self) -> LazyArray { + empty_proc_macro!(self); + let externally_implementable_items = self.tcx.externally_implementable_items(LOCAL_CRATE); + + self.lazy_array(externally_implementable_items.iter().map(|(decl_did, (decl, impls))| { + (*decl_did, (decl.clone(), impls.iter().map(|(impl_did, i)| (*impl_did, *i)).collect())) + })) + } + #[instrument(level = "trace", skip(self))] fn encode_info_for_adt(&mut self, local_def_id: LocalDefId) { let def_id = local_def_id.to_def_id(); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index c5230685bfaf..0de54cf87433 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -44,6 +44,7 @@ use {rustc_ast as ast, rustc_hir as hir}; use crate::creader::CrateMetadataRef; +use crate::eii::EiiMapEncodedKeyValue; mod decoder; mod def_path_hash_map; @@ -250,6 +251,7 @@ pub(crate) struct CrateRoot { has_alloc_error_handler: bool, has_panic_handler: bool, has_default_lib_allocator: bool, + externally_implementable_items: LazyArray, crate_deps: LazyArray, dylib_dependency_formats: LazyArray>, diff --git a/compiler/rustc_metadata/src/rmeta/parameterized.rs b/compiler/rustc_metadata/src/rmeta/parameterized.rs index d6ccad798112..8a9de07836db 100644 --- a/compiler/rustc_metadata/src/rmeta/parameterized.rs +++ b/compiler/rustc_metadata/src/rmeta/parameterized.rs @@ -87,6 +87,8 @@ impl ParameterizedOverTcx for $ty { rustc_hir::Safety, rustc_hir::Stability, rustc_hir::attrs::Deprecation, + rustc_hir::attrs::EiiDecl, + rustc_hir::attrs::EiiImpl, rustc_hir::attrs::StrippedCfgItem, rustc_hir::def::DefKind, rustc_hir::def::DocLinkResMap, diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 404330a9a45a..774dd88997f2 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -296,6 +296,8 @@ impl EraseType for $ty { rustc_ast::expand::allocator::AllocatorKind, rustc_hir::DefaultBodyStability, rustc_hir::attrs::Deprecation, + rustc_hir::attrs::EiiDecl, + rustc_hir::attrs::EiiImpl, rustc_data_structures::svh::Svh, rustc_errors::ErrorGuaranteed, rustc_hir::Constness, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 15c84a5b01fb..9b4306f656d6 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -76,7 +76,7 @@ use rustc_data_structures::svh::Svh; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::ErrorGuaranteed; -use rustc_hir::attrs::StrippedCfgItem; +use rustc_hir::attrs::{EiiDecl, EiiImpl, StrippedCfgItem}; use rustc_hir::def::{DefKind, DocLinkResMap}; use rustc_hir::def_id::{ CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId, @@ -2753,6 +2753,17 @@ desc { |tcx| "checking what set of sanitizers are enabled on `{}`", tcx.def_path_str(key) } feedable } + + query check_externally_implementable_items(_: ()) { + desc { "check externally implementable items" } + } + + /// Returns a list of all `externally implementable items` crate. + query externally_implementable_items(_: CrateNum) -> &'tcx FxIndexMap)> { + arena_cache + desc { "looking up the externally implementable items of a crate" } + separate_provide_extern + } } rustc_with_all_queries! { define_callbacks! } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 43c3b3fb3619..21191085253b 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -164,6 +164,17 @@ passes_duplicate_diagnostic_item_in_crate = duplicate diagnostic item in crate `{$crate_name}`: `{$name}` .note = the diagnostic item is first defined in crate `{$orig_crate_name}` +passes_duplicate_eii_impls = + multiple implementations of `#[{$name}]` + .first = first implemented here in crate `{$first_crate}` + .second = also implemented here in crate `{$second_crate}` + .note = in addition to these two, { $num_additional_crates -> + [one] another implementation was found in crate {$additional_crate_names} + *[other] more implementations were also found in the following crates: {$additional_crate_names} + } + + .help = an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict + passes_duplicate_feature_err = the feature `{$feature}` has already been enabled @@ -197,6 +208,22 @@ passes_duplicate_lang_item_crate_depends = .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} +passes_eii_fn_with_track_caller = + `#[{$name}]` is not allowed to have `#[track_caller]` + .label = `#[{$name}]` is not allowed to have `#[track_caller]` + +passes_eii_impl_not_function = + `eii_macro_for` is only valid on functions + +passes_eii_impl_requires_unsafe = + `#[{$name}]` is unsafe to implement +passes_eii_impl_requires_unsafe_suggestion = wrap the attribute in `unsafe(...)` + +passes_eii_without_impl = + `#[{$name}]` required, but not found + .label = expected because `#[{$name}]` was declared here in crate `{$decl_crate_name}` + .help = expected at least one implementation in crate `{$current_crate_name}` or any of its dependencies + passes_enum_variant_same_name = it is impossible to refer to the {$dead_descr} `{$dead_name}` because it is shadowed by this enum variant with the same name @@ -590,18 +617,3 @@ passes_useless_stability = this stability annotation is useless .label = useless stability annotation .item = the stability attribute annotates this item - -passes_eii_fn_with_target_feature = - `#[{$name}]` is not allowed to have `#[target_feature]` - .label = `#[{$name}]` is not allowed to have `#[target_feature]` - -passes_eii_fn_with_track_caller = - `#[{$name}]` is not allowed to have `#[track_caller]` - .label = `#[{$name}]` is not allowed to have `#[track_caller]` - -passes_eii_impl_not_function = - `eii_macro_for` is only valid on functions - -passes_eii_impl_requires_unsafe = - `#[{$name}]` is unsafe to implement -passes_eii_impl_requires_unsafe_suggestion = wrap the attribute in `unsafe(...)` diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs new file mode 100644 index 000000000000..691576e6a05f --- /dev/null +++ b/compiler/rustc_passes/src/eii.rs @@ -0,0 +1,158 @@ +//! Checks necessary for externally implementable items: +//! Are all items implemented etc.? + +use std::iter; + +use rustc_data_structures::fx::FxIndexMap; +use rustc_hir::attrs::{EiiDecl, EiiImpl}; +use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_middle::ty::TyCtxt; +use rustc_session::config::CrateType; + +use crate::errors::{DuplicateEiiImpls, EiiWithoutImpl}; + +#[derive(Clone, Copy, Debug)] +enum CheckingMode { + CheckDuplicates, + CheckExistence, +} + +fn get_checking_mode(tcx: TyCtxt<'_>) -> CheckingMode { + // if any of the crate types is not rlib or dylib, we must check for existence. + if tcx.crate_types().iter().any(|i| !matches!(i, CrateType::Rlib | CrateType::Dylib)) { + CheckingMode::CheckExistence + } else { + CheckingMode::CheckDuplicates + } +} + +/// Checks for a given crate, what EIIs need to be generated in it. +/// This is usually a small subset of all EIIs. +/// +/// EII implementations come in two varieties: explicit and default. +/// This query is called once for every crate, to check whether there aren't any duplicate explicit implementations. +/// A duplicate may be caused by an implementation in the current crate, +/// though it's also entirely possible that the source is two dependencies with an explicit implementation. +/// Those work fine on their own but the combination of the two is a conflict. +/// +/// However, if the current crate is a "root" crate, one that generates a final artifact like a binary, +/// then we check one more thing, namely that every EII actually has an implementation, either default or not. +/// If one EII has no implementation, that's an error at that point. +/// +/// These two behaviors are implemented using `CheckingMode`. +pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) { + let checking_mode = get_checking_mode(tcx); + + #[derive(Debug)] + struct FoundImpl { + imp: EiiImpl, + impl_crate: CrateNum, + } + + #[derive(Debug)] + struct FoundEii { + decl: EiiDecl, + decl_crate: CrateNum, + impls: FxIndexMap, + } + + let mut eiis = FxIndexMap::::default(); + + // collect all the EII declarations, and possibly implementations from all descendent crates + for &cnum in tcx.crates(()).iter().chain(iter::once(&LOCAL_CRATE)) { + // get the eiis for the crate we're currently looking at + let crate_eiis = tcx.externally_implementable_items(cnum); + + // update or insert the corresponding entries + for (did, (decl, impls)) in crate_eiis { + eiis.entry(*did) + .or_insert_with(|| FoundEii { + decl: *decl, + decl_crate: cnum, + impls: Default::default(), + }) + .impls + .extend( + impls + .into_iter() + .map(|(did, i)| (*did, FoundImpl { imp: *i, impl_crate: cnum })), + ); + } + } + + // now we have all eiis! For each of them, choose one we want to actually generate. + for (decl_did, FoundEii { decl, decl_crate, impls }) in eiis { + let mut default_impls = Vec::new(); + let mut explicit_impls = Vec::new(); + + for (impl_did, FoundImpl { imp, impl_crate }) in impls { + if imp.is_default { + default_impls.push((impl_did, impl_crate)); + } else { + explicit_impls.push((impl_did, impl_crate)); + } + } + + // more than one explicit implementation (across all crates) + // is instantly an error. + if explicit_impls.len() > 1 { + tcx.dcx().emit_err(DuplicateEiiImpls { + name: tcx.item_name(decl_did), + first_span: tcx.def_span(explicit_impls[0].0), + first_crate: tcx.crate_name(explicit_impls[0].1), + second_span: tcx.def_span(explicit_impls[1].0), + second_crate: tcx.crate_name(explicit_impls[1].1), + + help: (), + + additional_crates: (explicit_impls.len() > 2).then_some(()), + num_additional_crates: explicit_impls.len() - 2, + additional_crate_names: explicit_impls[2..] + .iter() + .map(|i| format!("`{}`", tcx.crate_name(i.1))) + .collect::>() + .join(", "), + }); + } + + if default_impls.len() > 1 { + panic!("multiple not supported right now"); + } + + let (local_impl, is_default) = + // note, for a single crate we never need to generate both a default and an explicit implementation. + // In that case, generating the explicit implementation is enough! + match (checking_mode, explicit_impls.first(), default_impls.first()) { + // If we find an explicit implementation, it's instantly the chosen implementation. + (_, Some((explicit, _)), _) => (explicit, false), + // if we find a default implementation, we can emit it but the alias should be weak + (_, _, Some((deflt, _))) => (deflt, true), + + // if we find no explicit implementation, + // that's fine if we're only checking for duplicates. + // The existence will be checked somewhere else in a crate downstream. + (CheckingMode::CheckDuplicates, None, _) => continue, + + // We have a target to generate, but no impl to put in it. error! + (CheckingMode::CheckExistence, None, None) => { + tcx.dcx().emit_err(EiiWithoutImpl { + current_crate_name: tcx.crate_name(LOCAL_CRATE), + decl_crate_name: tcx.crate_name(decl_crate), + name: tcx.item_name(decl_did), + span: decl.span, + help: (), + }); + + continue; + } + }; + + // if it's not local, who cares about generating it. + // That's the local crates' responsibility + let Some(chosen_impl) = local_impl.as_local() else { + continue; + }; + + tracing::debug!("generating EII {chosen_impl:?} (default={is_default})"); + } +} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index c8db9efe4773..7abd2c703aeb 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1344,3 +1344,41 @@ pub(crate) struct EiiWithTrackCaller { #[label] pub sig_span: Span, } + +#[derive(Diagnostic)] +#[diag(passes_eii_without_impl)] +pub(crate) struct EiiWithoutImpl { + #[primary_span] + #[label] + pub span: Span, + pub name: Symbol, + + pub current_crate_name: Symbol, + pub decl_crate_name: Symbol, + #[help] + pub help: (), +} + +#[derive(Diagnostic)] +#[diag(passes_duplicate_eii_impls)] +pub(crate) struct DuplicateEiiImpls { + pub name: Symbol, + + #[primary_span] + #[label(passes_first)] + pub first_span: Span, + pub first_crate: Symbol, + + #[label(passes_second)] + pub second_span: Span, + pub second_crate: Symbol, + + #[note] + pub additional_crates: Option<()>, + + pub num_additional_crates: usize, + pub additional_crate_names: String, + + #[help] + pub help: (), +} diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 149714f943a7..865f2a9c3b8b 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -17,6 +17,7 @@ pub mod dead; mod debugger_visualizer; mod diagnostic_items; +mod eii; pub mod entry; mod errors; pub mod hir_id_validator; @@ -43,4 +44,5 @@ pub fn provide(providers: &mut Providers) { stability::provide(providers); upvars::provide(providers); check_export::provide(providers); + providers.check_externally_implementable_items = eii::check_externally_implementable_items; } From b732030025eb67ff88f942e9b2895042ac6a3e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 10 Sep 2025 13:21:59 -0700 Subject: [PATCH 549/585] make EII iteration faster --- compiler/rustc_ast_lowering/src/item.rs | 8 ++++++++ compiler/rustc_hir/src/hir.rs | 3 +++ compiler/rustc_hir/src/intravisit.rs | 2 +- compiler/rustc_metadata/src/eii.rs | 3 +-- compiler/rustc_middle/src/hir/map.rs | 12 ++++++++++++ compiler/rustc_middle/src/hir/mod.rs | 7 +++++++ 6 files changed, 32 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 0e0ded0b27a0..a68d63bf1464 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -227,6 +227,10 @@ fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> { vis_span, span: self.lower_span(i.span), has_delayed_lints: !self.delayed_lints.is_empty(), + eii: find_attr!( + attrs, + AttributeKind::EiiImpls(..) | AttributeKind::EiiExternTarget(..) + ), }; self.arena.alloc(item) } @@ -670,6 +674,10 @@ fn lower_use_tree( vis_span, span: this.lower_span(use_tree.span), has_delayed_lints: !this.delayed_lints.is_empty(), + eii: find_attr!( + attrs, + AttributeKind::EiiImpls(..) | AttributeKind::EiiExternTarget(..) + ), }; hir::OwnerNode::Item(this.arena.alloc(item)) }); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f5470adb87e0..c60471848c89 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4164,6 +4164,9 @@ pub struct Item<'hir> { pub span: Span, pub vis_span: Span, pub has_delayed_lints: bool, + /// hint to speed up collection: true if the item is a static or function and has + /// either an `EiiImpls` or `EiiExternTarget` attribute + pub eii: bool, } impl<'hir> Item<'hir> { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 625766f8bd3d..be3cab6461ef 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -532,7 +532,7 @@ pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> } pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result { - let Item { owner_id: _, kind, span: _, vis_span: _, has_delayed_lints: _ } = item; + let Item { owner_id: _, kind, span: _, vis_span: _, has_delayed_lints: _, eii: _ } = item; try_visit!(visitor.visit_id(item.hir_id())); match *kind { ItemKind::ExternCrate(orig_name, ident) => { diff --git a/compiler/rustc_metadata/src/eii.rs b/compiler/rustc_metadata/src/eii.rs index 2d99ba516ad4..5558ff930851 100644 --- a/compiler/rustc_metadata/src/eii.rs +++ b/compiler/rustc_metadata/src/eii.rs @@ -24,8 +24,7 @@ pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap let mut eiis = EiiMap::default(); // iterate over all items in the current crate - // FIXME(speed up) - for id in tcx.hir_crate_items(()).definitions() { + for id in tcx.hir_crate_items(()).eiis() { for i in find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiImpls(e) => e).into_iter().flatten() { diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index bf3192d9df17..5da762ef8565 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -1224,6 +1224,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod body_owners, opaques, nested_bodies, + eiis, .. } = collector; ModuleItems { @@ -1237,6 +1238,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod opaques: opaques.into_boxed_slice(), nested_bodies: nested_bodies.into_boxed_slice(), delayed_lint_items: Box::new([]), + eiis: eiis.into_boxed_slice(), } } @@ -1259,6 +1261,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { opaques, nested_bodies, mut delayed_lint_items, + eiis, .. } = collector; @@ -1281,6 +1284,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { opaques: opaques.into_boxed_slice(), nested_bodies: nested_bodies.into_boxed_slice(), delayed_lint_items: delayed_lint_items.into_boxed_slice(), + eiis: eiis.into_boxed_slice(), } } @@ -1298,6 +1302,7 @@ struct ItemCollector<'tcx> { opaques: Vec, nested_bodies: Vec, delayed_lint_items: Vec, + eiis: Vec, } impl<'tcx> ItemCollector<'tcx> { @@ -1314,6 +1319,7 @@ fn new(tcx: TyCtxt<'tcx>, crate_collector: bool) -> ItemCollector<'tcx> { opaques: Vec::default(), nested_bodies: Vec::default(), delayed_lint_items: Vec::default(), + eiis: Vec::default(), } } } @@ -1335,6 +1341,12 @@ fn visit_item(&mut self, item: &'hir Item<'hir>) { self.delayed_lint_items.push(item.item_id().owner_id); } + if let ItemKind::Static(..) | ItemKind::Fn { .. } | ItemKind::Macro(..) = &item.kind + && item.eii + { + self.eiis.push(item.owner_id.def_id) + } + // Items that are modules are handled here instead of in visit_mod. if let ItemKind::Mod(_, module) = &item.kind { self.submodules.push(item.owner_id); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 0ab5a792e040..217ecbab059e 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -37,6 +37,9 @@ pub struct ModuleItems { nested_bodies: Box<[LocalDefId]>, // only filled with hir_crate_items, not with hir_module_items delayed_lint_items: Box<[OwnerId]>, + + /// Statics and functions with an `EiiImpls` or `EiiExternTarget` attribute + eiis: Box<[LocalDefId]>, } impl ModuleItems { @@ -58,6 +61,10 @@ pub fn delayed_lint_items(&self) -> impl Iterator { self.delayed_lint_items.iter().copied() } + pub fn eiis(&self) -> impl Iterator { + self.eiis.iter().copied() + } + /// Returns all items that are associated with some `impl` block (both inherent and trait impl /// blocks). pub fn impl_items(&self) -> impl Iterator { From 8dfb2cdecef9dea3a98dde094fcda54fbc23a892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 12 Aug 2025 14:40:05 +0200 Subject: [PATCH 550/585] EII type checking --- compiler/rustc_hir_analysis/messages.ftl | 11 + .../src/check/compare_eii.rs | 424 ++++++++++++++++++ compiler/rustc_hir_analysis/src/check/mod.rs | 1 + .../rustc_hir_analysis/src/check/wfcheck.rs | 28 +- compiler/rustc_hir_analysis/src/errors.rs | 25 ++ compiler/rustc_middle/src/traits/mod.rs | 7 + .../src/error_reporting/traits/suggestions.rs | 3 + 7 files changed, 498 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_hir_analysis/src/check/compare_eii.rs diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index bcf4d7f59e34..8022a48ee137 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -165,6 +165,10 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice .label = parameter captured again here +hir_analysis_eii_with_generics = + #[{$eii_name}] cannot have generic parameters other than lifetimes + .label = required by this attribute + hir_analysis_empty_specialization = specialization impl does not specialize any associated items .note = impl is a specialization of this impl @@ -300,6 +304,13 @@ hir_analysis_lifetime_not_captured = `impl Trait` captures lifetime parameter, b .label = lifetime captured due to being mentioned in the bounds of the `impl Trait` .param_label = this lifetime parameter is captured +hir_analysis_lifetimes_or_bounds_mismatch_on_eii = + lifetime parameters or bounds of `{$ident}` do not match the declaration + .label = lifetimes do not match + .generics_label = lifetimes in impl do not match this signature + .where_label = this `where` clause might not match the one in the declaration + .bounds_label = this bound might be missing in the implementation + hir_analysis_lifetimes_or_bounds_mismatch_on_trait = lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration .label = lifetimes do not match {$item_kind} in trait diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs new file mode 100644 index 000000000000..06b7f4952957 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -0,0 +1,424 @@ +use std::borrow::Cow; +use std::iter; + +use rustc_data_structures::fx::FxIndexSet; +use rustc_errors::{Applicability, E0805, struct_span_code_err}; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::{self as hir, FnSig, HirId, ItemKind}; +use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; +use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_middle::ty::{self, TyCtxt, TypingMode}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; +use rustc_trait_selection::regions::InferCtxtRegionExt; +use rustc_trait_selection::traits::ObligationCtxt; +use tracing::{debug, instrument}; + +use super::potentially_plural_count; +use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii}; + +/// checks whether the signature of some `external_impl`, matches +/// the signature of `declaration`, which it is supposed to be compatible +/// with in order to implement the item. +pub(crate) fn compare_eii_function_types<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + declaration: DefId, + eii_name: Symbol, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + check_is_structurally_compatible(tcx, external_impl, declaration, eii_name, eii_attr_span)?; + + let external_impl_span = tcx.def_span(external_impl); + let cause = ObligationCause::new( + external_impl_span, + external_impl, + ObligationCauseCode::CompareEii { external_impl, declaration }, + ); + + // FIXME(eii): even if we don't support generic functions, we should support explicit outlive bounds here + let param_env = tcx.param_env(declaration); + + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); + + // We now need to check that the signature of the impl method is + // compatible with that of the trait method. We do this by + // checking that `impl_fty <: trait_fty`. + // + // FIXME: We manually instantiate the trait method here as we need + // to manually compute its implied bounds. Otherwise this could just + // be ocx.sub(impl_sig, trait_sig). + + let wf_tys = FxIndexSet::default(); + let norm_cause = ObligationCause::misc(external_impl_span, external_impl); + + let declaration_sig = tcx.fn_sig(declaration).instantiate_identity(); + let declaration_sig = infcx.enter_forall_and_leak_universe(declaration_sig); + let declaration_sig = ocx.normalize(&norm_cause, param_env, declaration_sig); + + let external_impl_sig = infcx.instantiate_binder_with_fresh_vars( + external_impl_span, + infer::BoundRegionConversionTime::HigherRankedType, + tcx.fn_sig(external_impl).instantiate( + tcx, + infcx.fresh_args_for_item(external_impl_span, external_impl.to_def_id()), + ), + ); + let external_impl_sig = ocx.normalize(&norm_cause, param_env, external_impl_sig); + debug!(?external_impl_sig); + + // FIXME: We'd want to keep more accurate spans than "the method signature" when + // processing the comparison between the trait and impl fn, but we sadly lose them + // and point at the whole signature when a trait bound or specific input or output + // type would be more appropriate. In other places we have a `Vec` + // corresponding to their `Vec`, but we don't have that here. + // Fixing this would improve the output of test `issue-83765.rs`. + let result = ocx.sup(&cause, param_env, declaration_sig, external_impl_sig); + + if let Err(terr) = result { + debug!(?external_impl_sig, ?declaration_sig, ?terr, "sub_types failed"); + + let emitted = report_eii_mismatch( + infcx, + cause, + param_env, + terr, + (declaration, declaration_sig), + (external_impl, external_impl_sig), + eii_attr_span, + eii_name, + ); + return Err(emitted); + } + + // Check that all obligations are satisfied by the implementation's + // version. + let errors = ocx.evaluate_obligations_error_on_ambiguity(); + if !errors.is_empty() { + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); + return Err(reported); + } + + // Finally, resolve all regions. This catches wily misuses of + // lifetime parameters. + let errors = infcx.resolve_regions(external_impl, param_env, wf_tys); + if !errors.is_empty() { + return Err(infcx + .tainted_by_errors() + .unwrap_or_else(|| infcx.err_ctxt().report_region_errors(external_impl, &errors))); + } + + Ok(()) +} + +/// Checks a bunch of different properties of the impl/trait methods for +/// compatibility, such as asyncness, number of argument, self receiver kind, +/// and number of early- and late-bound generics. +fn check_is_structurally_compatible<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + declaration: DefId, + eii_name: Symbol, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + check_no_generics(tcx, external_impl, declaration, eii_name, eii_attr_span)?; + compare_number_of_method_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?; + check_region_bounds_on_impl_item(tcx, external_impl, declaration, eii_attr_span)?; + Ok(()) +} + +fn check_no_generics<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + _declaration: DefId, + eii_name: Symbol, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + let generics = tcx.generics_of(external_impl); + if generics.own_requires_monomorphization() { + tcx.dcx().emit_err(EiiWithGenerics { + span: tcx.def_span(external_impl), + attr: eii_attr_span, + eii_name, + }); + } + + Ok(()) +} + +fn compare_number_of_method_arguments<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + declaration: DefId, + eii_name: Symbol, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + let external_impl_fty = tcx.fn_sig(external_impl); + let declaration_fty = tcx.fn_sig(declaration); + let declaration_number_args = declaration_fty.skip_binder().inputs().skip_binder().len(); + let external_impl_number_args = external_impl_fty.skip_binder().inputs().skip_binder().len(); + let external_impl_name = tcx.item_name(external_impl.to_def_id()); + + if declaration_number_args != external_impl_number_args { + let declaration_span = declaration + .as_local() + .and_then(|def_id| { + let declaration_sig = get_declaration_sig(tcx, def_id).expect("foreign item sig"); + let pos = declaration_number_args.saturating_sub(1); + declaration_sig.decl.inputs.get(pos).map(|arg| { + if pos == 0 { + arg.span + } else { + arg.span.with_lo(declaration_sig.decl.inputs[0].span.lo()) + } + }) + }) + .or_else(|| tcx.hir_span_if_local(declaration)) + .unwrap_or_else(|| tcx.def_span(declaration)); + + let (_, external_impl_sig, _, _) = &tcx.hir_expect_item(external_impl).expect_fn(); + let pos = external_impl_number_args.saturating_sub(1); + let impl_span = external_impl_sig + .decl + .inputs + .get(pos) + .map(|arg| { + if pos == 0 { + arg.span + } else { + arg.span.with_lo(external_impl_sig.decl.inputs[0].span.lo()) + } + }) + .unwrap_or_else(|| tcx.def_span(external_impl)); + + let mut err = struct_span_code_err!( + tcx.dcx(), + impl_span, + E0805, + "`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}", + potentially_plural_count(external_impl_number_args, "parameter"), + declaration_number_args + ); + + // if let Some(declaration_span) = declaration_span { + err.span_label( + declaration_span, + format!("requires {}", potentially_plural_count(declaration_number_args, "parameter")), + ); + // } + + err.span_label( + impl_span, + format!( + "expected {}, found {}", + potentially_plural_count(declaration_number_args, "parameter"), + external_impl_number_args + ), + ); + + err.span_label(eii_attr_span, format!("required because of this attribute")); + + return Err(err.emit()); + } + + Ok(()) +} + +fn check_region_bounds_on_impl_item<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + declaration: DefId, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + let external_impl_generics = tcx.generics_of(external_impl.to_def_id()); + let external_impl_params = external_impl_generics.own_counts().lifetimes; + + let declaration_generics = tcx.generics_of(declaration); + let declaration_params = declaration_generics.own_counts().lifetimes; + + debug!(?declaration_generics, ?external_impl_generics); + + // Must have same number of early-bound lifetime parameters. + // Unfortunately, if the user screws up the bounds, then this + // will change classification between early and late. E.g., + // if in trait we have `<'a,'b:'a>`, and in impl we just have + // `<'a,'b>`, then we have 2 early-bound lifetime parameters + // in trait but 0 in the impl. But if we report "expected 2 + // but found 0" it's confusing, because it looks like there + // are zero. Since I don't quite know how to phrase things at + // the moment, give a kind of vague error message. + if declaration_params != external_impl_params { + let span = tcx + .hir_get_generics(external_impl) + .expect("expected impl item to have generics or else we can't compare them") + .span; + + let mut generics_span = None; + let mut bounds_span = vec![]; + let mut where_span = None; + + if let Some(declaration_node) = tcx.hir_get_if_local(declaration) + && let Some(declaration_generics) = declaration_node.generics() + { + generics_span = Some(declaration_generics.span); + // FIXME: we could potentially look at the impl's bounds to not point at bounds that + // *are* present in the impl. + for p in declaration_generics.predicates { + if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind { + for b in pred.bounds { + if let hir::GenericBound::Outlives(lt) = b { + bounds_span.push(lt.ident.span); + } + } + } + } + if let Some(implementation_generics) = tcx.hir_get_generics(external_impl) { + let mut impl_bounds = 0; + for p in implementation_generics.predicates { + if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind { + for b in pred.bounds { + if let hir::GenericBound::Outlives(_) = b { + impl_bounds += 1; + } + } + } + } + if impl_bounds == bounds_span.len() { + bounds_span = vec![]; + } else if implementation_generics.has_where_clause_predicates { + where_span = Some(implementation_generics.where_clause_span); + } + } + } + let mut diag = tcx.dcx().create_err(LifetimesOrBoundsMismatchOnEii { + span, + ident: tcx.item_name(external_impl.to_def_id()), + generics_span, + bounds_span, + where_span, + }); + + diag.span_label(eii_attr_span, format!("required because of this attribute")); + return Err(diag.emit()); + } + + Ok(()) +} + +fn report_eii_mismatch<'tcx>( + infcx: &InferCtxt<'tcx>, + mut cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + terr: TypeError<'tcx>, + (declaration_did, declaration_sig): (DefId, ty::FnSig<'tcx>), + (external_impl_did, external_impl_sig): (LocalDefId, ty::FnSig<'tcx>), + eii_attr_span: Span, + eii_name: Symbol, +) -> ErrorGuaranteed { + let tcx = infcx.tcx; + let (impl_err_span, trait_err_span, external_impl_name) = + extract_spans_for_error_reporting(infcx, terr, &cause, declaration_did, external_impl_did); + + let mut diag = struct_span_code_err!( + tcx.dcx(), + impl_err_span, + E0805, + "function `{}` has a type that is incompatible with the declaration of `#[{eii_name}]`", + external_impl_name + ); + + diag.span_note(eii_attr_span, "expected this because of this attribute"); + + match &terr { + TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => { + if declaration_sig.inputs().len() == *i { + // Suggestion to change output type. We do not suggest in `async` functions + // to avoid complex logic or incorrect output. + if let ItemKind::Fn { sig, .. } = &tcx.hir_expect_item(external_impl_did).kind + && !sig.header.asyncness.is_async() + { + let msg = "change the output type to match the declaration"; + let ap = Applicability::MachineApplicable; + match sig.decl.output { + hir::FnRetTy::DefaultReturn(sp) => { + let sugg = format!(" -> {}", declaration_sig.output()); + diag.span_suggestion_verbose(sp, msg, sugg, ap); + } + hir::FnRetTy::Return(hir_ty) => { + let sugg = declaration_sig.output(); + diag.span_suggestion_verbose(hir_ty.span, msg, sugg, ap); + } + }; + }; + } else if let Some(trait_ty) = declaration_sig.inputs().get(*i) { + diag.span_suggestion_verbose( + impl_err_span, + "change the parameter type to match the declaration", + trait_ty, + Applicability::MachineApplicable, + ); + } + } + _ => {} + } + + cause.span = impl_err_span; + infcx.err_ctxt().note_type_err( + &mut diag, + &cause, + trait_err_span.map(|sp| (sp, Cow::from("type in declaration"), false)), + Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound { + expected: ty::Binder::dummy(declaration_sig), + found: ty::Binder::dummy(external_impl_sig), + }))), + terr, + false, + None, + ); + + diag.emit() +} + +#[instrument(level = "debug", skip(infcx))] +fn extract_spans_for_error_reporting<'tcx>( + infcx: &infer::InferCtxt<'tcx>, + terr: TypeError<'_>, + cause: &ObligationCause<'tcx>, + declaration: DefId, + external_impl: LocalDefId, +) -> (Span, Option, Ident) { + let tcx = infcx.tcx; + let (mut external_impl_args, external_impl_name) = { + let item = tcx.hir_expect_item(external_impl); + let (ident, sig, _, _) = item.expect_fn(); + (sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())), ident) + }; + + let declaration_args = declaration.as_local().map(|def_id| { + if let Some(sig) = get_declaration_sig(tcx, def_id) { + sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) + } else { + panic!("expected {def_id:?} to be a foreign function"); + } + }); + + match terr { + TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => ( + external_impl_args.nth(i).unwrap(), + declaration_args.and_then(|mut args| args.nth(i)), + external_impl_name, + ), + _ => ( + cause.span, + tcx.hir_span_if_local(declaration).or_else(|| Some(tcx.def_span(declaration))), + external_impl_name, + ), + } +} + +fn get_declaration_sig<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<&'tcx FnSig<'tcx>> { + let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id); + tcx.hir_fn_sig_by_hir_id(hir_id) +} diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index f1c84a14de30..d6ae14a7acfe 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -64,6 +64,7 @@ pub mod always_applicable; mod check; +mod compare_eii; mod compare_impl_item; mod entry; pub mod intrinsic; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 0e8859facf58..97097f4a0bfc 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; -use rustc_hir::attrs::AttributeKind; +use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; @@ -39,6 +39,7 @@ use tracing::{debug, instrument}; use {rustc_ast as ast, rustc_hir as hir}; +use super::compare_eii::compare_eii_function_types; use crate::autoderef::Autoderef; use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params}; use crate::errors::InvalidReceiverTyHint; @@ -1171,6 +1172,31 @@ fn check_item_fn( decl: &hir::FnDecl<'_>, ) -> Result<(), ErrorGuaranteed> { enter_wf_checking_ctxt(tcx, def_id, |wfcx| { + // does the function have an EiiImpl attribute? that contains the defid of a *macro* + // that was used to mark the implementation. This is a two step process. + for EiiImpl { eii_macro, span, .. } in + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpls(impls) => impls) + .into_iter() + .flatten() + { + // we expect this macro to have the `EiiMacroFor` attribute, that points to a function + // signature that we'd like to compare the function we're currently checking with + if let Some(eii_extern_target) = find_attr!(tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl {eii_extern_target, ..}) => *eii_extern_target) + { + let _ = compare_eii_function_types( + tcx, + def_id, + eii_extern_target, + tcx.item_name(*eii_macro), + *span, + ); + } else { + panic!( + "EII impl macro {eii_macro:?} did not have an eii extern target attribute pointing to a foreign function" + ) + } + } + let sig = tcx.fn_sig(def_id).instantiate_identity(); check_fn_or_method(wfcx, sig, decl, def_id); Ok(()) diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 34ad4e720eb5..865abdbd32c2 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1697,3 +1697,28 @@ pub(crate) struct AsyncDropWithoutSyncDrop { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_lifetimes_or_bounds_mismatch_on_eii)] +pub(crate) struct LifetimesOrBoundsMismatchOnEii { + #[primary_span] + #[label] + pub span: Span, + #[label(hir_analysis_generics_label)] + pub generics_span: Option, + #[label(hir_analysis_where_label)] + pub where_span: Option, + #[label(hir_analysis_bounds_label)] + pub bounds_span: Vec, + pub ident: Symbol, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_eii_with_generics)] +pub(crate) struct EiiWithGenerics { + #[primary_span] + pub span: Span, + #[label] + pub attr: Span, + pub eii_name: Symbol, +} diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 0c7bddf60d97..c064313f67b2 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -420,6 +420,13 @@ pub enum ObligationCauseCode<'tcx> { /// Only reachable if the `unsized_fn_params` feature is used. Unsized function arguments must /// be place expressions because we can't store them in MIR locals as temporaries. UnsizedNonPlaceExpr(Span), + + /// Error derived when checking an impl item is compatible with + /// its corresponding trait item's definition + CompareEii { + external_impl: LocalDefId, + declaration: DefId, + }, } /// Whether a value can be extracted into a const. diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index fd845e31c909..d14ff2c3b7e2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3843,6 +3843,9 @@ pub(super) fn note_obligation_cause_code( "unsized values must be place expressions and cannot be put in temporaries", ); } + ObligationCauseCode::CompareEii { .. } => { + panic!("trait bounds on EII not yet supported ") + } } } From 230ad7f639c5d453eb743cd2b94b1345cb1cab78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 12 Sep 2025 11:21:59 -0700 Subject: [PATCH 551/585] fix problems with type checking --- .../src/check/compare_eii.rs | 317 +++++++++--------- .../src/check/compare_impl_item.rs | 81 +++-- .../rustc_hir_analysis/src/check/wfcheck.rs | 52 +-- compiler/rustc_hir_analysis/src/errors.rs | 2 +- 4 files changed, 250 insertions(+), 202 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 06b7f4952957..609f29103fdd 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -1,3 +1,8 @@ +//! This module is very similar to `compare_impl_item`. +//! Most logic is taken from there, +//! since in a very similar way we're comparing some declaration of a signature to an implementation. +//! The major difference is that we don't bother with self types, since for EIIs we're comparing freestanding item. + use std::borrow::Cow; use std::iter; @@ -8,17 +13,20 @@ use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, TyCtxt, TypingMode}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; -use rustc_trait_selection::traits::ObligationCtxt; +use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::{debug, instrument}; use super::potentially_plural_count; +use crate::check::compare_impl_item::{ + CheckNumberOfEarlyBoundRegionsError, check_number_of_early_bound_regions, +}; use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii}; -/// checks whether the signature of some `external_impl`, matches +/// Checks whether the signature of some `external_impl`, matches /// the signature of `declaration`, which it is supposed to be compatible /// with in order to implement the item. pub(crate) fn compare_eii_function_types<'tcx>( @@ -43,22 +51,22 @@ pub(crate) fn compare_eii_function_types<'tcx>( let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); - // We now need to check that the signature of the impl method is - // compatible with that of the trait method. We do this by + // We now need to check that the signature of the implementation is + // compatible with that of the declaration. We do this by // checking that `impl_fty <: trait_fty`. // - // FIXME: We manually instantiate the trait method here as we need + // FIXME: We manually instantiate the declaration here as we need // to manually compute its implied bounds. Otherwise this could just // be ocx.sub(impl_sig, trait_sig). - let wf_tys = FxIndexSet::default(); + let mut wf_tys = FxIndexSet::default(); let norm_cause = ObligationCause::misc(external_impl_span, external_impl); let declaration_sig = tcx.fn_sig(declaration).instantiate_identity(); - let declaration_sig = infcx.enter_forall_and_leak_universe(declaration_sig); - let declaration_sig = ocx.normalize(&norm_cause, param_env, declaration_sig); + let declaration_sig = tcx.liberate_late_bound_regions(external_impl.into(), declaration_sig); + debug!(?declaration_sig); - let external_impl_sig = infcx.instantiate_binder_with_fresh_vars( + let unnormalized_external_impl_sig = infcx.instantiate_binder_with_fresh_vars( external_impl_span, infer::BoundRegionConversionTime::HigherRankedType, tcx.fn_sig(external_impl).instantiate( @@ -66,10 +74,20 @@ pub(crate) fn compare_eii_function_types<'tcx>( infcx.fresh_args_for_item(external_impl_span, external_impl.to_def_id()), ), ); - let external_impl_sig = ocx.normalize(&norm_cause, param_env, external_impl_sig); + let external_impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_external_impl_sig); debug!(?external_impl_sig); - // FIXME: We'd want to keep more accurate spans than "the method signature" when + // Next, add all inputs and output as well-formed tys. Importantly, + // we have to do this before normalization, since the normalized ty may + // not contain the input parameters. See issue #87748. + wf_tys.extend(declaration_sig.inputs_and_output.iter()); + let declaration_sig = ocx.normalize(&norm_cause, param_env, declaration_sig); + // We also have to add the normalized declaration + // as we don't normalize during implied bounds computation. + wf_tys.extend(external_impl_sig.inputs_and_output.iter()); + + // FIXME: Copied over from compare impl items, same issue: + // We'd want to keep more accurate spans than "the method signature" when // processing the comparison between the trait and impl fn, but we sadly lose them // and point at the whole signature when a trait bound or specific input or output // type would be more appropriate. In other places we have a `Vec` @@ -93,6 +111,17 @@ pub(crate) fn compare_eii_function_types<'tcx>( return Err(emitted); } + if !(declaration_sig, external_impl_sig).references_error() { + for ty in unnormalized_external_impl_sig.inputs_and_output { + ocx.register_obligation(traits::Obligation::new( + infcx.tcx, + cause.clone(), + param_env, + ty::ClauseKind::WellFormed(ty.into()), + )); + } + } + // Check that all obligations are satisfied by the implementation's // version. let errors = ocx.evaluate_obligations_error_on_ambiguity(); @@ -116,6 +145,8 @@ pub(crate) fn compare_eii_function_types<'tcx>( /// Checks a bunch of different properties of the impl/trait methods for /// compatibility, such as asyncness, number of argument, self receiver kind, /// and number of early- and late-bound generics. +/// +/// Corresponds to `check_method_is_structurally_compatible` for impl method compatibility checks. fn check_is_structurally_compatible<'tcx>( tcx: TyCtxt<'tcx>, external_impl: LocalDefId, @@ -124,11 +155,12 @@ fn check_is_structurally_compatible<'tcx>( eii_attr_span: Span, ) -> Result<(), ErrorGuaranteed> { check_no_generics(tcx, external_impl, declaration, eii_name, eii_attr_span)?; - compare_number_of_method_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?; - check_region_bounds_on_impl_item(tcx, external_impl, declaration, eii_attr_span)?; + check_number_of_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?; + check_early_region_bounds(tcx, external_impl, declaration, eii_attr_span)?; Ok(()) } +/// externally implementable items can't have generics fn check_no_generics<'tcx>( tcx: TyCtxt<'tcx>, external_impl: LocalDefId, @@ -148,85 +180,7 @@ fn check_no_generics<'tcx>( Ok(()) } -fn compare_number_of_method_arguments<'tcx>( - tcx: TyCtxt<'tcx>, - external_impl: LocalDefId, - declaration: DefId, - eii_name: Symbol, - eii_attr_span: Span, -) -> Result<(), ErrorGuaranteed> { - let external_impl_fty = tcx.fn_sig(external_impl); - let declaration_fty = tcx.fn_sig(declaration); - let declaration_number_args = declaration_fty.skip_binder().inputs().skip_binder().len(); - let external_impl_number_args = external_impl_fty.skip_binder().inputs().skip_binder().len(); - let external_impl_name = tcx.item_name(external_impl.to_def_id()); - - if declaration_number_args != external_impl_number_args { - let declaration_span = declaration - .as_local() - .and_then(|def_id| { - let declaration_sig = get_declaration_sig(tcx, def_id).expect("foreign item sig"); - let pos = declaration_number_args.saturating_sub(1); - declaration_sig.decl.inputs.get(pos).map(|arg| { - if pos == 0 { - arg.span - } else { - arg.span.with_lo(declaration_sig.decl.inputs[0].span.lo()) - } - }) - }) - .or_else(|| tcx.hir_span_if_local(declaration)) - .unwrap_or_else(|| tcx.def_span(declaration)); - - let (_, external_impl_sig, _, _) = &tcx.hir_expect_item(external_impl).expect_fn(); - let pos = external_impl_number_args.saturating_sub(1); - let impl_span = external_impl_sig - .decl - .inputs - .get(pos) - .map(|arg| { - if pos == 0 { - arg.span - } else { - arg.span.with_lo(external_impl_sig.decl.inputs[0].span.lo()) - } - }) - .unwrap_or_else(|| tcx.def_span(external_impl)); - - let mut err = struct_span_code_err!( - tcx.dcx(), - impl_span, - E0805, - "`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}", - potentially_plural_count(external_impl_number_args, "parameter"), - declaration_number_args - ); - - // if let Some(declaration_span) = declaration_span { - err.span_label( - declaration_span, - format!("requires {}", potentially_plural_count(declaration_number_args, "parameter")), - ); - // } - - err.span_label( - impl_span, - format!( - "expected {}, found {}", - potentially_plural_count(declaration_number_args, "parameter"), - external_impl_number_args - ), - ); - - err.span_label(eii_attr_span, format!("required because of this attribute")); - - return Err(err.emit()); - } - - Ok(()) -} - -fn check_region_bounds_on_impl_item<'tcx>( +fn check_early_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, external_impl: LocalDefId, declaration: DefId, @@ -238,73 +192,128 @@ fn check_region_bounds_on_impl_item<'tcx>( let declaration_generics = tcx.generics_of(declaration); let declaration_params = declaration_generics.own_counts().lifetimes; - debug!(?declaration_generics, ?external_impl_generics); + let Err(CheckNumberOfEarlyBoundRegionsError { span, generics_span, bounds_span, where_span }) = + check_number_of_early_bound_regions( + tcx, + external_impl, + declaration, + external_impl_generics, + external_impl_params, + declaration_generics, + declaration_params, + ) + else { + return Ok(()); + }; - // Must have same number of early-bound lifetime parameters. - // Unfortunately, if the user screws up the bounds, then this - // will change classification between early and late. E.g., - // if in trait we have `<'a,'b:'a>`, and in impl we just have - // `<'a,'b>`, then we have 2 early-bound lifetime parameters - // in trait but 0 in the impl. But if we report "expected 2 - // but found 0" it's confusing, because it looks like there - // are zero. Since I don't quite know how to phrase things at - // the moment, give a kind of vague error message. - if declaration_params != external_impl_params { - let span = tcx - .hir_get_generics(external_impl) - .expect("expected impl item to have generics or else we can't compare them") - .span; + let mut diag = tcx.dcx().create_err(LifetimesOrBoundsMismatchOnEii { + span, + ident: tcx.item_name(external_impl.to_def_id()), + generics_span, + bounds_span, + where_span, + }); - let mut generics_span = None; - let mut bounds_span = vec![]; - let mut where_span = None; + diag.span_label(eii_attr_span, format!("required because of this attribute")); + return Err(diag.emit()); +} - if let Some(declaration_node) = tcx.hir_get_if_local(declaration) - && let Some(declaration_generics) = declaration_node.generics() - { - generics_span = Some(declaration_generics.span); - // FIXME: we could potentially look at the impl's bounds to not point at bounds that - // *are* present in the impl. - for p in declaration_generics.predicates { - if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind { - for b in pred.bounds { - if let hir::GenericBound::Outlives(lt) = b { - bounds_span.push(lt.ident.span); - } - } - } - } - if let Some(implementation_generics) = tcx.hir_get_generics(external_impl) { - let mut impl_bounds = 0; - for p in implementation_generics.predicates { - if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind { - for b in pred.bounds { - if let hir::GenericBound::Outlives(_) = b { - impl_bounds += 1; - } - } - } - } - if impl_bounds == bounds_span.len() { - bounds_span = vec![]; - } else if implementation_generics.has_where_clause_predicates { - where_span = Some(implementation_generics.where_clause_span); - } - } - } - let mut diag = tcx.dcx().create_err(LifetimesOrBoundsMismatchOnEii { - span, - ident: tcx.item_name(external_impl.to_def_id()), - generics_span, - bounds_span, - where_span, - }); +fn check_number_of_arguments<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + declaration: DefId, + eii_name: Symbol, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + let external_impl_fty = tcx.fn_sig(external_impl); + let declaration_fty = tcx.fn_sig(declaration); + let declaration_number_args = declaration_fty.skip_binder().inputs().skip_binder().len(); + let external_impl_number_args = external_impl_fty.skip_binder().inputs().skip_binder().len(); - diag.span_label(eii_attr_span, format!("required because of this attribute")); - return Err(diag.emit()); + // if the number of args are equal, we're trivially done + if declaration_number_args == external_impl_number_args { + Ok(()) + } else { + Err(report_number_of_arguments_mismatch( + tcx, + external_impl, + declaration, + eii_name, + eii_attr_span, + declaration_number_args, + external_impl_number_args, + )) } +} - Ok(()) +fn report_number_of_arguments_mismatch<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + declaration: DefId, + eii_name: Symbol, + eii_attr_span: Span, + declaration_number_args: usize, + external_impl_number_args: usize, +) -> ErrorGuaranteed { + let external_impl_name = tcx.item_name(external_impl.to_def_id()); + + let declaration_span = declaration + .as_local() + .and_then(|def_id| { + let declaration_sig = get_declaration_sig(tcx, def_id).expect("foreign item sig"); + let pos = declaration_number_args.saturating_sub(1); + declaration_sig.decl.inputs.get(pos).map(|arg| { + if pos == 0 { + arg.span + } else { + arg.span.with_lo(declaration_sig.decl.inputs[0].span.lo()) + } + }) + }) + .or_else(|| tcx.hir_span_if_local(declaration)) + .unwrap_or_else(|| tcx.def_span(declaration)); + + let (_, external_impl_sig, _, _) = &tcx.hir_expect_item(external_impl).expect_fn(); + let pos = external_impl_number_args.saturating_sub(1); + let impl_span = external_impl_sig + .decl + .inputs + .get(pos) + .map(|arg| { + if pos == 0 { + arg.span + } else { + arg.span.with_lo(external_impl_sig.decl.inputs[0].span.lo()) + } + }) + .unwrap_or_else(|| tcx.def_span(external_impl)); + + let mut err = struct_span_code_err!( + tcx.dcx(), + impl_span, + E0805, + "`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}", + potentially_plural_count(external_impl_number_args, "parameter"), + declaration_number_args + ); + + err.span_label( + declaration_span, + format!("requires {}", potentially_plural_count(declaration_number_args, "parameter")), + ); + + err.span_label( + impl_span, + format!( + "expected {}, found {}", + potentially_plural_count(declaration_number_args, "parameter"), + external_impl_number_args + ), + ); + + err.span_label(eii_attr_span, format!("required because of this attribute")); + + err.emit() } fn report_eii_mismatch<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index c18faa785b16..b09e03941725 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -14,8 +14,9 @@ use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ - self, BottomUpFolder, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast, + self, BottomUpFolder, GenericArgs, GenericParamDefKind, Generics, Ty, TyCtxt, TypeFoldable, + TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, + Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_span::{DUMMY_SP, Span}; @@ -352,6 +353,7 @@ fn compare_method_predicate_entailment<'tcx>( // type would be more appropriate. In other places we have a `Vec` // corresponding to their `Vec`, but we don't have that here. // Fixing this would improve the output of test `issue-83765.rs`. + // There's the same issue in compare_eii code. let result = ocx.sup(&cause, param_env, trait_sig, impl_sig); if let Err(terr) = result { @@ -1093,6 +1095,55 @@ fn check_region_bounds_on_impl_item<'tcx>( let trait_generics = tcx.generics_of(trait_m.def_id); let trait_params = trait_generics.own_counts().lifetimes; + let Err(CheckNumberOfEarlyBoundRegionsError { span, generics_span, bounds_span, where_span }) = + check_number_of_early_bound_regions( + tcx, + impl_m.def_id.expect_local(), + trait_m.def_id, + impl_generics, + impl_params, + trait_generics, + trait_params, + ) + else { + return Ok(()); + }; + + if !delay && let Some(guar) = check_region_late_boundedness(tcx, impl_m, trait_m) { + return Err(guar); + } + + let reported = tcx + .dcx() + .create_err(LifetimesOrBoundsMismatchOnTrait { + span, + item_kind: impl_m.descr(), + ident: impl_m.ident(tcx), + generics_span, + bounds_span, + where_span, + }) + .emit_unless_delay(delay); + + Err(reported) +} + +pub(super) struct CheckNumberOfEarlyBoundRegionsError { + pub(super) span: Span, + pub(super) generics_span: Span, + pub(super) bounds_span: Vec, + pub(super) where_span: Option, +} + +pub(super) fn check_number_of_early_bound_regions<'tcx>( + tcx: TyCtxt<'tcx>, + impl_def_id: LocalDefId, + trait_def_id: DefId, + impl_generics: &Generics, + impl_params: usize, + trait_generics: &Generics, + trait_params: usize, +) -> Result<(), CheckNumberOfEarlyBoundRegionsError> { debug!(?trait_generics, ?impl_generics); // Must have same number of early-bound lifetime parameters. @@ -1108,20 +1159,16 @@ fn check_region_bounds_on_impl_item<'tcx>( return Ok(()); } - if !delay && let Some(guar) = check_region_late_boundedness(tcx, impl_m, trait_m) { - return Err(guar); - } - let span = tcx - .hir_get_generics(impl_m.def_id.expect_local()) + .hir_get_generics(impl_def_id) .expect("expected impl item to have generics or else we can't compare them") .span; - let mut generics_span = tcx.def_span(trait_m.def_id); + let mut generics_span = tcx.def_span(trait_def_id); let mut bounds_span = vec![]; let mut where_span = None; - if let Some(trait_node) = tcx.hir_get_if_local(trait_m.def_id) + if let Some(trait_node) = tcx.hir_get_if_local(trait_def_id) && let Some(trait_generics) = trait_node.generics() { generics_span = trait_generics.span; @@ -1146,7 +1193,7 @@ fn check_region_bounds_on_impl_item<'tcx>( _ => {} } } - if let Some(impl_node) = tcx.hir_get_if_local(impl_m.def_id) + if let Some(impl_node) = tcx.hir_get_if_local(impl_def_id.into()) && let Some(impl_generics) = impl_node.generics() { let mut impl_bounds = 0; @@ -1177,19 +1224,7 @@ fn check_region_bounds_on_impl_item<'tcx>( } } - let reported = tcx - .dcx() - .create_err(LifetimesOrBoundsMismatchOnTrait { - span, - item_kind: impl_m.descr(), - ident: impl_m.ident(tcx), - generics_span, - bounds_span, - where_span, - }) - .emit_unless_delay(delay); - - Err(reported) + Err(CheckNumberOfEarlyBoundRegionsError { span, generics_span, bounds_span, where_span }) } #[allow(unused)] diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 97097f4a0bfc..12c5dc8cdf20 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1172,30 +1172,7 @@ fn check_item_fn( decl: &hir::FnDecl<'_>, ) -> Result<(), ErrorGuaranteed> { enter_wf_checking_ctxt(tcx, def_id, |wfcx| { - // does the function have an EiiImpl attribute? that contains the defid of a *macro* - // that was used to mark the implementation. This is a two step process. - for EiiImpl { eii_macro, span, .. } in - find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpls(impls) => impls) - .into_iter() - .flatten() - { - // we expect this macro to have the `EiiMacroFor` attribute, that points to a function - // signature that we'd like to compare the function we're currently checking with - if let Some(eii_extern_target) = find_attr!(tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl {eii_extern_target, ..}) => *eii_extern_target) - { - let _ = compare_eii_function_types( - tcx, - def_id, - eii_extern_target, - tcx.item_name(*eii_macro), - *span, - ); - } else { - panic!( - "EII impl macro {eii_macro:?} did not have an eii extern target attribute pointing to a foreign function" - ) - } - } + check_eiis(tcx, def_id); let sig = tcx.fn_sig(def_id).instantiate_identity(); check_fn_or_method(wfcx, sig, decl, def_id); @@ -1203,6 +1180,33 @@ fn check_item_fn( }) } +fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) { + // does the function have an EiiImpl attribute? that contains the defid of a *macro* + // that was used to mark the implementation. This is a two step process. + for EiiImpl { eii_macro, span, .. } in + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpls(impls) => impls) + .into_iter() + .flatten() + { + // we expect this macro to have the `EiiMacroFor` attribute, that points to a function + // signature that we'd like to compare the function we're currently checking with + if let Some(eii_extern_target) = find_attr!(tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl {eii_extern_target, ..}) => *eii_extern_target) + { + let _ = compare_eii_function_types( + tcx, + def_id, + eii_extern_target, + tcx.item_name(*eii_macro), + *span, + ); + } else { + panic!( + "EII impl macro {eii_macro:?} did not have an eii extern target attribute pointing to a foreign function" + ) + } + } +} + #[instrument(level = "debug", skip(tcx))] pub(crate) fn check_static_item<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 865abdbd32c2..8e17a4962520 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1705,7 +1705,7 @@ pub(crate) struct LifetimesOrBoundsMismatchOnEii { #[label] pub span: Span, #[label(hir_analysis_generics_label)] - pub generics_span: Option, + pub generics_span: Span, #[label(hir_analysis_where_label)] pub where_span: Option, #[label(hir_analysis_bounds_label)] From a4abfad99bc742f424253798af5a311286ae21d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 21 Aug 2025 13:30:55 +0200 Subject: [PATCH 552/585] EII new error code --- .../src/error_codes/E0806.md | 68 +++++++++++++++++++ compiler/rustc_error_codes/src/lib.rs | 1 + .../src/check/compare_eii.rs | 6 +- tests/ui/error-codes/E0806.rs | 12 ++++ tests/ui/error-codes/E0806.stderr | 14 ++++ 5 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0806.md create mode 100644 tests/ui/error-codes/E0806.rs create mode 100644 tests/ui/error-codes/E0806.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0806.md b/compiler/rustc_error_codes/src/error_codes/E0806.md new file mode 100644 index 000000000000..9de1bb5891fa --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0806.md @@ -0,0 +1,68 @@ +An externally implementable item is not compatible with its declaration. + +Erroneous code example: + +```rust,edition2021,compile_fail,E0806 +#![feature(eii)] + +#[eii(foo)] +fn x(); + +#[foo] +fn y(a: u64) -> u64 { +//~^ ERROR E0806 + a +} + + +fn main() {} +``` + +The error here is caused by the fact that `y` implements the +externally implementable item `foo`. +It can only do so if the signature of the implementation `y` matches +that of the declaration of `foo`. +So, to fix this, `y`'s signature must be changed to match that of `x`: + +```rust,edition2021 +#![feature(eii)] + +#[eii(foo)] +fn x(); + +#[foo] +fn y() {} + + +fn main() {} +``` + +One common way this can be triggered is by using the wrong +signature for `#[panic_handler]`. +The signature is provided by `core`. + +```rust,edition2021,ignore +#![no_std] + +#[panic_handler] +fn on_panic() -> ! { +//~^ ERROR E0806 + + loop {} +} + +fn main() {} +``` + +Should be: + +```rust,edition2021,ignore +#![no_std] + +#[panic_handler] +fn on_panic(info: &core::panic::PanicInfo<'_>) -> ! { + loop {} +} + +fn main() {} +``` diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 6acd0342d2bb..65f1780885ad 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -543,6 +543,7 @@ macro_rules! error_codes { 0803, 0804, 0805, +0806, ); ) } diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 609f29103fdd..4e7f47a92108 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -7,7 +7,7 @@ use std::iter; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{Applicability, E0805, struct_span_code_err}; +use rustc_errors::{Applicability, E0806, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, FnSig, HirId, ItemKind}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; @@ -291,7 +291,7 @@ fn report_number_of_arguments_mismatch<'tcx>( let mut err = struct_span_code_err!( tcx.dcx(), impl_span, - E0805, + E0806, "`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}", potentially_plural_count(external_impl_number_args, "parameter"), declaration_number_args @@ -333,7 +333,7 @@ fn report_eii_mismatch<'tcx>( let mut diag = struct_span_code_err!( tcx.dcx(), impl_err_span, - E0805, + E0806, "function `{}` has a type that is incompatible with the declaration of `#[{eii_name}]`", external_impl_name ); diff --git a/tests/ui/error-codes/E0806.rs b/tests/ui/error-codes/E0806.rs new file mode 100644 index 000000000000..168c7120fc17 --- /dev/null +++ b/tests/ui/error-codes/E0806.rs @@ -0,0 +1,12 @@ +#![feature(eii)] + +#[eii(foo)] +fn x(); + +#[foo] +fn y(a: u64) -> u64 { + //~^ ERROR E0806 + a +} + +fn main() {} diff --git a/tests/ui/error-codes/E0806.stderr b/tests/ui/error-codes/E0806.stderr new file mode 100644 index 000000000000..ab6ba45185df --- /dev/null +++ b/tests/ui/error-codes/E0806.stderr @@ -0,0 +1,14 @@ +error[E0806]: `y` has 1 parameter but #[foo] requires it to have 0 + --> $DIR/E0806.rs:7:9 + | +LL | fn x(); + | ------- requires 0 parameters +LL | +LL | #[foo] + | ------ required because of this attribute +LL | fn y(a: u64) -> u64 { + | ^^^ expected 0 parameters, found 1 + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0806`. From a63f10a827bd58c953b97c5d3e9a04173f89127a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 21 Aug 2025 13:30:55 +0200 Subject: [PATCH 553/585] EII liveness analysis From 9bd6b7ff7239f55a859552ce69f19bcde475f5ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 29 Aug 2025 08:37:44 +0200 Subject: [PATCH 554/585] EII: generate aliases for implementations --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 8 ++++ compiler/rustc_codegen_llvm/src/llvm/mod.rs | 13 +++++- compiler/rustc_codegen_llvm/src/mono_item.rs | 27 ++++++++++++ .../rustc_codegen_ssa/src/codegen_attrs.rs | 42 +++++++++++++++++-- .../src/middle/codegen_fn_attrs.rs | 8 ++++ compiler/rustc_middle/src/mir/mono.rs | 2 +- 6 files changed, 95 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index c5cbc92ae772..8abf8b24d9d6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2583,4 +2583,12 @@ pub(crate) fn LLVMRustGetSymbols( pub(crate) fn LLVMRustSetNoSanitizeAddress(Global: &Value); pub(crate) fn LLVMRustSetNoSanitizeHWAddress(Global: &Value); + + pub(crate) fn LLVMAddAlias2<'ll>( + M: &'ll Module, + ValueTy: &Type, + AddressSpace: c_uint, + Aliasee: &Value, + Name: *const c_char, + ) -> &'ll Value; } diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 55a4b415a4e2..621004e756ec 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -6,7 +6,7 @@ use std::string::FromUtf8Error; use libc::c_uint; -use rustc_abi::{Align, Size, WrappingRange}; +use rustc_abi::{AddressSpace, Align, Size, WrappingRange}; use rustc_llvm::RustString; pub(crate) use self::CallConv::*; @@ -452,3 +452,14 @@ pub(crate) fn append_module_inline_asm<'ll>(llmod: &'ll Module, asm: &[u8]) { LLVMAppendModuleInlineAsm(llmod, asm.as_ptr(), asm.len()); } } + +/// Safe wrapper for `LLVMAddAlias2` +pub(crate) fn add_alias<'ll>( + module: &'ll Module, + ty: &Type, + address_space: AddressSpace, + aliasee: &Value, + name: &CStr, +) -> &'ll Value { + unsafe { LLVMAddAlias2(module, ty, address_space.0, aliasee, name.as_ptr()) } +} diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 4184ced74962..41cf92390b0d 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -1,3 +1,6 @@ +use std::ffi::CString; + +use rustc_abi::AddressSpace; use rustc_codegen_ssa::traits::*; use rustc_hir::attrs::Linkage; use rustc_hir::def::DefKind; @@ -7,6 +10,7 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use rustc_session::config::CrateType; +use rustc_span::Symbol; use rustc_target::spec::{Arch, RelocModel}; use tracing::debug; @@ -41,6 +45,9 @@ fn predefine_static( llvm::set_visibility(g, base::visibility_to_llvm(visibility)); self.assume_dso_local(g, false); + let attrs = self.tcx.codegen_instance_attrs(instance.def); + self.add_aliases(g, &attrs.foreign_item_symbol_aliases); + self.instances.borrow_mut().insert(instance, g); } @@ -78,11 +85,31 @@ fn predefine_fn( self.assume_dso_local(lldecl, false); + self.add_aliases(lldecl, &attrs.foreign_item_symbol_aliases); + self.instances.borrow_mut().insert(instance, lldecl); } } impl CodegenCx<'_, '_> { + fn add_aliases(&self, aliasee: &llvm::Value, aliases: &[(Symbol, Linkage, Visibility)]) { + let ty = self.get_type_of_global(aliasee); + + for (alias, linkage, visibility) in aliases { + tracing::debug!("ALIAS: {alias:?} {linkage:?} {visibility:?}"); + let lldecl = llvm::add_alias( + self.llmod, + ty, + AddressSpace::ZERO, + aliasee, + &CString::new(alias.as_str()).unwrap(), + ); + + llvm::set_visibility(lldecl, base::visibility_to_llvm(*visibility)); + llvm::set_linkage(lldecl, base::linkage_to_llvm(*linkage)); + } + } + /// Whether a definition or declaration can be assumed to be local to a group of /// libraries that form a single DSO or executable. /// Marks the local as DSO if so. diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 0ab0cb0ef88a..0c409cef298a 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -3,19 +3,22 @@ use rustc_abi::{Align, ExternAbi}; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr}; -use rustc_hir::attrs::{AttributeKind, InlineAttr, InstructionSetAttr, RtsanSetting, UsedBy}; +use rustc_hir::attrs::{ + AttributeKind, InlineAttr, InstructionSetAttr, Linkage, RtsanSetting, UsedBy, +}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items}; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs, }; +use rustc_middle::mir::mono::Visibility; use rustc_middle::query::Providers; use rustc_middle::span_bug; -use rustc_middle::ty::{self as ty, TyCtxt}; +use rustc_middle::ty::{self as ty, Instance, TyCtxt}; use rustc_session::lint; use rustc_session::parse::feature_err; -use rustc_span::{Ident, Span, sym}; +use rustc_span::{Ident, Span, Symbol, sym}; use rustc_target::spec::Os; use crate::errors; @@ -310,6 +313,39 @@ fn process_builtin_attrs( AttributeKind::ObjcSelector { methname, .. } => { codegen_fn_attrs.objc_selector = Some(*methname); } + AttributeKind::EiiImpls(impls) => { + for i in impls { + let extern_item = find_attr!( + tcx.get_all_attrs(i.eii_macro), + AttributeKind::EiiExternTarget(target) => target.eii_extern_target + ) + .expect("eii should have declaration macro with extern target attribute"); + + let symbol_name = tcx.symbol_name(Instance::mono(tcx, extern_item)); + + // this is to prevent a bug where a single crate defines both the default and explicit implementation + // for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure + // what happens, either rustc deduplicates the symbol or llvm, or it's random/order-dependent. + // However, the fact that the default one of has weak linkage isn't considered and you sometimes get that + // the default implementation is used while an explicit implementation is given. + if + // if this is a default impl + i.is_default + // iterate over all implementations *in the current crate* + // (this is ok since we generate codegen fn attrs in the local crate) + // if any of them is *not default* then don't emit the alias. + && tcx.externally_implementable_items(LOCAL_CRATE).get(&i.eii_macro).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default) + { + continue; + } + + codegen_fn_attrs.foreign_item_symbol_aliases.push(( + Symbol::intern(symbol_name.name), + if i.is_default { Linkage::LinkOnceAny } else { Linkage::External }, + Visibility::Default, + )); + } + } _ => {} } } diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 9630cfc94b43..7922cc38aaab 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -6,6 +6,7 @@ use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; +use crate::mir::mono::Visibility; use crate::ty::{InstanceKind, TyCtxt}; impl<'tcx> TyCtxt<'tcx> { @@ -62,6 +63,12 @@ pub struct CodegenFnAttrs { /// using the `#[export_name = "..."]` or `#[link_name = "..."]` attribute /// depending on if this is a function definition or foreign function. pub symbol_name: Option, + /// Defids of foreign items somewhere that this function should "satisfy". + /// i.e., if a foreign function has some symbol foo, + /// generate this function under its real name, + /// but *also* under the same name as this foreign function so that the foreign function has an implementation. + // FIXME: make "SymbolName<'tcx>" + pub foreign_item_symbol_aliases: Vec<(Symbol, Linkage, Visibility)>, /// The `#[link_ordinal = "..."]` attribute, indicating an ordinal an /// imported function has in the dynamic library. Note that this must not /// be set when `link_name` is set. This is for foreign items with the @@ -207,6 +214,7 @@ pub const fn new() -> CodegenFnAttrs { symbol_name: None, link_ordinal: None, target_features: vec![], + foreign_item_symbol_aliases: vec![], safe_target_features: false, linkage: None, import_linkage: None, diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index a499f149a42b..c7ced84a527f 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -374,7 +374,7 @@ pub struct MonoItemData { /// Visibility doesn't have any effect when linkage is internal. /// /// DSO means dynamic shared object, that is a dynamically linked executable or dylib. -#[derive(Copy, Clone, PartialEq, Debug, HashStable)] +#[derive(Copy, Clone, PartialEq, Debug, HashStable, TyEncodable, TyDecodable)] pub enum Visibility { /// Export the symbol from the DSO and apply overrides of the symbol by outside DSOs to within /// the DSO if the object file format supports this. From f7e453e2fa406d0397712ee36da34d526cb46810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 8 Sep 2025 13:24:42 -0700 Subject: [PATCH 555/585] visibility using std_internal_symbol --- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 1 + compiler/rustc_passes/src/reachable.rs | 14 +++++++++++++- compiler/rustc_resolve/src/check_unused.rs | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 0c409cef298a..6aea249d6356 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -344,6 +344,7 @@ fn process_builtin_attrs( if i.is_default { Linkage::LinkOnceAny } else { Linkage::External }, Visibility::Default, )); + codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } } _ => {} diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index acb64bc6990b..b9323e91ca83 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -184,7 +184,13 @@ fn propagate_node(&mut self, node: &Node<'tcx>, search_item: LocalDefId) { CodegenFnAttrs::EMPTY }; let is_extern = codegen_attrs.contains_extern_indicator(); - if is_extern { + // Right now, the only way to get "foreign item symbol aliases" is by being an EII-implementation. + // EII implementations will generate under their own name but also under the name of some foreign item + // (hence alias) that may be in another crate. These functions are marked as always-reachable since + // it's very hard to track whether the original foreign item was reachable. It may live in another crate + // and may be reachable from sibling crates. + let has_foreign_aliases_eii = !codegen_attrs.foreign_item_symbol_aliases.is_empty(); + if is_extern || has_foreign_aliases_eii { self.reachable_symbols.insert(search_item); } } else { @@ -429,6 +435,12 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs. || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) + // Right now, the only way to get "foreign item symbol aliases" is by being an EII-implementation. + // EII implementations will generate under their own name but also under the name of some foreign item + // (hence alias) that may be in another crate. These functions are marked as always-reachable since + // it's very hard to track whether the original foreign item was reachable. It may live in another crate + // and may be reachable from sibling crates. + || !codegen_attrs.foreign_item_symbol_aliases.is_empty() } /// See module-level doc comment above. diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 0aaea96348b5..5349cf6d7dbe 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -422,6 +422,7 @@ pub(crate) fn check_unused(&mut self, krate: &ast::Crate) { && !tcx.is_panic_runtime(cnum) && !tcx.has_global_allocator(cnum) && !tcx.has_panic_handler(cnum) + && tcx.externally_implementable_items(cnum).is_empty() }) { maybe_unused_extern_crates.insert(id, import.span); } From 3cf74cb2a4e4c00873e31954f849956d49903fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 27 Oct 2025 11:46:02 +0100 Subject: [PATCH 556/585] disable gcc for now --- tests/ui/eii/codegen_cross_crate.rs | 1 + tests/ui/eii/codegen_single_crate.rs | 1 + tests/ui/eii/default/call_default.rs | 1 + tests/ui/eii/default/call_impl.rs | 1 + tests/ui/eii/default/local_crate.rs | 1 + tests/ui/eii/default/local_crate_explicit.rs | 1 + tests/ui/eii/duplicate/duplicate1.rs | 1 + tests/ui/eii/duplicate/duplicate2.rs | 1 + tests/ui/eii/duplicate/duplicate3.rs | 1 + tests/ui/eii/privacy1.rs | 1 + 10 files changed, 10 insertions(+) diff --git a/tests/ui/eii/codegen_cross_crate.rs b/tests/ui/eii/codegen_cross_crate.rs index b5b2d940b730..ccce32e0eb3e 100644 --- a/tests/ui/eii/codegen_cross_crate.rs +++ b/tests/ui/eii/codegen_cross_crate.rs @@ -2,6 +2,7 @@ //@ check-run-results //@ aux-build: codegen2.rs //@ compile-flags: -O +//@ ignore-backends: gcc // Tests whether calling EIIs works with the declaration in another crate. #![feature(eii)] diff --git a/tests/ui/eii/codegen_single_crate.rs b/tests/ui/eii/codegen_single_crate.rs index c2d986d12c1a..4172f59b0df6 100644 --- a/tests/ui/eii/codegen_single_crate.rs +++ b/tests/ui/eii/codegen_single_crate.rs @@ -1,5 +1,6 @@ //@ run-pass //@ check-run-results +//@ ignore-backends: gcc // Tests whether calling EIIs works with the declaration in the same crate. #![feature(eii)] diff --git a/tests/ui/eii/default/call_default.rs b/tests/ui/eii/default/call_default.rs index 520863f1d3e9..3557e1cdac12 100644 --- a/tests/ui/eii/default/call_default.rs +++ b/tests/ui/eii/default/call_default.rs @@ -2,6 +2,7 @@ //@ aux-build: decl_with_default.rs //@ run-pass //@ check-run-results +//@ ignore-backends: gcc // Tests EIIs with default implementations. // When there's no explicit declaration, the default should be called from the declaring crate. #![feature(eii)] diff --git a/tests/ui/eii/default/call_impl.rs b/tests/ui/eii/default/call_impl.rs index b81e604238ec..1bb37f30f027 100644 --- a/tests/ui/eii/default/call_impl.rs +++ b/tests/ui/eii/default/call_impl.rs @@ -3,6 +3,7 @@ //@ aux-build: impl1.rs //@ run-pass //@ check-run-results +//@ ignore-backends: gcc // Tests EIIs with default implementations. // When an explicit implementation is given in one dependency, and the declaration is in another, // the explicit implementation is preferred. diff --git a/tests/ui/eii/default/local_crate.rs b/tests/ui/eii/default/local_crate.rs index 9ae471d90cbc..74e90fdc273d 100644 --- a/tests/ui/eii/default/local_crate.rs +++ b/tests/ui/eii/default/local_crate.rs @@ -1,5 +1,6 @@ //@ run-pass //@ check-run-results +//@ ignore-backends: gcc // Tests EIIs with default implementations. // In the same crate, when there's no explicit declaration, the default should be called. #![feature(eii)] diff --git a/tests/ui/eii/default/local_crate_explicit.rs b/tests/ui/eii/default/local_crate_explicit.rs index 844d1d2911af..d671d8e70c97 100644 --- a/tests/ui/eii/default/local_crate_explicit.rs +++ b/tests/ui/eii/default/local_crate_explicit.rs @@ -1,5 +1,6 @@ //@ run-pass //@ check-run-results +//@ ignore-backends: gcc // Tests EIIs with default implementations. // In the same crate, the explicit implementation should get priority. #![feature(eii)] diff --git a/tests/ui/eii/duplicate/duplicate1.rs b/tests/ui/eii/duplicate/duplicate1.rs index 921270fe3d48..5573f47472a7 100644 --- a/tests/ui/eii/duplicate/duplicate1.rs +++ b/tests/ui/eii/duplicate/duplicate1.rs @@ -1,6 +1,7 @@ //@ no-prefer-dynamic //@ aux-build: impl1.rs //@ aux-build: impl2.rs +//@ ignore-backends: gcc // tests that EIIs error properly, even if the conflicting implementations live in another crate. #![feature(eii)] diff --git a/tests/ui/eii/duplicate/duplicate2.rs b/tests/ui/eii/duplicate/duplicate2.rs index 8355b8f7bc70..d2bb1856565a 100644 --- a/tests/ui/eii/duplicate/duplicate2.rs +++ b/tests/ui/eii/duplicate/duplicate2.rs @@ -2,6 +2,7 @@ //@ aux-build: impl1.rs //@ aux-build: impl2.rs //@ aux-build: impl3.rs +//@ ignore-backends: gcc // Tests the error message when there are multiple implementations of an EII in many crates. #![feature(eii)] diff --git a/tests/ui/eii/duplicate/duplicate3.rs b/tests/ui/eii/duplicate/duplicate3.rs index b967fb8b4903..2cd51268a6fb 100644 --- a/tests/ui/eii/duplicate/duplicate3.rs +++ b/tests/ui/eii/duplicate/duplicate3.rs @@ -3,6 +3,7 @@ //@ aux-build: impl2.rs //@ aux-build: impl3.rs //@ aux-build: impl4.rs +//@ ignore-backends: gcc // Tests the error message when there are multiple implementations of an EII in many crates. #![feature(eii)] diff --git a/tests/ui/eii/privacy1.rs b/tests/ui/eii/privacy1.rs index 7dd87a5b7ce4..64b35f7a070d 100644 --- a/tests/ui/eii/privacy1.rs +++ b/tests/ui/eii/privacy1.rs @@ -1,6 +1,7 @@ //@ run-pass //@ check-run-results //@ aux-build: codegen1.rs +//@ ignore-backends: gcc // Tests whether re-exports work. #![feature(eii)] From f4fd8a063369bbadc99cffb0a646deb96c0db151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 3 Nov 2025 16:06:58 +0100 Subject: [PATCH 557/585] experiment query caching --- compiler/rustc_middle/src/query/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9b4306f656d6..676f0d82e4fb 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2759,9 +2759,10 @@ } /// Returns a list of all `externally implementable items` crate. - query externally_implementable_items(_: CrateNum) -> &'tcx FxIndexMap)> { + query externally_implementable_items(cnum: CrateNum) -> &'tcx FxIndexMap)> { arena_cache desc { "looking up the externally implementable items of a crate" } + cache_on_disk_if { *cnum == LOCAL_CRATE } separate_provide_extern } } From 52e0bfccb08b5ae9957532518221e7e748ca590c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 1 Dec 2025 17:17:06 +0100 Subject: [PATCH 558/585] rename feature gate to extern_item_impls --- compiler/rustc_error_codes/src/error_codes/E0806.md | 4 ++-- compiler/rustc_feature/src/unstable.rs | 4 ++-- compiler/rustc_span/src/symbol.rs | 2 +- library/core/src/macros/mod.rs | 4 ++-- library/core/src/prelude/v1.rs | 2 +- library/std/src/prelude/v1.rs | 2 +- tests/ui/eii/auxiliary/codegen1.rs | 2 +- tests/ui/eii/auxiliary/codegen2.rs | 2 +- tests/ui/eii/auxiliary/codegen3.rs | 2 +- tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs | 2 +- tests/ui/eii/codegen_cross_crate.rs | 2 +- tests/ui/eii/codegen_single_crate.rs | 2 +- tests/ui/eii/cross_crate.rs | 2 +- tests/ui/eii/cross_crate_wrong_ty.rs | 2 +- tests/ui/eii/default/auxiliary/decl_with_default.rs | 2 +- tests/ui/eii/default/auxiliary/impl1.rs | 2 +- tests/ui/eii/default/call_default.rs | 2 +- tests/ui/eii/default/call_impl.rs | 2 +- tests/ui/eii/default/local_crate.rs | 2 +- tests/ui/eii/default/local_crate_explicit.rs | 2 +- tests/ui/eii/duplicate/auxiliary/decl.rs | 2 +- tests/ui/eii/duplicate/auxiliary/impl1.rs | 2 +- tests/ui/eii/duplicate/auxiliary/impl2.rs | 2 +- tests/ui/eii/duplicate/auxiliary/impl3.rs | 2 +- tests/ui/eii/duplicate/auxiliary/impl4.rs | 2 +- tests/ui/eii/duplicate/duplicate1.rs | 2 +- tests/ui/eii/duplicate/duplicate2.rs | 2 +- tests/ui/eii/duplicate/duplicate3.rs | 2 +- tests/ui/eii/errors.rs | 2 +- tests/ui/eii/multiple_decls.rs | 2 +- tests/ui/eii/multiple_impls.rs | 2 +- tests/ui/eii/privacy1.rs | 2 +- tests/ui/eii/privacy2.rs | 2 +- tests/ui/eii/subtype_1.rs | 2 +- tests/ui/eii/subtype_2.rs | 2 +- tests/ui/eii/subtype_3.rs | 2 +- tests/ui/eii/subtype_4.rs | 2 +- tests/ui/eii/unsafe_impl_err.rs | 2 +- tests/ui/eii/unsafe_impl_ok.rs | 2 +- tests/ui/eii/wrong_ret_ty.rs | 2 +- tests/ui/eii/wrong_target.rs | 2 +- tests/ui/eii/wrong_ty.rs | 2 +- tests/ui/eii/wrong_ty_2.rs | 2 +- tests/ui/error-codes/E0806.rs | 2 +- ...eature-gate-eii.rs => feature-gate-extern-item-impls.rs} | 2 +- ...ate-eii.stderr => feature-gate-extern-item-impls.stderr} | 6 +++--- 46 files changed, 51 insertions(+), 51 deletions(-) rename tests/ui/feature-gates/{feature-gate-eii.rs => feature-gate-extern-item-impls.rs} (59%) rename tests/ui/feature-gates/{feature-gate-eii.stderr => feature-gate-extern-item-impls.stderr} (63%) diff --git a/compiler/rustc_error_codes/src/error_codes/E0806.md b/compiler/rustc_error_codes/src/error_codes/E0806.md index 9de1bb5891fa..e4a89b92354f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0806.md +++ b/compiler/rustc_error_codes/src/error_codes/E0806.md @@ -3,7 +3,7 @@ An externally implementable item is not compatible with its declaration. Erroneous code example: ```rust,edition2021,compile_fail,E0806 -#![feature(eii)] +#![feature(extern_item_impls)] #[eii(foo)] fn x(); @@ -25,7 +25,7 @@ that of the declaration of `foo`. So, to fix this, `y`'s signature must be changed to match that of `x`: ```rust,edition2021 -#![feature(eii)] +#![feature(extern_item_impls)] #[eii(foo)] fn x(); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1568edd275bb..fe053935f9e6 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -493,8 +493,6 @@ pub fn internal(&self, feature: Symbol) -> bool { (unstable, doc_masked, "1.21.0", Some(44027)), /// Allows features to allow target_feature to better interact with traits. (incomplete, effective_target_features, "1.91.0", Some(143352)), - /// Externally implementatble items - (unstable, extern_item_impls, "CURRENT_RUSTC_VERSION", Some(125418)), /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }` (incomplete, ergonomic_clones, "1.87.0", Some(132290)), /// Allows exhaustive pattern matching on types that contain uninhabited types. @@ -505,6 +503,8 @@ pub fn internal(&self, feature: Symbol) -> bool { (incomplete, explicit_tail_calls, "1.72.0", Some(112788)), /// Allows using `#[export_stable]` which indicates that an item is exportable. (incomplete, export_stable, "1.88.0", Some(139939)), + /// Externally implementatble items + (unstable, extern_item_impls, "CURRENT_RUSTC_VERSION", Some(125418)), /// Allows defining `extern type`s. (unstable, extern_types, "1.23.0", Some(43467)), /// Allow using 128-bit (quad precision) floating point numbers. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c609e00b8df7..8f43a31ea4b1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -933,7 +933,6 @@ eii_extern_target, eii_impl, eii_internals, - extern_item_impls, eii_shared_macro, emit, emit_enum, @@ -994,6 +993,7 @@ extern_crate_item_prelude, extern_crate_self, extern_in_paths, + extern_item_impls, extern_prelude, extern_system_varargs, extern_types, diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 68b5b2d1efc6..a12ee60277f0 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1893,7 +1893,7 @@ macro_rules! trace_macros { /// Externally Implementable Item: Defines an attribute macro that can override the item /// this is applied to. - #[unstable(feature = "eii", issue = "125418")] + #[unstable(feature = "extern_item_impls", issue = "125418")] #[rustc_builtin_macro] #[allow_internal_unstable(eii_internals, decl_macro, rustc_attrs)] pub macro eii($item:item) { @@ -1902,7 +1902,7 @@ macro_rules! trace_macros { /// Unsafely Externally Implementable Item: Defines an unsafe attribute macro that can override /// the item this is applied to. - #[unstable(feature = "eii", issue = "125418")] + #[unstable(feature = "extern_item_impls", issue = "125418")] #[rustc_builtin_macro] #[allow_internal_unstable(eii_internals, decl_macro, rustc_attrs)] pub macro unsafe_eii($item:item) { diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 3446f04a6429..977fd1926fd0 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -125,7 +125,7 @@ )] pub use crate::macros::builtin::From; -#[unstable(feature = "eii", issue = "125418")] +#[unstable(feature = "extern_item_impls", issue = "125418")] pub use crate::macros::builtin::{eii, unsafe_eii}; #[unstable(feature = "eii_internals", issue = "none")] diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 6c2f5f108f1a..63f75ea8a881 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -110,7 +110,7 @@ )] pub use core::prelude::v1::define_opaque; -#[unstable(feature = "eii", issue = "125418")] +#[unstable(feature = "extern_item_impls", issue = "125418")] pub use core::prelude::v1::{eii, unsafe_eii}; #[unstable(feature = "eii_internals", issue = "none")] diff --git a/tests/ui/eii/auxiliary/codegen1.rs b/tests/ui/eii/auxiliary/codegen1.rs index 93c5df2d41c0..41160cd1fe39 100644 --- a/tests/ui/eii/auxiliary/codegen1.rs +++ b/tests/ui/eii/auxiliary/codegen1.rs @@ -1,6 +1,6 @@ //@ no-prefer-dynamic #![crate_type = "rlib"] -#![feature(eii)] +#![feature(extern_item_impls)] #[eii(eii1)] fn decl1(x: u64); diff --git a/tests/ui/eii/auxiliary/codegen2.rs b/tests/ui/eii/auxiliary/codegen2.rs index 9545ad007c57..7e0ba5f971c3 100644 --- a/tests/ui/eii/auxiliary/codegen2.rs +++ b/tests/ui/eii/auxiliary/codegen2.rs @@ -1,6 +1,6 @@ //@ no-prefer-dynamic #![crate_type = "rlib"] -#![feature(eii)] +#![feature(extern_item_impls)] #[eii(eii1)] pub fn decl1(x: u64); diff --git a/tests/ui/eii/auxiliary/codegen3.rs b/tests/ui/eii/auxiliary/codegen3.rs index 2b882c48d829..9fb19298f09f 100644 --- a/tests/ui/eii/auxiliary/codegen3.rs +++ b/tests/ui/eii/auxiliary/codegen3.rs @@ -1,6 +1,6 @@ //@ no-prefer-dynamic #![crate_type = "rlib"] -#![feature(eii)] +#![feature(extern_item_impls)] // does have an impl but can't be called #[eii(eii1)] diff --git a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs index 3147d91bbee8..40d0222082d5 100644 --- a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs +++ b/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs @@ -1,6 +1,6 @@ //@ no-prefer-dynamic #![crate_type = "rlib"] -#![feature(eii)] +#![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] diff --git a/tests/ui/eii/codegen_cross_crate.rs b/tests/ui/eii/codegen_cross_crate.rs index ccce32e0eb3e..760c960297e0 100644 --- a/tests/ui/eii/codegen_cross_crate.rs +++ b/tests/ui/eii/codegen_cross_crate.rs @@ -4,7 +4,7 @@ //@ compile-flags: -O //@ ignore-backends: gcc // Tests whether calling EIIs works with the declaration in another crate. -#![feature(eii)] +#![feature(extern_item_impls)] extern crate codegen2 as codegen; diff --git a/tests/ui/eii/codegen_single_crate.rs b/tests/ui/eii/codegen_single_crate.rs index 4172f59b0df6..00e0abca65f3 100644 --- a/tests/ui/eii/codegen_single_crate.rs +++ b/tests/ui/eii/codegen_single_crate.rs @@ -2,7 +2,7 @@ //@ check-run-results //@ ignore-backends: gcc // Tests whether calling EIIs works with the declaration in the same crate. -#![feature(eii)] +#![feature(extern_item_impls)] #[eii] fn hello(x: u64); diff --git a/tests/ui/eii/cross_crate.rs b/tests/ui/eii/cross_crate.rs index 72f1533587bf..157d659bfd64 100644 --- a/tests/ui/eii/cross_crate.rs +++ b/tests/ui/eii/cross_crate.rs @@ -2,7 +2,7 @@ //@ check-pass //@ aux-build: cross_crate_eii_declaration.rs // Tests whether calling EIIs works with the declaration in another crate. -#![feature(eii)] +#![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] diff --git a/tests/ui/eii/cross_crate_wrong_ty.rs b/tests/ui/eii/cross_crate_wrong_ty.rs index f99b812b6c50..7ae1a5995a86 100644 --- a/tests/ui/eii/cross_crate_wrong_ty.rs +++ b/tests/ui/eii/cross_crate_wrong_ty.rs @@ -1,7 +1,7 @@ //@ compile-flags: --crate-type rlib //@ aux-build: cross_crate_eii_declaration.rs // Tests whether the type checking still works properly when the declaration is in another crate. -#![feature(eii)] +#![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] diff --git a/tests/ui/eii/default/auxiliary/decl_with_default.rs b/tests/ui/eii/default/auxiliary/decl_with_default.rs index b1811b07eb17..8d962c19c94d 100644 --- a/tests/ui/eii/default/auxiliary/decl_with_default.rs +++ b/tests/ui/eii/default/auxiliary/decl_with_default.rs @@ -1,6 +1,6 @@ //@ no-prefer-dynamic #![crate_type = "rlib"] -#![feature(eii)] +#![feature(extern_item_impls)] #[eii(eii1)] pub fn decl1(x: u64) { diff --git a/tests/ui/eii/default/auxiliary/impl1.rs b/tests/ui/eii/default/auxiliary/impl1.rs index 4d627a5f68a6..3510ea1eb3f2 100644 --- a/tests/ui/eii/default/auxiliary/impl1.rs +++ b/tests/ui/eii/default/auxiliary/impl1.rs @@ -1,7 +1,7 @@ //@ no-prefer-dynamic //@ aux-build: decl_with_default.rs #![crate_type = "rlib"] -#![feature(eii)] +#![feature(extern_item_impls)] extern crate decl_with_default as decl; diff --git a/tests/ui/eii/default/call_default.rs b/tests/ui/eii/default/call_default.rs index 3557e1cdac12..90c56be78f13 100644 --- a/tests/ui/eii/default/call_default.rs +++ b/tests/ui/eii/default/call_default.rs @@ -5,7 +5,7 @@ //@ ignore-backends: gcc // Tests EIIs with default implementations. // When there's no explicit declaration, the default should be called from the declaring crate. -#![feature(eii)] +#![feature(extern_item_impls)] extern crate decl_with_default; diff --git a/tests/ui/eii/default/call_impl.rs b/tests/ui/eii/default/call_impl.rs index 1bb37f30f027..2e1cd5e7a966 100644 --- a/tests/ui/eii/default/call_impl.rs +++ b/tests/ui/eii/default/call_impl.rs @@ -7,7 +7,7 @@ // Tests EIIs with default implementations. // When an explicit implementation is given in one dependency, and the declaration is in another, // the explicit implementation is preferred. -#![feature(eii)] +#![feature(extern_item_impls)] extern crate decl_with_default; extern crate impl1; diff --git a/tests/ui/eii/default/local_crate.rs b/tests/ui/eii/default/local_crate.rs index 74e90fdc273d..f229f3cabf0c 100644 --- a/tests/ui/eii/default/local_crate.rs +++ b/tests/ui/eii/default/local_crate.rs @@ -3,7 +3,7 @@ //@ ignore-backends: gcc // Tests EIIs with default implementations. // In the same crate, when there's no explicit declaration, the default should be called. -#![feature(eii)] +#![feature(extern_item_impls)] #[eii(eii1)] pub fn decl1(x: u64) { diff --git a/tests/ui/eii/default/local_crate_explicit.rs b/tests/ui/eii/default/local_crate_explicit.rs index d671d8e70c97..e9d879b61c92 100644 --- a/tests/ui/eii/default/local_crate_explicit.rs +++ b/tests/ui/eii/default/local_crate_explicit.rs @@ -3,7 +3,7 @@ //@ ignore-backends: gcc // Tests EIIs with default implementations. // In the same crate, the explicit implementation should get priority. -#![feature(eii)] +#![feature(extern_item_impls)] #[eii(eii1)] pub fn decl1(x: u64) { diff --git a/tests/ui/eii/duplicate/auxiliary/decl.rs b/tests/ui/eii/duplicate/auxiliary/decl.rs index 81557fa6891b..2a0661715bfd 100644 --- a/tests/ui/eii/duplicate/auxiliary/decl.rs +++ b/tests/ui/eii/duplicate/auxiliary/decl.rs @@ -1,6 +1,6 @@ //@ no-prefer-dynamic #![crate_type = "rlib"] -#![feature(eii)] +#![feature(extern_item_impls)] #[eii(eii1)] fn decl1(x: u64); diff --git a/tests/ui/eii/duplicate/auxiliary/impl1.rs b/tests/ui/eii/duplicate/auxiliary/impl1.rs index d7c27f4dfde9..e99932c69b90 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl1.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl1.rs @@ -1,7 +1,7 @@ //@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] -#![feature(eii)] +#![feature(extern_item_impls)] extern crate decl; diff --git a/tests/ui/eii/duplicate/auxiliary/impl2.rs b/tests/ui/eii/duplicate/auxiliary/impl2.rs index bce6f11b89c4..3a09c824b829 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl2.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl2.rs @@ -1,7 +1,7 @@ //@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] -#![feature(eii)] +#![feature(extern_item_impls)] extern crate decl; diff --git a/tests/ui/eii/duplicate/auxiliary/impl3.rs b/tests/ui/eii/duplicate/auxiliary/impl3.rs index 82ba5af09863..09bdd8509da2 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl3.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl3.rs @@ -1,7 +1,7 @@ //@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] -#![feature(eii)] +#![feature(extern_item_impls)] extern crate decl; diff --git a/tests/ui/eii/duplicate/auxiliary/impl4.rs b/tests/ui/eii/duplicate/auxiliary/impl4.rs index 5275da1b1433..fd68a83de125 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl4.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl4.rs @@ -1,7 +1,7 @@ //@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] -#![feature(eii)] +#![feature(extern_item_impls)] extern crate decl; diff --git a/tests/ui/eii/duplicate/duplicate1.rs b/tests/ui/eii/duplicate/duplicate1.rs index 5573f47472a7..2e12d700b0a6 100644 --- a/tests/ui/eii/duplicate/duplicate1.rs +++ b/tests/ui/eii/duplicate/duplicate1.rs @@ -3,7 +3,7 @@ //@ aux-build: impl2.rs //@ ignore-backends: gcc // tests that EIIs error properly, even if the conflicting implementations live in another crate. -#![feature(eii)] +#![feature(extern_item_impls)] // has a span but in the other crate //~? ERROR multiple implementations of `#[eii1]` diff --git a/tests/ui/eii/duplicate/duplicate2.rs b/tests/ui/eii/duplicate/duplicate2.rs index d2bb1856565a..157871d2a3db 100644 --- a/tests/ui/eii/duplicate/duplicate2.rs +++ b/tests/ui/eii/duplicate/duplicate2.rs @@ -4,7 +4,7 @@ //@ aux-build: impl3.rs //@ ignore-backends: gcc // Tests the error message when there are multiple implementations of an EII in many crates. -#![feature(eii)] +#![feature(extern_item_impls)] // has a span but in the other crate //~? ERROR multiple implementations of `#[eii1]` diff --git a/tests/ui/eii/duplicate/duplicate3.rs b/tests/ui/eii/duplicate/duplicate3.rs index 2cd51268a6fb..5ac5ae7ff3d4 100644 --- a/tests/ui/eii/duplicate/duplicate3.rs +++ b/tests/ui/eii/duplicate/duplicate3.rs @@ -5,7 +5,7 @@ //@ aux-build: impl4.rs //@ ignore-backends: gcc // Tests the error message when there are multiple implementations of an EII in many crates. -#![feature(eii)] +#![feature(extern_item_impls)] // has a span but in the other crate //~? ERROR multiple implementations of `#[eii1]` diff --git a/tests/ui/eii/errors.rs b/tests/ui/eii/errors.rs index ec365b0e9d16..d59850a7d5f5 100644 --- a/tests/ui/eii/errors.rs +++ b/tests/ui/eii/errors.rs @@ -1,6 +1,6 @@ //@ compile-flags: --crate-type rlib // Tests all the kinds of errors when EII attributes are used with wrong syntax. -#![feature(eii)] +#![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] diff --git a/tests/ui/eii/multiple_decls.rs b/tests/ui/eii/multiple_decls.rs index 63ef269d7818..f7646630cab4 100644 --- a/tests/ui/eii/multiple_decls.rs +++ b/tests/ui/eii/multiple_decls.rs @@ -1,5 +1,5 @@ // Tests whether only one EII attribute cane be applied to a signature. -#![feature(eii)] +#![feature(extern_item_impls)] #[eii(a)] #[eii(b)] diff --git a/tests/ui/eii/multiple_impls.rs b/tests/ui/eii/multiple_impls.rs index 7f6691791410..ec3244137390 100644 --- a/tests/ui/eii/multiple_impls.rs +++ b/tests/ui/eii/multiple_impls.rs @@ -2,7 +2,7 @@ //@ check-run-results //@ ignore-backends: gcc // Tests whether one function could implement two EIIs. -#![feature(eii)] +#![feature(extern_item_impls)] #[eii] fn a(x: u64); diff --git a/tests/ui/eii/privacy1.rs b/tests/ui/eii/privacy1.rs index 64b35f7a070d..fc13a27c061e 100644 --- a/tests/ui/eii/privacy1.rs +++ b/tests/ui/eii/privacy1.rs @@ -3,7 +3,7 @@ //@ aux-build: codegen1.rs //@ ignore-backends: gcc // Tests whether re-exports work. -#![feature(eii)] +#![feature(extern_item_impls)] extern crate codegen1 as codegen; diff --git a/tests/ui/eii/privacy2.rs b/tests/ui/eii/privacy2.rs index 702773fb5c78..a4ae188bd0ec 100644 --- a/tests/ui/eii/privacy2.rs +++ b/tests/ui/eii/privacy2.rs @@ -1,6 +1,6 @@ //@ aux-build:codegen3.rs // Tests whether name resulution respects privacy properly. -#![feature(eii)] +#![feature(extern_item_impls)] extern crate codegen3 as codegen; diff --git a/tests/ui/eii/subtype_1.rs b/tests/ui/eii/subtype_1.rs index 8c58a5d7fac2..dfb998aa6f66 100644 --- a/tests/ui/eii/subtype_1.rs +++ b/tests/ui/eii/subtype_1.rs @@ -1,7 +1,7 @@ //@ compile-flags: --crate-type rlib // Uses manual desugaring of EII internals: // Tests whether it's not ok when the lifetimes are different between the decl and impl. -#![feature(eii)] +#![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] diff --git a/tests/ui/eii/subtype_2.rs b/tests/ui/eii/subtype_2.rs index 0453286a19c5..5f0c5553fccc 100644 --- a/tests/ui/eii/subtype_2.rs +++ b/tests/ui/eii/subtype_2.rs @@ -1,7 +1,7 @@ //@ compile-flags: --crate-type rlib // Uses manual desugaring of EII internals: // Tests whether it's not ok when the implementation is less general. -#![feature(eii)] +#![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] diff --git a/tests/ui/eii/subtype_3.rs b/tests/ui/eii/subtype_3.rs index 39d232e27c5b..269bc84df744 100644 --- a/tests/ui/eii/subtype_3.rs +++ b/tests/ui/eii/subtype_3.rs @@ -2,7 +2,7 @@ //@ check-pass // Uses manual desugaring of EII internals: // Tests whether it's ok when the implementation is more general. -#![feature(eii)] +#![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] diff --git a/tests/ui/eii/subtype_4.rs b/tests/ui/eii/subtype_4.rs index c55030238e75..e9194df7584c 100644 --- a/tests/ui/eii/subtype_4.rs +++ b/tests/ui/eii/subtype_4.rs @@ -2,7 +2,7 @@ //@ check-pass // Uses manual desugaring of EII internals: // Tests whether it's ok when giving the right types. -#![feature(eii)] +#![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] diff --git a/tests/ui/eii/unsafe_impl_err.rs b/tests/ui/eii/unsafe_impl_err.rs index cb3eb5a27c63..6af7e9724e15 100644 --- a/tests/ui/eii/unsafe_impl_err.rs +++ b/tests/ui/eii/unsafe_impl_err.rs @@ -1,6 +1,6 @@ //@ compile-flags: --crate-type rlib // Tests whether it's an error to implement an unsafe EII safely. -#![feature(eii)] +#![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] diff --git a/tests/ui/eii/unsafe_impl_ok.rs b/tests/ui/eii/unsafe_impl_ok.rs index 5ffd1ef1321b..268c5bc16fd8 100644 --- a/tests/ui/eii/unsafe_impl_ok.rs +++ b/tests/ui/eii/unsafe_impl_ok.rs @@ -2,7 +2,7 @@ //@ check-pass // Uses manual desugaring of EII internals: // Tests whether it's okay to implement an unsafe EII with an unsafe implementation. -#![feature(eii)] +#![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] diff --git a/tests/ui/eii/wrong_ret_ty.rs b/tests/ui/eii/wrong_ret_ty.rs index 4a268ca675bc..5fe7d2f8bb62 100644 --- a/tests/ui/eii/wrong_ret_ty.rs +++ b/tests/ui/eii/wrong_ret_ty.rs @@ -1,6 +1,6 @@ //@ compile-flags: --crate-type rlib // Uses manual desugaring of EII internals: tests whether the return type matches. -#![feature(eii)] +#![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] diff --git a/tests/ui/eii/wrong_target.rs b/tests/ui/eii/wrong_target.rs index 2a7fc4420943..a62915fe2609 100644 --- a/tests/ui/eii/wrong_target.rs +++ b/tests/ui/eii/wrong_target.rs @@ -1,4 +1,4 @@ -#![feature(eii)] +#![feature(extern_item_impls)] // Check whether the EII attributes do target checking properly. #[eii] diff --git a/tests/ui/eii/wrong_ty.rs b/tests/ui/eii/wrong_ty.rs index 4fb81734c74a..ebb756f6a314 100644 --- a/tests/ui/eii/wrong_ty.rs +++ b/tests/ui/eii/wrong_ty.rs @@ -1,6 +1,6 @@ //@ compile-flags: --crate-type rlib // Uses manual desugaring of EII internals: tests whether the types of parameters match. -#![feature(eii)] +#![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] diff --git a/tests/ui/eii/wrong_ty_2.rs b/tests/ui/eii/wrong_ty_2.rs index 085b9184caf0..d55f405bf157 100644 --- a/tests/ui/eii/wrong_ty_2.rs +++ b/tests/ui/eii/wrong_ty_2.rs @@ -1,6 +1,6 @@ //@ compile-flags: --crate-type rlib // Uses manual desugaring of EII internals: tests whether the number of parameters matches. -#![feature(eii)] +#![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] diff --git a/tests/ui/error-codes/E0806.rs b/tests/ui/error-codes/E0806.rs index 168c7120fc17..ab6a31673cc0 100644 --- a/tests/ui/error-codes/E0806.rs +++ b/tests/ui/error-codes/E0806.rs @@ -1,4 +1,4 @@ -#![feature(eii)] +#![feature(extern_item_impls)] #[eii(foo)] fn x(); diff --git a/tests/ui/feature-gates/feature-gate-eii.rs b/tests/ui/feature-gates/feature-gate-extern-item-impls.rs similarity index 59% rename from tests/ui/feature-gates/feature-gate-eii.rs rename to tests/ui/feature-gates/feature-gate-extern-item-impls.rs index 3a51c3dd2eae..f70ece554a09 100644 --- a/tests/ui/feature-gates/feature-gate-eii.rs +++ b/tests/ui/feature-gates/feature-gate-extern-item-impls.rs @@ -1,6 +1,6 @@ #![crate_type = "rlib"] -#[eii] //~ ERROR use of unstable library feature `eii` +#[eii] //~ ERROR use of unstable library feature `extern_item_impls` fn hello(x: u64); #[hello] diff --git a/tests/ui/feature-gates/feature-gate-eii.stderr b/tests/ui/feature-gates/feature-gate-extern-item-impls.stderr similarity index 63% rename from tests/ui/feature-gates/feature-gate-eii.stderr rename to tests/ui/feature-gates/feature-gate-extern-item-impls.stderr index 6ec231257ba7..0baace310d42 100644 --- a/tests/ui/feature-gates/feature-gate-eii.stderr +++ b/tests/ui/feature-gates/feature-gate-extern-item-impls.stderr @@ -1,11 +1,11 @@ -error[E0658]: use of unstable library feature `eii` - --> $DIR/feature-gate-eii.rs:3:3 +error[E0658]: use of unstable library feature `extern_item_impls` + --> $DIR/feature-gate-extern-item-impls.rs:3:3 | LL | #[eii] | ^^^ | = note: see issue #125418 for more information - = help: add `#![feature(eii)]` to the crate attributes to enable + = help: add `#![feature(extern_item_impls)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 1 previous error From 13de732df5d6988a4377247c04b64efed080cae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 8 Dec 2025 11:47:25 +0100 Subject: [PATCH 559/585] add test for symbol mangling issue --- tests/ui/eii/same-symbol.rs | 29 +++++++++++++++++++++++++++++ tests/ui/eii/same-symbol.run.stdout | 2 ++ 2 files changed, 31 insertions(+) create mode 100644 tests/ui/eii/same-symbol.rs create mode 100644 tests/ui/eii/same-symbol.run.stdout diff --git a/tests/ui/eii/same-symbol.rs b/tests/ui/eii/same-symbol.rs new file mode 100644 index 000000000000..d24e5c4266bb --- /dev/null +++ b/tests/ui/eii/same-symbol.rs @@ -0,0 +1,29 @@ +//@ run-pass +//@ check-run-results +//@ ignore-backends: gcc +#![feature(extern_item_impls)] + +pub mod a { + #[eii(foo)] + pub fn foo(); +} + +pub mod b { + #[eii(foo)] + pub fn foo(); +} + +#[a::foo] +fn a_foo_impl() { + println!("foo1"); +} + +#[b::foo] +fn b_foo_impl() { + println!("foo2"); +} + +fn main() { + a::foo(); + b::foo(); +} diff --git a/tests/ui/eii/same-symbol.run.stdout b/tests/ui/eii/same-symbol.run.stdout new file mode 100644 index 000000000000..873ddc86a9d5 --- /dev/null +++ b/tests/ui/eii/same-symbol.run.stdout @@ -0,0 +1,2 @@ +foo1 +foo1 From 3f63f521c1f611c2d68eaaf1fe5f9a3f08be3ed5 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 12 Dec 2025 22:06:07 +1100 Subject: [PATCH 560/585] Don't pass an unused `--color` to compiletest This flag was an artifact of compiletest's old libtest-based test executor, and currently doesn't influence compiletest's output at all. --- src/bootstrap/src/core/build_steps/test.rs | 1 - src/tools/compiletest/src/lib.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a699cd23fb60..f30641d71e83 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2401,7 +2401,6 @@ fn run(self, builder: &Builder<'_>) { let git_config = builder.config.git_config(); cmd.arg("--nightly-branch").arg(git_config.nightly_branch); cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email); - cmd.force_coloring_in_ci(); #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 1fa818df62de..71dad3633793 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -136,8 +136,6 @@ fn parse_config(args: Vec) -> Config { ) .optflag("", "fail-fast", "stop as soon as possible after any test fails") .optopt("", "target", "the target to build for", "TARGET") - // FIXME: Should be removed once `bootstrap` will be updated to not use this option. - .optopt("", "color", "coloring: auto, always, never", "WHEN") .optopt("", "host", "the host to build for", "HOST") .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH") .optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH") From 5768b234de07a3d39bb35deb36d3af92b790bc75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 8 Dec 2025 11:46:59 +0100 Subject: [PATCH 561/585] use our own alternative to STD_INTERNAL_SYMBOL and make sure we mangle EIIs properly --- .../src/attributes/codegen_attrs.rs | 9 +++++++++ compiler/rustc_attr_parsing/src/context.rs | 5 +++-- compiler/rustc_builtin_macros/src/eii.rs | 20 ++++++++++++++++++- .../src/back/symbol_export.rs | 9 +++++++-- .../rustc_codegen_ssa/src/codegen_attrs.rs | 11 +++++++++- compiler/rustc_feature/src/builtin_attrs.rs | 5 +++++ .../rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + .../src/middle/codegen_fn_attrs.rs | 13 ++++++++++++ .../src/middle/exported_symbols.rs | 1 + compiler/rustc_monomorphize/src/collector.rs | 12 ++++++----- .../rustc_monomorphize/src/partitioning.rs | 12 +++++++++-- compiler/rustc_passes/src/check_attr.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + tests/ui/eii/same-symbol.run.stdout | 2 +- 15 files changed, 91 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index b4ecbe6e4de6..c5800324fa99 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -699,3 +699,12 @@ impl NoArgsAttributeParser for RustcPassIndirectlyInNonRusticAbisPa const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis; } + +pub(crate) struct EiiExternItemParser; + +impl NoArgsAttributeParser for EiiExternItemParser { + const PATH: &[Symbol] = &[sym::rustc_eii_extern_item]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::EiiExternItem; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index f41ea3708788..894b4c564ab7 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -20,8 +20,8 @@ }; use crate::attributes::body::CoroutineParser; use crate::attributes::codegen_attrs::{ - ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser, - NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, + ColdParser, CoverageParser, EiiExternItemParser, ExportNameParser, ForceTargetFeatureParser, + NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser, TrackCallerParser, UsedParser, }; @@ -227,6 +227,7 @@ mod late { Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index f1161c644ef5..b97cb1daec53 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -209,6 +209,24 @@ fn eii_( } // extern "…" { safe fn item(); } + let mut extern_item_attrs = attrs.clone(); + extern_item_attrs.push(ast::Attribute { + kind: ast::AttrKind::Normal(Box::new(ast::NormalAttr { + item: ast::AttrItem { + unsafety: ast::Safety::Default, + // Add the rustc_eii_extern_item on the foreign item. Usually, foreign items are mangled. + // This attribute makes sure that we later know that this foreign item's symbol should not be. + path: ast::Path::from_ident(Ident::new(sym::rustc_eii_extern_item, span)), + args: ast::AttrArgs::Empty, + tokens: None, + }, + tokens: None, + })), + id: ecx.sess.psess.attr_id_generator.mk_attr_id(), + style: ast::AttrStyle::Outer, + span, + }); + let extern_block = Box::new(ast::Item { attrs: ast::AttrVec::default(), id: ast::DUMMY_NODE_ID, @@ -219,7 +237,7 @@ fn eii_( safety: ast::Safety::Unsafe(span), abi, items: From::from([Box::new(ast::ForeignItem { - attrs: attrs.clone(), + attrs: extern_item_attrs, id: ast::DUMMY_NODE_ID, span: item_span, vis, diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 9d06de2b35c2..27989f6f5ea2 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -127,7 +127,10 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap, sym_def_id: DefId) -> SymbolExportLevel let is_extern = codegen_fn_attrs.contains_extern_indicator(); let std_internal = codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); + let eii = codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM); - if is_extern && !std_internal { + if is_extern && !std_internal && !eii { let target = &tcx.sess.target.llvm_target; // WebAssembly cannot export data symbols, so reduce their export level + // FIXME(jdonszelmann) don't do a substring match here. if target.contains("emscripten") { if let DefKind::Static { .. } = tcx.def_kind(sym_def_id) { return SymbolExportLevel::Rust; diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 6aea249d6356..1933947ee0de 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -313,6 +313,9 @@ fn process_builtin_attrs( AttributeKind::ObjcSelector { methname, .. } => { codegen_fn_attrs.objc_selector = Some(*methname); } + AttributeKind::EiiExternItem => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM; + } AttributeKind::EiiImpls(impls) => { for i in impls { let extern_item = find_attr!( @@ -344,7 +347,7 @@ fn process_builtin_attrs( if i.is_default { Linkage::LinkOnceAny } else { Linkage::External }, Visibility::Default, )); - codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM; } } _ => {} @@ -448,6 +451,12 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code // * `#[rustc_std_internal_symbol]` mangles the symbol name in a special way // both for exports and imports through foreign items. This is handled further, // during symbol mangling logic. + } else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM) + { + // * externally implementable items keep their mangled symbol name. + // multiple EIIs can have the same name, so not mangling them would be a bug. + // Implementing an EII does the appropriate name resolution to make sure the implementations + // get the same symbol name as the *mangled* foreign item they refer to so that's all good. } else if codegen_fn_attrs.symbol_name.is_some() { // * This can be overridden with the `#[link_name]` attribute } else { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 6eefb2f48d12..c70dbc15e552 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -961,6 +961,11 @@ pub struct BuiltinAttribute { allow_internal_unsafe, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint", ), + gated!( + rustc_eii_extern_item, Normal, template!(Word), + ErrorFollowing, EncodeCrossCrate::Yes, eii_internals, + "used internally to mark types with a `transparent` representation when it is guaranteed by the documentation", + ), rustc_attr!( rustc_allowed_through_unstable_modules, Normal, template!(NameValueStr: "deprecation message"), WarnFollowing, EncodeCrossCrate::No, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 28433f261220..34d78afca9b2 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -709,6 +709,9 @@ pub enum AttributeKind { /// Represents `#[rustc_dummy]`. Dummy, + /// Implementation detail of `#[eii]` + EiiExternItem, + /// Implementation detail of `#[eii]` EiiExternTarget(EiiDecl), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index e42d511da695..4cb786f59bfe 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -43,6 +43,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate { Doc(_) => Yes, DocComment { .. } => Yes, Dummy => No, + EiiExternItem => No, EiiExternTarget(_) => Yes, EiiImpls(..) => No, ExportName { .. } => Yes, diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 7922cc38aaab..9033d9c46d54 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -43,6 +43,10 @@ pub fn codegen_instance_attrs( attrs.to_mut().flags.remove(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); } + if attrs.flags.contains(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM) { + attrs.to_mut().flags.remove(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM); + } + if attrs.symbol_name.is_some() { attrs.to_mut().symbol_name = None; } @@ -199,6 +203,12 @@ impl CodegenFnAttrFlags: u32 { const FOREIGN_ITEM = 1 << 16; /// `#[rustc_offload_kernel]`: indicates that this is an offload kernel, an extra ptr arg will be added. const OFFLOAD_KERNEL = 1 << 17; + /// Externally implementable item symbols act a little like `RUSTC_STD_INTERNAL_SYMBOL`. + /// When a crate declares an EII and dependencies expect the symbol to exist, + /// they will refer to this symbol name before a definition is given. + /// As such, we must make sure these symbols really do exist in the final binary/library. + /// This flag is put on both the implementations of EIIs and the foreign item they implement. + const EXTERNALLY_IMPLEMENTABLE_ITEM = 1 << 18; } } rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags } @@ -242,6 +252,9 @@ pub fn contains_extern_indicator(&self) -> bool { self.flags.contains(CodegenFnAttrFlags::NO_MANGLE) || self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) + // note: for these we do also set a symbol name so technically also handled by the + // condition below. However, I think that regardless these should be treated as extern. + || self.flags.contains(CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM) || self.symbol_name.is_some() || match self.linkage { // These are private, so make sure we don't try to consider diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index c70ff398ceaf..58fc32078039 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -41,6 +41,7 @@ pub struct SymbolExportInfo { /// Was the symbol marked as `#[used(compiler)]` or `#[used(linker)]`? pub used: bool, /// Was the symbol marked as `#[rustc_std_internal_symbol]`? + /// We also use this for externally implementable items. pub rustc_std_internal_symbol: bool, } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 948f965ed7ad..cd699436e012 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1643,11 +1643,13 @@ fn is_root(&self, def_id: LocalDefId) -> bool { MonoItemCollectionStrategy::Lazy => { self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id) || self.tcx.is_reachable_non_generic(def_id) - || self - .tcx - .codegen_fn_attrs(def_id) - .flags - .contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) + || { + let flags = self.tcx.codegen_fn_attrs(def_id).flags; + flags.intersects( + CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL + | CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM, + ) + } } } } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index b87ab840a32d..1c8d6db08c31 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -872,7 +872,7 @@ fn mono_item_visibility<'tcx>( // visibility. In some situations though we'll want to prevent this // symbol from being internalized. // - // There's two categories of items here: + // There's three categories of items here: // // * First is weak lang items. These are basically mechanisms for // libcore to forward-reference symbols defined later in crates like @@ -902,8 +902,16 @@ fn mono_item_visibility<'tcx>( // visibility below. Like the weak lang items, though, we can't let // LLVM internalize them as this decision is left up to the linker to // omit them, so prevent them from being internalized. + // + // * Externally implementable items. They work (in this case) pretty much the same as + // RUSTC_STD_INTERNAL_SYMBOL in that their implementation is also chosen later in + // the compilation process and we can't let them be internalized and they can't + // show up as an external interface. let attrs = tcx.codegen_fn_attrs(def_id); - if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { + if attrs.flags.intersects( + CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL + | CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM, + ) { *can_be_internalized = false; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d5d2d64ffaf7..34f73212e90b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -217,6 +217,7 @@ fn check_attributes( }, Attribute::Parsed( AttributeKind::EiiExternTarget { .. } + | AttributeKind::EiiExternItem | AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect | AttributeKind::MacroTransparency(_) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8f43a31ea4b1..8e464b55d6c2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1944,6 +1944,7 @@ rustc_dump_user_args, rustc_dump_vtable, rustc_effective_visibility, + rustc_eii_extern_item, rustc_evaluate_where_clauses, rustc_expected_cgu_reuse, rustc_force_inline, diff --git a/tests/ui/eii/same-symbol.run.stdout b/tests/ui/eii/same-symbol.run.stdout index 873ddc86a9d5..463021151d29 100644 --- a/tests/ui/eii/same-symbol.run.stdout +++ b/tests/ui/eii/same-symbol.run.stdout @@ -1,2 +1,2 @@ foo1 -foo1 +foo2 From e7b729cd92cae3d93ab70fdb21587d5c326711da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 9 Dec 2025 12:42:32 +0100 Subject: [PATCH 562/585] ignore test with defaults on macos --- tests/ui/eii/default/call_default.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/ui/eii/default/call_default.rs b/tests/ui/eii/default/call_default.rs index 90c56be78f13..7b39f6d225af 100644 --- a/tests/ui/eii/default/call_default.rs +++ b/tests/ui/eii/default/call_default.rs @@ -3,6 +3,16 @@ //@ run-pass //@ check-run-results //@ ignore-backends: gcc +// Functions can have target-cpu applied. On apple-darwin this is super important, +// since you can have binaries which mix x86 and aarch64 code that are compatible +// with both architectures. So we can't just reject target_cpu on EIIs since apple +// puts them on by default. The problem: we generate aliases. And aliases cannot +// get target_cpu applied to them. So, instead we should, in the case of functions, +// generate a shim function. For statics aliases should keep working in theory. +// In fact, aliases are only necessary for statics. For functions we could just +// always generate a shim and a previous version of EII did so but I was sad +// that that'd never support statics. +//@ ignore-macos // Tests EIIs with default implementations. // When there's no explicit declaration, the default should be called from the declaring crate. #![feature(extern_item_impls)] From ac5c70ad4d5d8f767237f5b3d28719fbc5d72bc8 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 11:46:11 +0100 Subject: [PATCH 563/585] time: Implement SystemTime::{MIN, MAX} This commit introduces two new constants to SystemTime: `MIN` and `MAX`, whose value represent the maximum values for the respective data type, depending upon the platform. Technically, this value is already obtainable during runtime with the following algorithm: Use `SystemTime::UNIX_EPOCH` and call `checked_add` (or `checked_sub`) repeatedly with `Duration::new(0, 1)` on it, until it returns None. Mathematically speaking, this algorithm will terminate after a finite amount of steps, yet it is impractical to run it, as it takes practically forever. Besides, this commit also adds a unit test. Concrete implementation depending upon the platform is done in later commits. In the future, the hope of the authors lies within the creation of a `SystemTime::saturating_add` and `SystemTime::saturating_sub`, similar to the functions already present in `std::time::Duration`. However, for those, these constants are crucially required, thereby this should be seen as the initial step towards this direction. Below are platform specifc notes: # Hermit The HermitOS implementation is more or less identitcal to the Unix one. # sgx The implementation uses a `Duration` to store the Unix time, thereby implying `Duration::ZERO` and `Duration::MAX` as the limits. # solid The implementation uses a `time_t` to store the system time within a single value (i.e. no dual secs/nanosecs handling), thereby implying its `::MIN` and `::MAX` values as the respective boundaries. # UEFI UEFI has a weird way to store times, i.e. a very complicated struct. The standard proclaims "1900-01-01T00:00:00+0000" to be the lowest possible value and `MAX_UEFI_TIME` is already present for the upper limit. # Windows Windows is weird. The Win32 documentation makes no statement on a maximum value here. Next to this, there are two conflicting types: `SYSTEMTIME` and `FILETIME`. Rust's Standard Library uses `FILETIME`, whose limit will (probably) be `i64::MAX` packed into two integers. However, `SYSTEMTIME` has a lower-limit. # xous It is similar to sgx in the sense of using a `Duration`. # unsupported Unsupported platforms store a `SystemTime` in a `Duration`, just like sgx, thereby implying `Duration::ZERO` and `Duration::MAX` as the respective limits. --- library/std/src/sys/pal/hermit/time.rs | 8 +++ library/std/src/sys/pal/sgx/time.rs | 4 ++ library/std/src/sys/pal/solid/time.rs | 4 ++ library/std/src/sys/pal/uefi/time.rs | 17 ++++++ library/std/src/sys/pal/unix/time.rs | 11 ++++ library/std/src/sys/pal/unsupported/time.rs | 4 ++ library/std/src/sys/pal/windows/time.rs | 10 ++++ library/std/src/sys/pal/xous/time.rs | 4 ++ library/std/src/time.rs | 63 +++++++++++++++++++++ library/std/tests/time.rs | 19 +++++++ 10 files changed, 144 insertions(+) diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index bd6fd5a3de42..53b1f9292b3d 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -15,6 +15,10 @@ struct Timespec { } impl Timespec { + const MAX: Timespec = Self::new(i64::MAX, 1_000_000_000 - 1); + + const MIN: Timespec = Self::new(i64::MIN, 0); + const fn zero() -> Timespec { Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } } } @@ -209,6 +213,10 @@ fn sub(self, other: Instant) -> Duration { pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero()); impl SystemTime { + pub const MAX: SystemTime = SystemTime { t: Timespec::MAX }; + + pub const MIN: SystemTime = SystemTime { t: Timespec::MIN }; + pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime { SystemTime(Timespec::new(tv_sec, tv_nsec)) } diff --git a/library/std/src/sys/pal/sgx/time.rs b/library/std/src/sys/pal/sgx/time.rs index db4cf2804bf1..a9a448226619 100644 --- a/library/std/src/sys/pal/sgx/time.rs +++ b/library/std/src/sys/pal/sgx/time.rs @@ -28,6 +28,10 @@ pub fn checked_sub_duration(&self, other: &Duration) -> Option { } impl SystemTime { + pub const MAX: SystemTime = SystemTime(Duration::MAX); + + pub const MIN: SystemTime = SystemTime(Duration::ZERO); + pub fn now() -> SystemTime { SystemTime(usercalls::insecure_time()) } diff --git a/library/std/src/sys/pal/solid/time.rs b/library/std/src/sys/pal/solid/time.rs index c39d715c6a6f..d5cf70f94c98 100644 --- a/library/std/src/sys/pal/solid/time.rs +++ b/library/std/src/sys/pal/solid/time.rs @@ -10,6 +10,10 @@ pub const UNIX_EPOCH: SystemTime = SystemTime(0); impl SystemTime { + pub const MAX: SystemTime = SystemTime(abi::time_t::MAX); + + pub const MIN: SystemTime = SystemTime(abi::time_t::MIN); + pub fn now() -> SystemTime { let rtc = unsafe { let mut out = MaybeUninit::zeroed(); diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index 28dacbe3068a..30df6d93d0ee 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -70,6 +70,23 @@ pub fn checked_sub_duration(&self, other: &Duration) -> Option { } impl SystemTime { + pub const MAX: SystemTime = MAX_UEFI_TIME; + + pub const MIN: SystemTime = SystemTime::from_uefi(r_efi::efi::Time { + year: 1900, + month: 1, + day: 1, + hour: 0, + minute: 0, + second: 0, + nanosecond: 0, + timezone: -1440, + daylight: 0, + pad1: 0, + pad2: 0, + }) + .unwrap(); + pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Option { match system_time_internal::from_uefi(&t) { Some(x) => Some(Self(x)), diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 24f13853b96b..1b3fbeee4d90 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -30,6 +30,10 @@ pub(crate) struct Timespec { } impl SystemTime { + pub const MAX: SystemTime = SystemTime { t: Timespec::MAX }; + + pub const MIN: SystemTime = SystemTime { t: Timespec::MIN }; + #[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))] pub fn new(tv_sec: i64, tv_nsec: i64) -> Result { Ok(SystemTime { t: Timespec::new(tv_sec, tv_nsec)? }) @@ -62,6 +66,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } impl Timespec { + const MAX: Timespec = unsafe { Self::new_unchecked(i64::MAX, 1_000_000_000 - 1) }; + + // As described below, on Apple OS, dates before epoch are represented differently. + // This is not an issue here however, because we are using tv_sec = i64::MIN, + // which will cause the compatibility wrapper to not be executed at all. + const MIN: Timespec = unsafe { Self::new_unchecked(i64::MIN, 0) }; + const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec { Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds::new_unchecked(tv_nsec as u32) } } } diff --git a/library/std/src/sys/pal/unsupported/time.rs b/library/std/src/sys/pal/unsupported/time.rs index 6d67b538a96b..9bdd57268fd5 100644 --- a/library/std/src/sys/pal/unsupported/time.rs +++ b/library/std/src/sys/pal/unsupported/time.rs @@ -27,6 +27,10 @@ pub fn checked_sub_duration(&self, other: &Duration) -> Option { } impl SystemTime { + pub const MAX: SystemTime = SystemTime(Duration::MAX); + + pub const MIN: SystemTime = SystemTime(Duration::ZERO); + pub fn now() -> SystemTime { panic!("time not implemented on this platform") } diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index 0d31b80e56af..88f4d4cdbd61 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -64,6 +64,16 @@ pub fn checked_sub_duration(&self, other: &Duration) -> Option { } impl SystemTime { + pub const MAX: SystemTime = SystemTime { + t: c::FILETIME { + dwLowDateTime: (i64::MAX & 0xFFFFFFFF) as u32, + dwHighDateTime: (i64::MAX >> 32) as u32, + }, + }; + + pub const MIN: SystemTime = + SystemTime { t: c::FILETIME { dwLowDateTime: 0, dwHighDateTime: 0 } }; + pub fn now() -> SystemTime { unsafe { let mut t: SystemTime = mem::zeroed(); diff --git a/library/std/src/sys/pal/xous/time.rs b/library/std/src/sys/pal/xous/time.rs index ae8be81c0b7c..1e7e48183e98 100644 --- a/library/std/src/sys/pal/xous/time.rs +++ b/library/std/src/sys/pal/xous/time.rs @@ -35,6 +35,10 @@ pub fn checked_sub_duration(&self, other: &Duration) -> Option { } impl SystemTime { + pub const MAX: SystemTime = SystemTime(Duration::MAX); + + pub const MIN: SystemTime = SystemTime(Duration::ZERO); + pub fn now() -> SystemTime { let result = blocking_scalar(systime_server(), GetUtcTimeMs.into()) .expect("failed to request utc time in ms"); diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 87aaf9091f1b..0bda83af4dfb 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -511,6 +511,69 @@ impl SystemTime { #[stable(feature = "assoc_unix_epoch", since = "1.28.0")] pub const UNIX_EPOCH: SystemTime = UNIX_EPOCH; + /// Represents the maximum value representable by [`SystemTime`] on this platform. + /// + /// This value differs a lot between platforms, but it is always the case + /// that any positive addition to [`SystemTime::MAX`] will fail. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(time_systemtime_limits)] + /// use std::time::{Duration, SystemTime}; + /// + /// // Adding zero will change nothing. + /// assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX)); + /// + /// // But adding just 1ns will already fail. + /// assert_eq!(SystemTime::MAX.checked_add(Duration::new(0, 1)), None); + /// + /// // Utilize this for saturating arithmetic to improve error handling. + /// // In this case, we will use a certificate with a timestamp in the + /// // future as a practical example. + /// let configured_offset = Duration::from_secs(60 * 60 * 24); + /// let valid_after = + /// SystemTime::now() + /// .checked_add(configured_offset) + /// .unwrap_or(SystemTime::MAX); + /// ``` + #[unstable(feature = "time_systemtime_limits", issue = "149067")] + pub const MAX: SystemTime = SystemTime(time::SystemTime::MAX); + + /// Represents the minimum value representable by [`SystemTime`] on this platform. + /// + /// This value differs a lot between platforms, but it is always the case + /// that any positive subtraction from [`SystemTime::MIN`] will fail. + /// + /// Depending on the platform, this may be either less than or equal to + /// [`SystemTime::UNIX_EPOCH`], depending on whether the operating system + /// supports the representation of timestamps before the Unix epoch or not. + /// However, it is always guaranteed that a [`SystemTime::UNIX_EPOCH`] fits + /// between a [`SystemTime::MIN`] and [`SystemTime::MAX`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(time_systemtime_limits)] + /// use std::time::{Duration, SystemTime}; + /// + /// // Subtracting zero will change nothing. + /// assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN)); + /// + /// // But subtracting just 1ns will already fail. + /// assert_eq!(SystemTime::MIN.checked_sub(Duration::new(0, 1)), None); + /// + /// // Utilize this for saturating arithmetic to improve error handling. + /// // In this case, we will use a cache expiry as a practical example. + /// let configured_expiry = Duration::from_secs(60 * 3); + /// let expiry_threshold = + /// SystemTime::now() + /// .checked_sub(configured_expiry) + /// .unwrap_or(SystemTime::MIN); + /// ``` + #[unstable(feature = "time_systemtime_limits", issue = "149067")] + pub const MIN: SystemTime = SystemTime(time::SystemTime::MIN); + /// Returns the system time corresponding to "now". /// /// # Examples diff --git a/library/std/tests/time.rs b/library/std/tests/time.rs index be1948af9156..31cc7171fe52 100644 --- a/library/std/tests/time.rs +++ b/library/std/tests/time.rs @@ -1,4 +1,5 @@ #![feature(duration_constants)] +#![feature(time_systemtime_limits)] use std::fmt::Debug; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; @@ -237,9 +238,27 @@ fn system_time_duration_since_max_range_on_unix() { let min = SystemTime::UNIX_EPOCH - (Duration::new(i64::MAX as u64 + 1, 0)); let max = SystemTime::UNIX_EPOCH + (Duration::new(i64::MAX as u64, 999_999_999)); + assert_eq!(min, SystemTime::MIN); + assert_eq!(max, SystemTime::MAX); + let delta_a = max.duration_since(min).expect("duration_since overflow"); let delta_b = min.duration_since(max).expect_err("duration_since overflow").duration(); assert_eq!(Duration::MAX, delta_a); assert_eq!(Duration::MAX, delta_b); } + +#[test] +fn system_time_max_min() { + // First, test everything with checked_* and Duration::ZERO. + assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX)); + assert_eq!(SystemTime::MAX.checked_sub(Duration::ZERO), Some(SystemTime::MAX)); + assert_eq!(SystemTime::MIN.checked_add(Duration::ZERO), Some(SystemTime::MIN)); + assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN)); + + // Now do the same again with checked_* but try by ± a single nanosecond. + assert!(SystemTime::MAX.checked_add(Duration::new(0, 1)).is_none()); + assert!(SystemTime::MAX.checked_sub(Duration::new(0, 1)).is_some()); + assert!(SystemTime::MIN.checked_add(Duration::new(0, 1)).is_some()); + assert!(SystemTime::MIN.checked_sub(Duration::new(0, 1)).is_none()); +} From 0e7dc328942c05a98f2e49b65692d7e7e70ea9d7 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 12 Dec 2025 22:26:31 +1100 Subject: [PATCH 564/585] Inline `BootstrapCommand::force_coloring_in_ci` into its only call site This logic is cargo-specific anyway, so there is no need for it to be a generally-available helper method. --- src/bootstrap/src/core/builder/cargo.rs | 10 +++++++++- src/bootstrap/src/utils/exec.rs | 13 ------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 2ca52c72e5ec..5a6bade59a6a 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -2,6 +2,8 @@ use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; +use build_helper::ci::CiEnv; + use super::{Builder, Kind}; use crate::core::build_steps::test; use crate::core::build_steps::tool::SourceType; @@ -1334,7 +1336,13 @@ fn cargo( // Try to use a sysroot-relative bindir, in case it was configured absolutely. cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative()); - cargo.force_coloring_in_ci(); + if CiEnv::is_ci() { + // Tell cargo to use colored output for nicer logs in CI, even + // though CI isn't printing to a terminal. + // Also set an explicit `TERM=xterm` so that cargo doesn't warn + // about TERM not being set. + cargo.env("TERM", "xterm").args(["--color=always"]); + }; // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index f875e6e1af75..61b8b26dceaf 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -21,7 +21,6 @@ use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; -use build_helper::ci::CiEnv; use build_helper::drop_bomb::DropBomb; use build_helper::exit; @@ -390,18 +389,6 @@ pub fn get_created_location(&self) -> std::panic::Location<'static> { self.drop_bomb.get_created_location() } - /// If in a CI environment, forces the command to run with colors. - pub fn force_coloring_in_ci(&mut self) { - if CiEnv::is_ci() { - // Due to use of stamp/docker, the output stream of bootstrap is not - // a TTY in CI, so coloring is by-default turned off. - // The explicit `TERM=xterm` environment is needed for - // `--color always` to actually work. This env var was lost when - // compiling through the Makefile. Very strange. - self.env("TERM", "xterm").args(["--color", "always"]); - } - } - pub fn fingerprint(&self) -> CommandFingerprint { let command = &self.command; CommandFingerprint { From 93c3ac2868b6823c5fb7c0e1c98f8578fcfe3ad0 Mon Sep 17 00:00:00 2001 From: Jamie Cunliffe Date: Fri, 12 Dec 2025 13:25:21 +0000 Subject: [PATCH 565/585] `declare_lint_pass` for `INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES` The `INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES` lint was missing from this causing it to be an unknown lint when attempting to allow it. --- compiler/rustc_lint_defs/src/builtin.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index baecc14424ec..99cce0c44b86 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -48,6 +48,7 @@ ILL_FORMED_ATTRIBUTE_INPUT, INCOMPLETE_INCLUDE, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES, INLINE_NO_SANITIZE, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, From 02bace8476c690a253f2dbdbe0f1fb75d402c8f6 Mon Sep 17 00:00:00 2001 From: Daria Sukhonina Date: Fri, 12 Dec 2025 16:35:48 +0300 Subject: [PATCH 566/585] Add a sanity check in case of any duplicate nodes --- compiler/rustc_query_system/src/dep_graph/graph.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index b2c72f19b78b..b85f226d108c 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1384,7 +1384,9 @@ pub(super) fn get(&self, index: SerializedDepNodeIndex) -> DepNodeColor { #[inline] pub(super) fn insert_red(&self, index: SerializedDepNodeIndex) { - self.values[index].store(COMPRESSED_RED, Ordering::Release) + let value = self.values[index].swap(COMPRESSED_RED, Ordering::Release); + // Sanity check for duplicate nodes + assert_eq!(value, COMPRESSED_UNKNOWN, "trying to encode a dep node twice"); } } From 0ab4b8b9e0257a15fdf791950f48fa77dc0019b0 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 12 Dec 2025 12:21:15 +0100 Subject: [PATCH 567/585] Remove the E0536 error code --- compiler/rustc_error_codes/src/error_codes/E0536.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_error_codes/src/error_codes/E0536.md b/compiler/rustc_error_codes/src/error_codes/E0536.md index c1f43fa741cf..7603be4fcc93 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0536.md +++ b/compiler/rustc_error_codes/src/error_codes/E0536.md @@ -1,3 +1,5 @@ +#### Note: this error code is no longer emitted by the compiler. + The `not` cfg-predicate was malformed. Erroneous code example (using `cargo doc`): From c7b5fb56950c3a7999fa9348096ee55d2773ace2 Mon Sep 17 00:00:00 2001 From: Daria Sukhonina Date: Fri, 12 Dec 2025 16:44:17 +0300 Subject: [PATCH 568/585] Also check in case it tries to mark red node as green --- compiler/rustc_query_system/src/dep_graph/graph.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index b85f226d108c..8634274c3a75 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1363,7 +1363,10 @@ pub(super) fn try_mark_green( Ordering::Relaxed, ) { Ok(_) => Ok(()), - Err(v) => Err(DepNodeIndex::from_u32(v)), + Err(v) => Err({ + assert_ne!(v, COMPRESSED_RED, "tried to mark a red node as green"); + DepNodeIndex::from_u32(v) + }), } } From d025cdef7d9f5214dfffc4425eb1dd2228f8dc6c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 12 Dec 2025 14:47:28 +0100 Subject: [PATCH 569/585] If there are too many suggestions for malformed attribute, do not suggest them --- .../src/session_diagnostics.rs | 24 +- .../rustc_attr_parsing/src/validate_attr.rs | 5 + tests/rustdoc-ui/bad-render-options.stderr | 144 --------- tests/rustdoc-ui/check-doc-alias-attr.stderr | 32 -- tests/rustdoc-ui/doc-cfg.stderr | 80 ----- tests/rustdoc-ui/invalid-cfg.stderr | 128 -------- tests/rustdoc-ui/lints/doc-attr.stderr | 48 --- .../ui/attributes/crate-type-delimited.stderr | 14 - tests/ui/attributes/crate-type-empty.stderr | 10 - .../attributes/crate-type-macro-call.stderr | 14 - tests/ui/attributes/doc-attr.stderr | 48 --- tests/ui/attributes/doc-test-literal.stderr | 16 - tests/ui/attributes/malformed-attrs.stderr | 62 ---- tests/ui/attributes/malformed-reprs.stderr | 11 - .../ui/deprecation/deprecation-sanity.stderr | 96 ------ tests/ui/error-codes/E0458.stderr | 15 - tests/ui/error-codes/E0565-1.stderr | 16 - tests/ui/issues/issue-43988.stderr | 22 -- tests/ui/link-native-libs/issue-43925.stderr | 15 - tests/ui/link-native-libs/issue-43926.stderr | 15 - .../link-attr-validation-early.stderr | 26 -- .../link-attr-validation-late.stderr | 279 ------------------ .../modifiers-override-4.stderr | 43 --- tests/ui/linkage-attr/linkage3.stderr | 16 - .../import-name-type-invalid-format.stderr | 15 - .../windows/import-name-type-multiple.stderr | 15 - .../import-name-type-unknown-value.stderr | 15 - .../ui/malformed/malformed-regressions.stderr | 26 -- tests/ui/repr/repr.stderr | 41 --- tests/ui/rustdoc/check-doc-alias-attr.stderr | 32 -- .../ui/sanitize-attr/invalid-sanitize.stderr | 76 ----- tests/ui/wasm/wasm-import-module.stderr | 45 --- 32 files changed, 19 insertions(+), 1425 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 7bb55d2a6de5..2bbdb5c2590b 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -769,16 +769,20 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { diag.note(format!("for more information, visit <{link}>")); } - diag.span_suggestions( - self.attr_span, - if self.suggestions.len() == 1 { - "must be of the form".to_string() - } else { - format!("try changing it to one of the following valid forms of the {description}") - }, - self.suggestions, - Applicability::HasPlaceholders, - ); + if self.suggestions.len() < 4 { + diag.span_suggestions( + self.attr_span, + if self.suggestions.len() == 1 { + "must be of the form".to_string() + } else { + format!( + "try changing it to one of the following valid forms of the {description}" + ) + }, + self.suggestions, + Applicability::HasPlaceholders, + ); + } diag } diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index cd28677b6a8f..e69ed0eea6b0 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -198,6 +198,11 @@ fn emit_malformed_attribute( suggestions.push(format!("#{inner}[{name} = \"{descr}\"]")); } } + // If there are too many suggestions, better remove all of them as it's just noise at this + // point. + if suggestions.len() > 3 { + suggestions.clear(); + } if should_warn(name) { psess.buffer_lint( ILL_FORMED_ATTRIBUTE_INPUT, diff --git a/tests/rustdoc-ui/bad-render-options.stderr b/tests/rustdoc-ui/bad-render-options.stderr index 296a41337f33..28d4533a6edb 100644 --- a/tests/rustdoc-ui/bad-render-options.stderr +++ b/tests/rustdoc-ui/bad-render-options.stderr @@ -5,22 +5,6 @@ LL | #![doc(html_favicon_url)] | ^^^^^^^----------------^^ | | | expected this to be of the form `html_favicon_url = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_favicon_url)] -LL + #![doc = "string"] - | -LL - #![doc(html_favicon_url)] -LL + #![doc(alias)] - | -LL - #![doc(html_favicon_url)] -LL + #![doc(attribute)] - | -LL - #![doc(html_favicon_url)] -LL + #![doc(auto_cfg)] - | - = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:6:1 @@ -29,22 +13,6 @@ LL | #![doc(html_logo_url)] | ^^^^^^^-------------^^ | | | expected this to be of the form `html_logo_url = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_logo_url)] -LL + #![doc = "string"] - | -LL - #![doc(html_logo_url)] -LL + #![doc(alias)] - | -LL - #![doc(html_logo_url)] -LL + #![doc(attribute)] - | -LL - #![doc(html_logo_url)] -LL + #![doc(auto_cfg)] - | - = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:9:1 @@ -53,22 +21,6 @@ LL | #![doc(html_playground_url)] | ^^^^^^^-------------------^^ | | | expected this to be of the form `html_playground_url = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_playground_url)] -LL + #![doc = "string"] - | -LL - #![doc(html_playground_url)] -LL + #![doc(alias)] - | -LL - #![doc(html_playground_url)] -LL + #![doc(attribute)] - | -LL - #![doc(html_playground_url)] -LL + #![doc(auto_cfg)] - | - = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:12:1 @@ -77,22 +29,6 @@ LL | #![doc(issue_tracker_base_url)] | ^^^^^^^----------------------^^ | | | expected this to be of the form `issue_tracker_base_url = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(issue_tracker_base_url)] -LL + #![doc = "string"] - | -LL - #![doc(issue_tracker_base_url)] -LL + #![doc(alias)] - | -LL - #![doc(issue_tracker_base_url)] -LL + #![doc(attribute)] - | -LL - #![doc(issue_tracker_base_url)] -LL + #![doc(auto_cfg)] - | - = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:15:1 @@ -101,22 +37,6 @@ LL | #![doc(html_favicon_url = 1)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_favicon_url = 1)] -LL + #![doc = "string"] - | -LL - #![doc(html_favicon_url = 1)] -LL + #![doc(alias)] - | -LL - #![doc(html_favicon_url = 1)] -LL + #![doc(attribute)] - | -LL - #![doc(html_favicon_url = 1)] -LL + #![doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:18:1 @@ -125,22 +45,6 @@ LL | #![doc(html_logo_url = 2)] | ^^^^^^^^^^^^^^^^^^^^^^^-^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_logo_url = 2)] -LL + #![doc = "string"] - | -LL - #![doc(html_logo_url = 2)] -LL + #![doc(alias)] - | -LL - #![doc(html_logo_url = 2)] -LL + #![doc(attribute)] - | -LL - #![doc(html_logo_url = 2)] -LL + #![doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:21:1 @@ -149,22 +53,6 @@ LL | #![doc(html_playground_url = 3)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_playground_url = 3)] -LL + #![doc = "string"] - | -LL - #![doc(html_playground_url = 3)] -LL + #![doc(alias)] - | -LL - #![doc(html_playground_url = 3)] -LL + #![doc(attribute)] - | -LL - #![doc(html_playground_url = 3)] -LL + #![doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:24:1 @@ -173,22 +61,6 @@ LL | #![doc(issue_tracker_base_url = 4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc = "string"] - | -LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc(alias)] - | -LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc(attribute)] - | -LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc(auto_cfg)] - | - = and 22 other candidates error[E0565]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:27:1 @@ -197,22 +69,6 @@ LL | #![doc(html_no_source = "asdf")] | ^^^^^^^^^^^^^^^^^^^^^^--------^^ | | | didn't expect any arguments here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_no_source = "asdf")] -LL + #![doc = "string"] - | -LL - #![doc(html_no_source = "asdf")] -LL + #![doc(alias)] - | -LL - #![doc(html_no_source = "asdf")] -LL + #![doc(attribute)] - | -LL - #![doc(html_no_source = "asdf")] -LL + #![doc(auto_cfg)] - | - = and 22 other candidates error: aborting due to 9 previous errors diff --git a/tests/rustdoc-ui/check-doc-alias-attr.stderr b/tests/rustdoc-ui/check-doc-alias-attr.stderr index 6c33f10e8785..d9e785ee0f1f 100644 --- a/tests/rustdoc-ui/check-doc-alias-attr.stderr +++ b/tests/rustdoc-ui/check-doc-alias-attr.stderr @@ -11,22 +11,6 @@ LL | #[doc(alias = 0)] | ^^^^^^^^^^^^^^-^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(alias = 0)] -LL + #[doc = "string"] - | -LL - #[doc(alias = 0)] -LL + #[doc(alias)] - | -LL - #[doc(alias = 0)] -LL + #[doc(attribute)] - | -LL - #[doc(alias = 0)] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:9:15 @@ -79,22 +63,6 @@ LL | #[doc(alias(0))] | ^^^^^^^^^^^^-^^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(alias(0))] -LL + #[doc = "string"] - | -LL - #[doc(alias(0))] -LL + #[doc(alias)] - | -LL - #[doc(alias(0))] -LL + #[doc(attribute)] - | -LL - #[doc(alias(0))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:20:13 diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr index 0efeac66554c..ce16ec31d875 100644 --- a/tests/rustdoc-ui/doc-cfg.stderr +++ b/tests/rustdoc-ui/doc-cfg.stderr @@ -5,22 +5,6 @@ LL | #[doc(cfg(), cfg(foo, bar))] | ^^^^^^^^^--^^^^^^^^^^^^^^^^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:3:1 @@ -29,22 +13,6 @@ LL | #[doc(cfg(), cfg(foo, bar))] | ^^^^^^^^^^^^^^^^----------^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:6:1 @@ -53,22 +21,6 @@ LL | #[doc(cfg())] | ^^^^^^^^^--^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg())] -LL + #[doc = "string"] - | -LL - #[doc(cfg())] -LL + #[doc(alias)] - | -LL - #[doc(cfg())] -LL + #[doc(attribute)] - | -LL - #[doc(cfg())] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:7:1 @@ -77,22 +29,6 @@ LL | #[doc(cfg(foo, bar))] | ^^^^^^^^^----------^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(foo, bar))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(foo, bar))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(foo, bar))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(foo, bar))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:8:1 @@ -101,22 +37,6 @@ LL | #[doc(auto_cfg(hide(foo::bar)))] | ^^^^^^^^^^^^^^^^^^^^--------^^^^ | | | expected a valid identifier here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc = "string"] - | -LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc(alias)] - | -LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc(attribute)] - | -LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: aborting due to 5 previous errors diff --git a/tests/rustdoc-ui/invalid-cfg.stderr b/tests/rustdoc-ui/invalid-cfg.stderr index 3363dbb56fb4..84f8cea54314 100644 --- a/tests/rustdoc-ui/invalid-cfg.stderr +++ b/tests/rustdoc-ui/invalid-cfg.stderr @@ -3,22 +3,6 @@ error[E0539]: malformed `doc` attribute input | LL | #[doc(cfg = "x")] | ^^^^^^^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg = "x")] -LL + #[doc = "string"] - | -LL - #[doc(cfg = "x")] -LL + #[doc(alias)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(attribute)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:3:1 @@ -27,44 +11,12 @@ LL | #[doc(cfg(x, y))] | ^^^^^^^^^------^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(x, y))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:7:1 | LL | #[doc(cfg = "x")] | ^^^^^^^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg = "x")] -LL + #[doc = "string"] - | -LL - #[doc(cfg = "x")] -LL + #[doc(alias)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(attribute)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:8:1 @@ -73,44 +25,12 @@ LL | #[doc(cfg(x, y))] | ^^^^^^^^^------^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(x, y))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:12:1 | LL | #[doc(cfg = "x")] | ^^^^^^^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg = "x")] -LL + #[doc = "string"] - | -LL - #[doc(cfg = "x")] -LL + #[doc(alias)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(attribute)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:13:1 @@ -119,44 +39,12 @@ LL | #[doc(cfg(x, y))] | ^^^^^^^^^------^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(x, y))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:18:1 | LL | #[doc(cfg = "x")] | ^^^^^^^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg = "x")] -LL + #[doc = "string"] - | -LL - #[doc(cfg = "x")] -LL + #[doc(alias)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(attribute)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:19:1 @@ -165,22 +53,6 @@ LL | #[doc(cfg(x, y))] | ^^^^^^^^^------^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(x, y))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: aborting due to 8 previous errors diff --git a/tests/rustdoc-ui/lints/doc-attr.stderr b/tests/rustdoc-ui/lints/doc-attr.stderr index 1201bd5c71f1..8f8c6000b364 100644 --- a/tests/rustdoc-ui/lints/doc-attr.stderr +++ b/tests/rustdoc-ui/lints/doc-attr.stderr @@ -5,22 +5,6 @@ LL | #[doc(123)] | ^^^^^^---^^ | | | expected this to be of the form `... = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(123)] -LL + #[doc = "string"] - | -LL - #[doc(123)] -LL + #[doc(alias)] - | -LL - #[doc(123)] -LL + #[doc(attribute)] - | -LL - #[doc(123)] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-attr.rs:5:1 @@ -29,22 +13,6 @@ LL | #[doc("hello", "bar")] | ^^^^^^-------^^^^^^^^^ | | | expected this to be of the form `... = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc("hello", "bar")] -LL + #[doc = "string"] - | -LL - #[doc("hello", "bar")] -LL + #[doc(alias)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(attribute)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-attr.rs:5:1 @@ -53,22 +21,6 @@ LL | #[doc("hello", "bar")] | ^^^^^^^^^^^^^^^-----^^ | | | expected this to be of the form `... = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc("hello", "bar")] -LL + #[doc = "string"] - | -LL - #[doc("hello", "bar")] -LL + #[doc(alias)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(attribute)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: aborting due to 3 previous errors diff --git a/tests/ui/attributes/crate-type-delimited.stderr b/tests/ui/attributes/crate-type-delimited.stderr index 7f080f748386..23234efe169f 100644 --- a/tests/ui/attributes/crate-type-delimited.stderr +++ b/tests/ui/attributes/crate-type-delimited.stderr @@ -5,21 +5,7 @@ LL | #![crate_type(lib)] | ^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit -help: the following are the possible correct uses | -LL - #![crate_type(lib)] -LL + #![crate_type = "bin"] - | -LL - #![crate_type(lib)] -LL + #![crate_type = "cdylib"] - | -LL - #![crate_type(lib)] -LL + #![crate_type = "dylib"] - | -LL - #![crate_type(lib)] -LL + #![crate_type = "lib"] - | - = and 4 other candidates error: aborting due to 1 previous error diff --git a/tests/ui/attributes/crate-type-empty.stderr b/tests/ui/attributes/crate-type-empty.stderr index f50bb33d6bb0..c1d474d9f17f 100644 --- a/tests/ui/attributes/crate-type-empty.stderr +++ b/tests/ui/attributes/crate-type-empty.stderr @@ -5,17 +5,7 @@ LL | #![crate_type] | ^^^^^^^^^^^^^^ | = note: for more information, visit -help: the following are the possible correct uses | -LL | #![crate_type = "bin"] - | +++++++ -LL | #![crate_type = "cdylib"] - | ++++++++++ -LL | #![crate_type = "dylib"] - | +++++++++ -LL | #![crate_type = "lib"] - | +++++++ - = and 4 other candidates error: aborting due to 1 previous error diff --git a/tests/ui/attributes/crate-type-macro-call.stderr b/tests/ui/attributes/crate-type-macro-call.stderr index 97938f7af24e..cd17b324041b 100644 --- a/tests/ui/attributes/crate-type-macro-call.stderr +++ b/tests/ui/attributes/crate-type-macro-call.stderr @@ -5,21 +5,7 @@ LL | #![crate_type = foo!()] | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit -help: the following are the possible correct uses | -LL - #![crate_type = foo!()] -LL + #![crate_type = "bin"] - | -LL - #![crate_type = foo!()] -LL + #![crate_type = "cdylib"] - | -LL - #![crate_type = foo!()] -LL + #![crate_type = "dylib"] - | -LL - #![crate_type = foo!()] -LL + #![crate_type = "lib"] - | - = and 4 other candidates error: aborting due to 1 previous error diff --git a/tests/ui/attributes/doc-attr.stderr b/tests/ui/attributes/doc-attr.stderr index 9234c1a0719b..dfc0e8ad5b6f 100644 --- a/tests/ui/attributes/doc-attr.stderr +++ b/tests/ui/attributes/doc-attr.stderr @@ -5,22 +5,6 @@ LL | #[doc(123)] | ^^^^^^---^^ | | | expected this to be of the form `... = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(123)] -LL + #[doc = "string"] - | -LL - #[doc(123)] -LL + #[doc(alias)] - | -LL - #[doc(123)] -LL + #[doc(attribute)] - | -LL - #[doc(123)] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-attr.rs:11:1 @@ -29,22 +13,6 @@ LL | #[doc("hello", "bar")] | ^^^^^^-------^^^^^^^^^ | | | expected this to be of the form `... = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc("hello", "bar")] -LL + #[doc = "string"] - | -LL - #[doc("hello", "bar")] -LL + #[doc(alias)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(attribute)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-attr.rs:11:1 @@ -53,22 +21,6 @@ LL | #[doc("hello", "bar")] | ^^^^^^^^^^^^^^^-----^^ | | | expected this to be of the form `... = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc("hello", "bar")] -LL + #[doc = "string"] - | -LL - #[doc("hello", "bar")] -LL + #[doc(alias)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(attribute)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: unknown `doc` attribute `as_ptr` --> $DIR/doc-attr.rs:5:7 diff --git a/tests/ui/attributes/doc-test-literal.stderr b/tests/ui/attributes/doc-test-literal.stderr index 3ffbdcbb9fee..2d70d5d206f0 100644 --- a/tests/ui/attributes/doc-test-literal.stderr +++ b/tests/ui/attributes/doc-test-literal.stderr @@ -5,22 +5,6 @@ LL | #![doc(test(""))] | ^^^^^^^^^^^^--^^^ | | | didn't expect a literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(test(""))] -LL + #![doc = "string"] - | -LL - #![doc(test(""))] -LL + #![doc(alias)] - | -LL - #![doc(test(""))] -LL + #![doc(attribute)] - | -LL - #![doc(test(""))] -LL + #![doc(auto_cfg)] - | - = and 22 other candidates error: aborting due to 1 previous error diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index a6bd62fa1214..e1ebe4ac9eab 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -240,22 +240,6 @@ LL | #[deprecated = 5] | ^^^^^^^^^^^^^^^-^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated = 5] -LL + #[deprecated = "reason"] - | -LL - #[deprecated = 5] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated = 5] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated = 5] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error[E0539]: malformed `rustc_macro_transparency` attribute input --> $DIR/malformed-attrs.rs:44:1 @@ -287,17 +271,6 @@ LL | #[repr] | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[repr()] - | ++++++++++++++++ -LL | #[repr(C)] - | +++ -LL | #[repr(Rust)] - | ++++++ -LL | #[repr(align(...))] - | ++++++++++++ - = and 2 other candidates error[E0565]: malformed `rustc_as_ptr` attribute input --> $DIR/malformed-attrs.rs:50:1 @@ -437,17 +410,6 @@ LL | #[link] | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[link(name = "...")] - | ++++++++++++++ -LL | #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...")] - | +++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - = and 1 other candidate error[E0539]: malformed `link_name` attribute input --> $DIR/malformed-attrs.rs:88:1 @@ -483,18 +445,6 @@ error[E0539]: malformed `sanitize` attribute input | LL | #[sanitize] | ^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL | #[sanitize(address = "on|off")] - | ++++++++++++++++++++ -LL | #[sanitize(cfi = "on|off")] - | ++++++++++++++++ -LL | #[sanitize(hwaddress = "on|off")] - | ++++++++++++++++++++++ -LL | #[sanitize(kcfi = "on|off")] - | +++++++++++++++++ - = and 6 other candidates error[E0565]: malformed `no_implicit_prelude` attribute input --> $DIR/malformed-attrs.rs:101:1 @@ -634,18 +584,6 @@ error[E0539]: malformed `linkage` attribute input | LL | #[linkage] | ^^^^^^^^^^ expected this to be of the form `linkage = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL | #[linkage = "available_externally"] - | ++++++++++++++++++++++++ -LL | #[linkage = "common"] - | ++++++++++ -LL | #[linkage = "extern_weak"] - | +++++++++++++++ -LL | #[linkage = "external"] - | ++++++++++++ - = and 5 other candidates error[E0539]: malformed `debugger_visualizer` attribute input --> $DIR/malformed-attrs.rs:194:1 diff --git a/tests/ui/attributes/malformed-reprs.stderr b/tests/ui/attributes/malformed-reprs.stderr index 3a788999542b..504ba91aac5f 100644 --- a/tests/ui/attributes/malformed-reprs.stderr +++ b/tests/ui/attributes/malformed-reprs.stderr @@ -5,17 +5,6 @@ LL | #![repr] | ^^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #![repr()] - | ++++++++++++++++ -LL | #![repr(C)] - | +++ -LL | #![repr(Rust)] - | ++++++ -LL | #![repr(align(...))] - | ++++++++++++ - = and 2 other candidates error[E0589]: invalid `repr(align)` attribute: not a power of two --> $DIR/malformed-reprs.rs:9:14 diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr index 48d08b18f8bd..a96d4a0bdea8 100644 --- a/tests/ui/deprecation/deprecation-sanity.stderr +++ b/tests/ui/deprecation/deprecation-sanity.stderr @@ -11,22 +11,6 @@ LL | #[deprecated(since = "a", note)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^----^^ | | | expected this to be of the form `note = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated(since = "a", note)] -LL + #[deprecated = "reason"] - | -LL - #[deprecated(since = "a", note)] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated(since = "a", note)] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated(since = "a", note)] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error[E0539]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:12:5 @@ -35,22 +19,6 @@ LL | #[deprecated(since, note = "a")] | ^^^^^^^^^^^^^-----^^^^^^^^^^^^^^ | | | expected this to be of the form `since = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated(since, note = "a")] -LL + #[deprecated = "reason"] - | -LL - #[deprecated(since, note = "a")] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated(since, note = "a")] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated(since, note = "a")] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error[E0539]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:15:5 @@ -59,22 +27,6 @@ LL | #[deprecated(since = "a", note(b))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^ | | | expected this to be of the form `note = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated(since = "a", note(b))] -LL + #[deprecated = "reason"] - | -LL - #[deprecated(since = "a", note(b))] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated(since = "a", note(b))] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated(since = "a", note(b))] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error[E0539]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:18:5 @@ -83,22 +35,6 @@ LL | #[deprecated(since(b), note = "a")] | ^^^^^^^^^^^^^--------^^^^^^^^^^^^^^ | | | expected this to be of the form `since = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated(since(b), note = "a")] -LL + #[deprecated = "reason"] - | -LL - #[deprecated(since(b), note = "a")] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated(since(b), note = "a")] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated(since(b), note = "a")] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error[E0539]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:21:5 @@ -117,22 +53,6 @@ LL | #[deprecated("test")] | ^^^^^^^^^^^^^------^^ | | | didn't expect a literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated("test")] -LL + #[deprecated = "reason"] - | -LL - #[deprecated("test")] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated("test")] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated("test")] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error: multiple `deprecated` attributes --> $DIR/deprecation-sanity.rs:29:1 @@ -153,22 +73,6 @@ LL | #[deprecated(since = "a", since = "b", note = "c")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^^^^^^^ | | | found `since` used as a key more than once - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated(since = "a", since = "b", note = "c")] -LL + #[deprecated = "reason"] - | -LL - #[deprecated(since = "a", since = "b", note = "c")] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated(since = "a", since = "b", note = "c")] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated(since = "a", since = "b", note = "c")] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error: `#[deprecated]` attribute cannot be used on trait impl blocks --> $DIR/deprecation-sanity.rs:37:1 diff --git a/tests/ui/error-codes/E0458.stderr b/tests/ui/error-codes/E0458.stderr index 524765ea12a1..e56c9473d287 100644 --- a/tests/ui/error-codes/E0458.stderr +++ b/tests/ui/error-codes/E0458.stderr @@ -7,21 +7,6 @@ LL | #[link(kind = "wonderful_unicorn")] extern "C" {} | valid arguments are "static", "dylib", "framework", "raw-dylib" or "link-arg" | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(kind = "wonderful_unicorn")] extern "C" {} -LL + #[link(name = "...")] extern "C" {} - | -LL - #[link(kind = "wonderful_unicorn")] extern "C" {} -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] extern "C" {} - | -LL - #[link(kind = "wonderful_unicorn")] extern "C" {} -LL + #[link(name = "...", kind = "dylib|static|...")] extern "C" {} - | -LL - #[link(kind = "wonderful_unicorn")] extern "C" {} -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] extern "C" {} - | - = and 1 other candidate error[E0459]: `#[link]` attribute requires a `name = "string"` argument --> $DIR/E0458.rs:1:1 diff --git a/tests/ui/error-codes/E0565-1.stderr b/tests/ui/error-codes/E0565-1.stderr index 52daf2a62fcd..d1aff042e8fb 100644 --- a/tests/ui/error-codes/E0565-1.stderr +++ b/tests/ui/error-codes/E0565-1.stderr @@ -5,22 +5,6 @@ LL | #[deprecated("since")] | ^^^^^^^^^^^^^-------^^ | | | didn't expect a literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated("since")] -LL + #[deprecated = "reason"] - | -LL - #[deprecated("since")] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated("since")] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated("since")] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr index 0219eeb693e7..d393255e0ee1 100644 --- a/tests/ui/issues/issue-43988.stderr +++ b/tests/ui/issues/issue-43988.stderr @@ -60,17 +60,6 @@ LL | #[repr] | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[repr()] - | ++++++++++++++++ -LL | #[repr(C)] - | +++ -LL | #[repr(Rust)] - | ++++++ -LL | #[repr(align(...))] - | ++++++++++++ - = and 2 other candidates error[E0539]: malformed `inline` attribute input --> $DIR/issue-43988.rs:31:5 @@ -108,17 +97,6 @@ LL | let _z = #[repr] 1; | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | let _z = #[repr()] 1; - | ++++++++++++++++ -LL | let _z = #[repr(C)] 1; - | +++ -LL | let _z = #[repr(Rust)] 1; - | ++++++ -LL | let _z = #[repr(align(...))] 1; - | ++++++++++++ - = and 2 other candidates error: aborting due to 9 previous errors diff --git a/tests/ui/link-native-libs/issue-43925.stderr b/tests/ui/link-native-libs/issue-43925.stderr index 68a020546c14..fdc644ed6469 100644 --- a/tests/ui/link-native-libs/issue-43925.stderr +++ b/tests/ui/link-native-libs/issue-43925.stderr @@ -16,21 +16,6 @@ LL | #[link(name = "foo", cfg("rlib"))] | expected a valid identifier here | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "foo", cfg("rlib"))] -LL + #[link(name = "...")] - | -LL - #[link(name = "foo", cfg("rlib"))] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "foo", cfg("rlib"))] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "foo", cfg("rlib"))] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: aborting due to 2 previous errors diff --git a/tests/ui/link-native-libs/issue-43926.stderr b/tests/ui/link-native-libs/issue-43926.stderr index 9e3ec21cc945..f7b85788a2a3 100644 --- a/tests/ui/link-native-libs/issue-43926.stderr +++ b/tests/ui/link-native-libs/issue-43926.stderr @@ -7,21 +7,6 @@ LL | #[link(name = "foo", cfg())] | expected a single argument here | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "foo", cfg())] -LL + #[link(name = "...")] - | -LL - #[link(name = "foo", cfg())] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "foo", cfg())] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "foo", cfg())] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: aborting due to 1 previous error diff --git a/tests/ui/link-native-libs/link-attr-validation-early.stderr b/tests/ui/link-native-libs/link-attr-validation-early.stderr index e4799b1a1618..101df0371b54 100644 --- a/tests/ui/link-native-libs/link-attr-validation-early.stderr +++ b/tests/ui/link-native-libs/link-attr-validation-early.stderr @@ -5,17 +5,6 @@ LL | #[link] | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[link(name = "...")] - | ++++++++++++++ -LL | #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...")] - | +++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-early.rs:3:1 @@ -24,21 +13,6 @@ LL | #[link = "foo"] | ^^^^^^^^^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link = "foo"] -LL + #[link(name = "...")] - | -LL - #[link = "foo"] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link = "foo"] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link = "foo"] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: aborting due to 2 previous errors diff --git a/tests/ui/link-native-libs/link-attr-validation-late.stderr b/tests/ui/link-native-libs/link-attr-validation-late.stderr index 106b7cebc99f..a5f654ca0aeb 100644 --- a/tests/ui/link-native-libs/link-attr-validation-late.stderr +++ b/tests/ui/link-native-libs/link-attr-validation-late.stderr @@ -7,21 +7,6 @@ LL | #[link(name = "...", "literal")] | didn't expect a literal here | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", "literal")] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", "literal")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", "literal")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", "literal")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:5:1 @@ -32,21 +17,6 @@ LL | #[link(name = "...", unknown)] | valid arguments are "name", "kind", "modifiers", "cfg", "wasm_import_module" or "import_name_type" | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", unknown)] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", unknown)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", unknown)] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", unknown)] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0538]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:9:1 @@ -57,21 +27,6 @@ LL | #[link(name = "foo", name = "bar")] | found `name` used as a key more than once | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "foo", name = "bar")] -LL + #[link(name = "...")] - | -LL - #[link(name = "foo", name = "bar")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "foo", name = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "foo", name = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0538]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:10:1 @@ -82,21 +37,6 @@ LL | #[link(name = "...", kind = "dylib", kind = "bar")] | found `kind` used as a key more than once | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", kind = "dylib", kind = "bar")] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", kind = "dylib", kind = "bar")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", kind = "dylib", kind = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", kind = "dylib", kind = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0538]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:11:1 @@ -107,21 +47,6 @@ LL | #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] | found `modifiers` used as a key more than once | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0538]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:12:1 @@ -132,21 +57,6 @@ LL | #[link(name = "...", cfg(false), cfg(false))] | found `cfg` used as a key more than once | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", cfg(false), cfg(false))] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", cfg(false), cfg(false))] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", cfg(false), cfg(false))] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", cfg(false), cfg(false))] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0538]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:13:1 @@ -157,21 +67,6 @@ LL | #[link(wasm_import_module = "foo", wasm_import_module = "bar")] | found `wasm_import_module` used as a key more than once | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(wasm_import_module = "foo", wasm_import_module = "bar")] -LL + #[link(name = "...")] - | -LL - #[link(wasm_import_module = "foo", wasm_import_module = "bar")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(wasm_import_module = "foo", wasm_import_module = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(wasm_import_module = "foo", wasm_import_module = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:17:1 @@ -182,17 +77,6 @@ LL | #[link(name)] | expected this to be of the form `name = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[link(name = "...")] - | +++++++ -LL | #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...")] - | ++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:18:1 @@ -203,21 +87,6 @@ LL | #[link(name())] | expected this to be of the form `name = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name())] -LL + #[link(name = "...")] - | -LL - #[link(name())] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name())] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name())] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:19:1 @@ -228,19 +97,6 @@ LL | #[link(name = "...", kind)] | expected this to be of the form `kind = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", kind)] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", kind)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL | #[link(name = "...", kind = "dylib|static|...")] - | ++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:20:1 @@ -251,21 +107,6 @@ LL | #[link(name = "...", kind())] | expected this to be of the form `kind = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", kind())] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", kind())] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", kind())] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", kind())] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:21:1 @@ -276,21 +117,6 @@ LL | #[link(name = "...", modifiers)] | expected this to be of the form `modifiers = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", modifiers)] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", modifiers)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", modifiers)] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", modifiers)] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:22:1 @@ -301,21 +127,6 @@ LL | #[link(name = "...", modifiers())] | expected this to be of the form `modifiers = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", modifiers())] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", modifiers())] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", modifiers())] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", modifiers())] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:23:1 @@ -326,21 +137,6 @@ LL | #[link(name = "...", cfg)] | expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", cfg)] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", cfg)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", cfg)] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", cfg)] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:24:1 @@ -351,21 +147,6 @@ LL | #[link(name = "...", cfg = "literal")] | expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", cfg = "literal")] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", cfg = "literal")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", cfg = "literal")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", cfg = "literal")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:25:1 @@ -376,21 +157,6 @@ LL | #[link(name = "...", cfg("literal"))] | expected a valid identifier here | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", cfg("literal"))] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", cfg("literal"))] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", cfg("literal"))] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", cfg("literal"))] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:26:1 @@ -401,21 +167,6 @@ LL | #[link(name = "...", wasm_import_module)] | expected this to be of the form `wasm_import_module = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:27:1 @@ -426,21 +177,6 @@ LL | #[link(name = "...", wasm_import_module())] | expected this to be of the form `wasm_import_module = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed --> $DIR/link-attr-validation-late.rs:31:34 @@ -463,21 +199,6 @@ LL | #[link(name = "...", modifiers = "+unknown")] | valid arguments are "bundle", "verbatim", "whole-archive" or "as-needed" | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", modifiers = "+unknown")] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", modifiers = "+unknown")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", modifiers = "+unknown")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", modifiers = "+unknown")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: multiple `verbatim` modifiers in a single `modifiers` argument --> $DIR/link-attr-validation-late.rs:34:34 diff --git a/tests/ui/link-native-libs/modifiers-override-4.stderr b/tests/ui/link-native-libs/modifiers-override-4.stderr index 317e89cb39cc..12b0d89c79a7 100644 --- a/tests/ui/link-native-libs/modifiers-override-4.stderr +++ b/tests/ui/link-native-libs/modifiers-override-4.stderr @@ -12,49 +12,6 @@ LL | | )] | |__^ | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link( -LL - -LL - name = "bar", -LL - kind = "static", -LL - modifiers = "+whole-archive,-whole-archive", -LL - -LL - modifiers = "+bundle" -LL - )] -LL + #[link(name = "...")] - | -LL - #[link( -LL - -LL - name = "bar", -LL - kind = "static", -LL - modifiers = "+whole-archive,-whole-archive", -LL - -LL - modifiers = "+bundle" -LL - )] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link( -LL - -LL - name = "bar", -LL - kind = "static", -LL - modifiers = "+whole-archive,-whole-archive", -LL - -LL - modifiers = "+bundle" -LL - )] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link( -LL - -LL - name = "bar", -LL - kind = "static", -LL - modifiers = "+whole-archive,-whole-archive", -LL - -LL - modifiers = "+bundle" -LL - )] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: multiple `whole-archive` modifiers in a single `modifiers` argument --> $DIR/modifiers-override-4.rs:6:17 diff --git a/tests/ui/linkage-attr/linkage3.stderr b/tests/ui/linkage-attr/linkage3.stderr index f1215f09aeaf..564090e9538f 100644 --- a/tests/ui/linkage-attr/linkage3.stderr +++ b/tests/ui/linkage-attr/linkage3.stderr @@ -5,22 +5,6 @@ LL | #[linkage = "foo"] | ^^^^^^^^^^^^-----^ | | | valid arguments are `available_externally`, `common`, `extern_weak`, `external`, `internal`, `linkonce`, `linkonce_odr`, `weak` or `weak_odr` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[linkage = "foo"] -LL + #[linkage = "available_externally"] - | -LL - #[linkage = "foo"] -LL + #[linkage = "common"] - | -LL - #[linkage = "foo"] -LL + #[linkage = "extern_weak"] - | -LL - #[linkage = "foo"] -LL + #[linkage = "external"] - | - = and 5 other candidates error: aborting due to 1 previous error diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr index 6b54f3b247d1..86a53a030f50 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr @@ -7,21 +7,6 @@ LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] | expected this to be of the form `import_name_type = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] -LL + #[link(name = "...")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: aborting due to 1 previous error diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr index 35ddb2a7e3d3..ef909ad7278b 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr @@ -7,21 +7,6 @@ LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", im | found `import_name_type` used as a key more than once | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] -LL + #[link(name = "...")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: aborting due to 1 previous error diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr index b0099675dd23..577ec8e7764c 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr @@ -7,21 +7,6 @@ LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] | valid arguments are "decorated", "noprefix" or "undecorated" | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] -LL + #[link(name = "...")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: aborting due to 1 previous error diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr index 29734fd84e6b..f46afda1e477 100644 --- a/tests/ui/malformed/malformed-regressions.stderr +++ b/tests/ui/malformed/malformed-regressions.stderr @@ -5,17 +5,6 @@ LL | #[link] | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[link(name = "...")] - | ++++++++++++++ -LL | #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...")] - | +++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/malformed-regressions.rs:10:1 @@ -24,21 +13,6 @@ LL | #[link = ""] | ^^^^^^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link = ""] -LL + #[link(name = "...")] - | -LL - #[link = ""] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link = ""] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link = ""] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/malformed-regressions.rs:7:1 diff --git a/tests/ui/repr/repr.stderr b/tests/ui/repr/repr.stderr index d4faea125176..e8168f8f9a58 100644 --- a/tests/ui/repr/repr.stderr +++ b/tests/ui/repr/repr.stderr @@ -5,17 +5,6 @@ LL | #[repr] | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[repr()] - | ++++++++++++++++ -LL | #[repr(C)] - | +++ -LL | #[repr(Rust)] - | ++++++ -LL | #[repr(align(...))] - | ++++++++++++ - = and 2 other candidates error[E0539]: malformed `repr` attribute input --> $DIR/repr.rs:4:1 @@ -24,21 +13,6 @@ LL | #[repr = "B"] | ^^^^^^^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[repr = "B"] -LL + #[repr()] - | -LL - #[repr = "B"] -LL + #[repr(C)] - | -LL - #[repr = "B"] -LL + #[repr(Rust)] - | -LL - #[repr = "B"] -LL + #[repr(align(...))] - | - = and 2 other candidates error[E0539]: malformed `repr` attribute input --> $DIR/repr.rs:7:1 @@ -47,21 +21,6 @@ LL | #[repr = "C"] | ^^^^^^^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[repr = "C"] -LL + #[repr()] - | -LL - #[repr = "C"] -LL + #[repr(C)] - | -LL - #[repr = "C"] -LL + #[repr(Rust)] - | -LL - #[repr = "C"] -LL + #[repr(align(...))] - | - = and 2 other candidates error: aborting due to 3 previous errors diff --git a/tests/ui/rustdoc/check-doc-alias-attr.stderr b/tests/ui/rustdoc/check-doc-alias-attr.stderr index 6c33f10e8785..d9e785ee0f1f 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr.stderr +++ b/tests/ui/rustdoc/check-doc-alias-attr.stderr @@ -11,22 +11,6 @@ LL | #[doc(alias = 0)] | ^^^^^^^^^^^^^^-^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(alias = 0)] -LL + #[doc = "string"] - | -LL - #[doc(alias = 0)] -LL + #[doc(alias)] - | -LL - #[doc(alias = 0)] -LL + #[doc(attribute)] - | -LL - #[doc(alias = 0)] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:9:15 @@ -79,22 +63,6 @@ LL | #[doc(alias(0))] | ^^^^^^^^^^^^-^^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(alias(0))] -LL + #[doc = "string"] - | -LL - #[doc(alias(0))] -LL + #[doc(alias)] - | -LL - #[doc(alias(0))] -LL + #[doc(attribute)] - | -LL - #[doc(alias(0))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:20:13 diff --git a/tests/ui/sanitize-attr/invalid-sanitize.stderr b/tests/ui/sanitize-attr/invalid-sanitize.stderr index 9c1a6e5c4528..2a3497678bdc 100644 --- a/tests/ui/sanitize-attr/invalid-sanitize.stderr +++ b/tests/ui/sanitize-attr/invalid-sanitize.stderr @@ -5,22 +5,6 @@ LL | #[sanitize(brontosaurus = "off")] | ^^^^^^^^^^^------------^^^^^^^^^^ | | | valid arguments are "address", "cfi", "kcfi", "memory", "memtag", "shadow_call_stack", "thread", "hwaddress" or "realtime" - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[sanitize(brontosaurus = "off")] -LL + #[sanitize(address = "on|off")] - | -LL - #[sanitize(brontosaurus = "off")] -LL + #[sanitize(cfi = "on|off")] - | -LL - #[sanitize(brontosaurus = "off")] -LL + #[sanitize(hwaddress = "on|off")] - | -LL - #[sanitize(brontosaurus = "off")] -LL + #[sanitize(kcfi = "on|off")] - | - = and 6 other candidates error: multiple `sanitize` attributes --> $DIR/invalid-sanitize.rs:7:1 @@ -53,62 +37,18 @@ LL | #[sanitize(address = "bogus")] | ^^^^^^^^^^^^^^^^^^^^^-------^^ | | | valid arguments are "on" or "off" - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[sanitize(address = "bogus")] -LL + #[sanitize(address = "on|off")] - | -LL - #[sanitize(address = "bogus")] -LL + #[sanitize(cfi = "on|off")] - | -LL - #[sanitize(address = "bogus")] -LL + #[sanitize(hwaddress = "on|off")] - | -LL - #[sanitize(address = "bogus")] -LL + #[sanitize(kcfi = "on|off")] - | - = and 6 other candidates error[E0539]: malformed `sanitize` attribute input --> $DIR/invalid-sanitize.rs:18:1 | LL | #[sanitize = "off"] | ^^^^^^^^^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[sanitize = "off"] -LL + #[sanitize(address = "on|off")] - | -LL - #[sanitize = "off"] -LL + #[sanitize(cfi = "on|off")] - | -LL - #[sanitize = "off"] -LL + #[sanitize(hwaddress = "on|off")] - | -LL - #[sanitize = "off"] -LL + #[sanitize(kcfi = "on|off")] - | - = and 6 other candidates error[E0539]: malformed `sanitize` attribute input --> $DIR/invalid-sanitize.rs:21:1 | LL | #[sanitize] | ^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL | #[sanitize(address = "on|off")] - | ++++++++++++++++++++ -LL | #[sanitize(cfi = "on|off")] - | ++++++++++++++++ -LL | #[sanitize(hwaddress = "on|off")] - | ++++++++++++++++++++++ -LL | #[sanitize(kcfi = "on|off")] - | +++++++++++++++++ - = and 6 other candidates error[E0539]: malformed `sanitize` attribute input --> $DIR/invalid-sanitize.rs:24:1 @@ -117,22 +57,6 @@ LL | #[sanitize(realtime = "on")] | ^^^^^^^^^^^^^^^^^^^^^^----^^ | | | valid arguments are "nonblocking", "blocking" or "caller" - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[sanitize(realtime = "on")] -LL + #[sanitize(address = "on|off")] - | -LL - #[sanitize(realtime = "on")] -LL + #[sanitize(cfi = "on|off")] - | -LL - #[sanitize(realtime = "on")] -LL + #[sanitize(hwaddress = "on|off")] - | -LL - #[sanitize(realtime = "on")] -LL + #[sanitize(kcfi = "on|off")] - | - = and 6 other candidates warning: the async executor can run blocking code, without realtime sanitizer catching it --> $DIR/invalid-sanitize.rs:27:1 diff --git a/tests/ui/wasm/wasm-import-module.stderr b/tests/ui/wasm/wasm-import-module.stderr index f5ea449839bb..6171f04f862c 100644 --- a/tests/ui/wasm/wasm-import-module.stderr +++ b/tests/ui/wasm/wasm-import-module.stderr @@ -7,21 +7,6 @@ LL | #[link(name = "...", wasm_import_module)] | expected this to be of the form `wasm_import_module = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/wasm-import-module.rs:6:1 @@ -32,21 +17,6 @@ LL | #[link(name = "...", wasm_import_module(x))] | expected this to be of the form `wasm_import_module = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", wasm_import_module(x))] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", wasm_import_module(x))] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", wasm_import_module(x))] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", wasm_import_module(x))] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/wasm-import-module.rs:9:1 @@ -57,21 +27,6 @@ LL | #[link(name = "...", wasm_import_module())] | expected this to be of the form `wasm_import_module = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: `wasm_import_module` is incompatible with other arguments in `#[link]` attributes --> $DIR/wasm-import-module.rs:12:8 From acc3a0e2da38051690d45e8f2ad620baf4600015 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 19 Nov 2025 20:01:24 +0000 Subject: [PATCH 570/585] Syntactically distinguish anon const const args --- compiler/rustc_ast/src/ast.rs | 43 +++++---- compiler/rustc_ast/src/visit.rs | 1 + compiler/rustc_ast_lowering/src/expr.rs | 6 +- compiler/rustc_ast_lowering/src/lib.rs | 80 ++++++++++++++-- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_builtin_macros/src/autodiff.rs | 10 +- .../rustc_builtin_macros/src/pattern_type.rs | 18 +++- compiler/rustc_expand/src/build.rs | 5 +- compiler/rustc_parse/src/parser/asm.rs | 4 +- .../rustc_parse/src/parser/diagnostics.rs | 71 ++++++-------- compiler/rustc_parse/src/parser/expr.rs | 28 +++++- compiler/rustc_parse/src/parser/item.rs | 13 ++- compiler/rustc_parse/src/parser/mod.rs | 26 +++++- compiler/rustc_parse/src/parser/path.rs | 88 ++++++++++++++++-- compiler/rustc_parse/src/parser/ty.rs | 25 +++-- compiler/rustc_resolve/src/late.rs | 17 ++-- .../assoc-const-eq-ambiguity.rs | 2 +- .../assoc-const-eq-ambiguity.stderr | 8 +- .../assoc-const-eq-bound-var-in-ty-not-wf.rs | 2 +- ...soc-const-eq-bound-var-in-ty-not-wf.stderr | 12 +-- .../assoc-const-eq-bound-var-in-ty.rs | 2 +- .../assoc-const-eq-esc-bound-var-in-ty.rs | 2 +- .../assoc-const-eq-esc-bound-var-in-ty.stderr | 2 +- .../assoc-const-eq-param-in-ty.rs | 34 +++---- .../assoc-const-eq-param-in-ty.stderr | 63 +++++++------ tests/ui/associated-consts/assoc-const.rs | 4 +- tests/ui/associated-consts/issue-110933.rs | 2 +- .../const-projection-err.rs | 4 - ...gce.stderr => const-projection-err.stderr} | 8 +- .../duplicate-bound-err.rs | 4 +- .../duplicate-bound-err.stderr | 46 +++++----- .../associated-type-bounds/duplicate-bound.rs | 4 +- .../unconstrained_impl_param.rs | 2 +- .../unconstrained_impl_param.stderr | 6 +- .../mgca/explicit_anon_consts.rs | 70 ++++++++++++++ .../mgca/explicit_anon_consts.stderr | 92 +++++++++++++++++++ .../explicit_anon_consts_literals_hack.rs | 22 +++++ .../mgca/multi_braced_direct_const_args.rs | 25 +++++ .../mgca/type_const-not-constparamty.rs | 8 +- .../mgca/type_const-not-constparamty.stderr | 4 +- .../mgca/type_const-on-generic-expr.rs | 10 +- .../mgca/type_const-on-generic-expr.stderr | 30 +++--- .../unbraced_const_block_const_arg_gated.rs | 42 +++++++++ ...nbraced_const_block_const_arg_gated.stderr | 73 +++++++++++++++ .../mgca/using-fnptr-as-type_const.rs | 2 +- .../assoc-const-no-infer-ice-115806.rs | 4 +- .../assoc-const-no-infer-ice-115806.stderr | 4 +- .../associated-const-equality.rs | 2 +- 48 files changed, 779 insertions(+), 252 deletions(-) rename tests/ui/associated-type-bounds/{const-projection-err.gce.stderr => const-projection-err.stderr} (66%) create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts.rs create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts.stderr create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs create mode 100644 tests/ui/const-generics/mgca/multi_braced_direct_const_args.rs create mode 100644 tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs create mode 100644 tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e348cc1ab281..a2975935ef55 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -141,16 +141,11 @@ pub fn is_global(&self) -> bool { /// Check if this path is potentially a trivial const arg, i.e., one that can _potentially_ /// be represented without an anon const in the HIR. /// - /// If `allow_mgca_arg` is true (as should be the case in most situations when - /// `#![feature(min_generic_const_args)]` is enabled), then this always returns true - /// because all paths are valid. - /// - /// Otherwise, it returns true iff the path has exactly one segment, and it has no generic args + /// Returns true iff the path has exactly one segment, and it has no generic args /// (i.e., it is _potentially_ a const parameter). #[tracing::instrument(level = "debug", ret)] - pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool { - allow_mgca_arg - || self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none()) + pub fn is_potential_trivial_const_arg(&self) -> bool { + self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none()) } } @@ -1385,6 +1380,15 @@ pub enum UnsafeSource { UserProvided, } +/// Track whether under `feature(min_generic_const_args)` this anon const +/// was explicitly disambiguated as an anon const or not through the use of +/// `const { ... }` syntax. +#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Walkable)] +pub enum MgcaDisambiguation { + AnonConst, + Direct, +} + /// A constant (expression) that's not an item or associated item, /// but needs its own `DefId` for type-checking, const-eval, etc. /// These are usually found nested inside types (e.g., array lengths) @@ -1394,6 +1398,7 @@ pub enum UnsafeSource { pub struct AnonConst { pub id: NodeId, pub value: Box, + pub mgca_disambiguation: MgcaDisambiguation, } /// An expression. @@ -1412,26 +1417,20 @@ impl Expr { /// /// This will unwrap at most one block level (curly braces). After that, if the expression /// is a path, it mostly dispatches to [`Path::is_potential_trivial_const_arg`]. - /// See there for more info about `allow_mgca_arg`. /// - /// The only additional thing to note is that when `allow_mgca_arg` is false, this function - /// will only allow paths with no qself, before dispatching to the `Path` function of - /// the same name. + /// This function will only allow paths with no qself, before dispatching to the `Path` + /// function of the same name. /// /// Does not ensure that the path resolves to a const param/item, the caller should check this. /// This also does not consider macros, so it's only correct after macro-expansion. - pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool { + pub fn is_potential_trivial_const_arg(&self) -> bool { let this = self.maybe_unwrap_block(); - if allow_mgca_arg { - matches!(this.kind, ExprKind::Path(..)) + if let ExprKind::Path(None, path) = &this.kind + && path.is_potential_trivial_const_arg() + { + true } else { - if let ExprKind::Path(None, path) = &this.kind - && path.is_potential_trivial_const_arg(allow_mgca_arg) - { - true - } else { - false - } + false } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 7a0424d39575..49bff8fdd65d 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -415,6 +415,7 @@ pub fn ctxt(&self) -> Option { UnsafeBinderCastKind, BinOpKind, BlockCheckMode, + MgcaDisambiguation, BorrowKind, BoundAsyncness, BoundConstness, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 7230e1c42474..c8a311443a58 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -489,7 +489,11 @@ fn lower_legacy_const_generics( arg }; - let anon_const = AnonConst { id: node_id, value: const_value }; + let anon_const = AnonConst { + id: node_id, + value: const_value, + mgca_disambiguation: MgcaDisambiguation::AnonConst, + }; generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const))); } else { real_args.push(arg); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c20bbcca44f7..47a8f744820f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1219,7 +1219,7 @@ fn lower_generic_arg( .and_then(|partial_res| partial_res.full_res()) { if !res.matches_ns(Namespace::TypeNS) - && path.is_potential_trivial_const_arg(false) + && path.is_potential_trivial_const_arg() { debug!( "lower_generic_arg: Lowering type argument as const argument: {:?}", @@ -2287,11 +2287,9 @@ fn lower_const_path_to_const_arg( ) -> &'hir hir::ConstArg<'hir> { let tcx = self.tcx; - let ct_kind = if path - .is_potential_trivial_const_arg(tcx.features().min_generic_const_args()) - && (tcx.features().min_generic_const_args() - || matches!(res, Res::Def(DefKind::ConstParam, _))) - { + let is_trivial_path = path.is_potential_trivial_const_arg() + && matches!(res, Res::Def(DefKind::ConstParam, _)); + let ct_kind = if is_trivial_path || tcx.features().min_generic_const_args() { let qpath = self.lower_qpath( ty_id, &None, @@ -2370,6 +2368,53 @@ fn lower_const_item_rhs( } } + #[instrument(level = "debug", skip(self), ret)] + fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> { + let overly_complex_const = |this: &mut Self| { + let e = this.dcx().struct_span_err( + expr.span, + "complex const arguments must be placed inside of a `const` block", + ); + + ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(expr.span, e.emit()) } + }; + + match &expr.kind { + ExprKind::Path(qself, path) => { + let qpath = self.lower_qpath( + expr.id, + qself, + path, + ParamMode::Explicit, + AllowReturnTypeNotation::No, + // FIXME(mgca): update for `fn foo() -> Bar>` support + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) } + } + ExprKind::Underscore => ConstArg { + hir_id: self.lower_node_id(expr.id), + kind: hir::ConstArgKind::Infer(expr.span, ()), + }, + ExprKind::Block(block, _) => { + if let [stmt] = block.stmts.as_slice() + && let StmtKind::Expr(expr) = &stmt.kind + && matches!( + expr.kind, + ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..) + ) + { + return self.lower_expr_to_const_arg_direct(expr); + } + + overly_complex_const(self) + } + _ => overly_complex_const(self), + } + } + /// See [`hir::ConstArg`] for when to use this function vs /// [`Self::lower_anon_const_to_anon_const`]. fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> { @@ -2379,6 +2424,22 @@ fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::Cons #[instrument(level = "debug", skip(self))] fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> { let tcx = self.tcx; + + // We cannot change parsing depending on feature gates available, + // we can only require feature gates to be active as a delayed check. + // Thus we just parse anon consts generally and make the real decision + // making in ast lowering. + // FIXME(min_generic_const_args): revisit once stable + if tcx.features().min_generic_const_args() { + return match anon.mgca_disambiguation { + MgcaDisambiguation::AnonConst => { + let lowered_anon = self.lower_anon_const_to_anon_const(anon); + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) } + } + MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value), + }; + } + // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments // currently have to be wrapped in curly brackets, so it's necessary to special-case. let expr = if let ExprKind::Block(block, _) = &anon.value.kind @@ -2390,12 +2451,12 @@ fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::Con } else { &anon.value }; + let maybe_res = self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); if let ExprKind::Path(qself, path) = &expr.kind - && path.is_potential_trivial_const_arg(tcx.features().min_generic_const_args()) - && (tcx.features().min_generic_const_args() - || matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _)))) + && path.is_potential_trivial_const_arg() + && matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))) { let qpath = self.lower_qpath( expr.id, @@ -2403,7 +2464,6 @@ fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::Con path, ParamMode::Explicit, AllowReturnTypeNotation::No, - // FIXME(mgca): update for `fn foo() -> Bar>` support ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 88e9bbd71060..dbbd3906b525 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -517,6 +517,7 @@ macro_rules! gate_all { gate_all!(fn_delegation, "functions delegation is not yet fully implemented"); gate_all!(postfix_match, "postfix match is experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental"); + gate_all!(min_generic_const_args, "unbraced const blocks as const args are experimental"); gate_all!(global_registration, "global registration is experimental"); gate_all!(return_type_notation, "return type notation is experimental"); gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index ddc59bfe1414..9de70b8ced1d 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -17,7 +17,7 @@ mod llvm_enzyme { use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemKind, BindingMode, FnRetTy, FnSig, GenericArg, GenericArgs, GenericParamKind, Generics, ItemKind, - MetaItemInner, PatKind, Path, PathSegment, TyKind, Visibility, + MetaItemInner, MgcaDisambiguation, PatKind, Path, PathSegment, TyKind, Visibility, }; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Ident, Span, Symbol, sym}; @@ -558,7 +558,11 @@ fn gen_turbofish_expr( } GenericParamKind::Const { .. } => { let expr = ecx.expr_path(ast::Path::from_ident(p.ident)); - let anon_const = AnonConst { id: ast::DUMMY_NODE_ID, value: expr }; + let anon_const = AnonConst { + id: ast::DUMMY_NODE_ID, + value: expr, + mgca_disambiguation: MgcaDisambiguation::Direct, + }; Some(AngleBracketedArg::Arg(GenericArg::Const(anon_const))) } GenericParamKind::Lifetime { .. } => None, @@ -813,6 +817,7 @@ fn gen_enzyme_decl( let anon_const = rustc_ast::AnonConst { id: ast::DUMMY_NODE_ID, value: ecx.expr_usize(span, 1 + x.width as usize), + mgca_disambiguation: MgcaDisambiguation::Direct, }; TyKind::Array(ty.clone(), anon_const) }; @@ -827,6 +832,7 @@ fn gen_enzyme_decl( let anon_const = rustc_ast::AnonConst { id: ast::DUMMY_NODE_ID, value: ecx.expr_usize(span, x.width as usize), + mgca_disambiguation: MgcaDisambiguation::Direct, }; let kind = TyKind::Array(ty.clone(), anon_const); let ty = diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index 87a5a440140e..4126547b0515 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -1,5 +1,5 @@ use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast, token}; +use rustc_ast::{AnonConst, DUMMY_NODE_ID, MgcaDisambiguation, Ty, TyPat, TyPatKind, ast, token}; use rustc_errors::PResult; use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_parse::exp; @@ -60,8 +60,20 @@ fn ty_pat(kind: TyPatKind, span: Span) -> TyPat { fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> TyPat { let kind = match pat.kind { ast::PatKind::Range(start, end, include_end) => TyPatKind::Range( - start.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })), - end.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })), + start.map(|value| { + Box::new(AnonConst { + id: DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + }) + }), + end.map(|value| { + Box::new(AnonConst { + id: DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + }) + }), include_end, ), ast::PatKind::Or(variants) => { diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 6be65b0fff16..e5c06889f3e0 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -2,8 +2,8 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::literal; use rustc_ast::{ - self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, - UnOp, attr, token, tokenstream, + self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, + MgcaDisambiguation, PatKind, UnOp, attr, token, tokenstream, }; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; @@ -101,6 +101,7 @@ pub fn anon_const(&self, span: Span, kind: ast::ExprKind) -> ast::AnonConst { attrs: AttrVec::new(), tokens: None, }), + mgca_disambiguation: MgcaDisambiguation::Direct, } } diff --git a/compiler/rustc_parse/src/parser/asm.rs b/compiler/rustc_parse/src/parser/asm.rs index 41c3b0f0b676..caec877232a6 100644 --- a/compiler/rustc_parse/src/parser/asm.rs +++ b/compiler/rustc_parse/src/parser/asm.rs @@ -1,4 +1,4 @@ -use rustc_ast::{self as ast, AsmMacro}; +use rustc_ast::{self as ast, AsmMacro, MgcaDisambiguation}; use rustc_span::{Span, Symbol, kw}; use super::{ExpKeywordPair, ForceCollect, IdentIsRaw, Trailing, UsePreAttrPos}; @@ -149,7 +149,7 @@ fn parse_asm_operand<'a>( let block = p.parse_block()?; ast::InlineAsmOperand::Label { block } } else if p.eat_keyword(exp!(Const)) { - let anon_const = p.parse_expr_anon_const()?; + let anon_const = p.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; ast::InlineAsmOperand::Const { anon_const } } else if p.eat_keyword(exp!(Sym)) { let expr = p.parse_expr()?; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 4f6860fead8d..d7d343ac16b4 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -6,8 +6,8 @@ use rustc_ast::util::parser::AssocOp; use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, - Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, - PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, + Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, + MgcaDisambiguation, Param, Pat, PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -31,16 +31,15 @@ AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType, AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, - ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, - DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, - GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, - HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait, - IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody, - QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, - StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, - TernaryOperator, TernaryOperatorSuggestion, UnexpectedConstInGenericParam, - UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, - UseEqInstead, WrapType, + DocCommentDoesNotDocumentAnything, DocCommentOnParamType, DoubleColonInBound, + ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, + GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, HelpUseLatestEdition, + InInTypo, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, + PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, + StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, + SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, TernaryOperatorSuggestion, + UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, + UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType, }; use crate::parser::FnContext; use crate::parser::attr::InnerAttrPolicy; @@ -2558,36 +2557,6 @@ pub(super) fn handle_ambiguous_unbraced_const_arg( Ok(false) // Don't continue. } - /// Attempt to parse a generic const argument that has not been enclosed in braces. - /// There are a limited number of expressions that are permitted without being encoded - /// in braces: - /// - Literals. - /// - Single-segment paths (i.e. standalone generic const parameters). - /// All other expressions that can be parsed will emit an error suggesting the expression be - /// wrapped in braces. - pub(super) fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, Box> { - let start = self.token.span; - let attrs = self.parse_outer_attributes()?; - let (expr, _) = - self.parse_expr_res(Restrictions::CONST_EXPR, attrs).map_err(|mut err| { - err.span_label( - start.shrink_to_lo(), - "while parsing a const generic argument starting here", - ); - err - })?; - if !self.expr_is_valid_const_arg(&expr) { - self.dcx().emit_err(ConstGenericWithoutBraces { - span: expr.span, - sugg: ConstGenericWithoutBracesSugg { - left: expr.span.shrink_to_lo(), - right: expr.span.shrink_to_hi(), - }, - }); - } - Ok(expr) - } - fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option { let snapshot = self.create_snapshot_for_diagnostic(); let param = match self.parse_const_param(AttrVec::new()) { @@ -2623,7 +2592,11 @@ fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg }); let value = self.mk_expr_err(param.span(), guar); - Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })) + Some(GenericArg::Const(AnonConst { + id: ast::DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + })) } pub(super) fn recover_const_param_declaration( @@ -2707,7 +2680,11 @@ pub(super) fn recover_const_arg( ); let guar = err.emit(); let value = self.mk_expr_err(start.to(expr.span), guar); - return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })); + return Ok(GenericArg::Const(AnonConst { + id: ast::DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + })); } else if snapshot.token == token::Colon && expr.span.lo() == snapshot.token.span.hi() && matches!(expr.kind, ExprKind::Path(..)) @@ -2776,7 +2753,11 @@ pub(super) fn dummy_const_arg_needs_braces(&self, mut err: Diag<'a>, span: Span) ); let guar = err.emit(); let value = self.mk_expr_err(span, guar); - GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }) + GenericArg::Const(AnonConst { + id: ast::DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + }) } /// Some special error handling for the "top-level" patterns in a match arm, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index fa5e61d24d91..3f0853a3c54d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -15,8 +15,8 @@ use rustc_ast::{ self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, - FnRetTy, Label, MacCall, MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, - UnOp, UnsafeBinderCastKind, YieldKind, + FnRetTy, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param, RangeLimits, + StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind, }; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic}; @@ -85,8 +85,15 @@ pub fn parse_expr_force_collect(&mut self) -> PResult<'a, Box> { ) } - pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> { - self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value }) + pub fn parse_expr_anon_const( + &mut self, + mgca_disambiguation: impl FnOnce(&Self, &Expr) -> MgcaDisambiguation, + ) -> PResult<'a, AnonConst> { + self.parse_expr().map(|value| AnonConst { + id: DUMMY_NODE_ID, + mgca_disambiguation: mgca_disambiguation(self, &value), + value, + }) } fn parse_expr_catch_underscore( @@ -1615,7 +1622,18 @@ fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair) -> PResult<'a, Box let first_expr = self.parse_expr()?; if self.eat(exp!(Semi)) { // Repeating array syntax: `[ 0; 512 ]` - let count = self.parse_expr_anon_const()?; + let count = if self.token.is_keyword(kw::Const) + && self.look_ahead(1, |t| *t == token::OpenBrace) + { + // While we could just disambiguate `Direct` from `AnonConst` by + // treating all const block exprs as `AnonConst`, that would + // complicate the DefCollector and likely all other visitors. + // So we strip the const blockiness and just store it as a block + // in the AST with the extra disambiguator on the AnonConst + self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)? + } else { + self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))? + }; self.expect(close)?; ExprKind::Repeat(first_expr, count) } else if self.eat(exp!(Comma)) { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index abc0ffa87d3d..b4ce30767cb8 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1431,7 +1431,7 @@ fn parse_const_item( let rhs = if self.eat(exp!(Eq)) { if attr::contains_name(attrs, sym::type_const) { - Some(ConstItemRhs::TypeConst(self.parse_expr_anon_const()?)) + Some(ConstItemRhs::TypeConst(self.parse_const_arg()?)) } else { Some(ConstItemRhs::Body(self.parse_expr()?)) } @@ -1650,8 +1650,11 @@ fn parse_enum_variant(&mut self, span: Span) -> PResult<'a, Option> { VariantData::Unit(DUMMY_NODE_ID) }; - let disr_expr = - if this.eat(exp!(Eq)) { Some(this.parse_expr_anon_const()?) } else { None }; + let disr_expr = if this.eat(exp!(Eq)) { + Some(this.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?) + } else { + None + }; let vr = ast::Variant { ident, @@ -1864,7 +1867,7 @@ pub(super) fn parse_tuple_struct_body(&mut self) -> PResult<'a, ThinVec { let sp = ty.span.shrink_to_hi().to(const_expr.value.span); p.psess.gated_spans.gate(sym::default_field_values, sp); @@ -2066,7 +2069,7 @@ fn parse_name_and_ty( } let default = if self.token == token::Eq { self.bump(); - let const_expr = self.parse_expr_anon_const()?; + let const_expr = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; let sp = ty.span.shrink_to_hi().to(const_expr.value.span); self.psess.gated_spans.gate(sym::default_field_values, sp); Some(const_expr) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 8577ea40589a..c86d586e4783 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -35,9 +35,9 @@ }; use rustc_ast::util::case::Case; use rustc_ast::{ - self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID, - DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, - Visibility, VisibilityKind, + self as ast, AnonConst, AttrArgs, AttrId, BlockCheckMode, ByRef, Const, CoroutineKind, + DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, MgcaDisambiguation, + Mutability, Recovered, Safety, StrLit, Visibility, VisibilityKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; @@ -727,7 +727,10 @@ fn check_type(&mut self) -> bool { } fn check_const_arg(&mut self) -> bool { - self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) + let is_mcg_arg = self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const); + let is_mgca_arg = self.is_keyword_ahead(0, &[kw::Const]) + && self.look_ahead(1, |t| *t == token::OpenBrace); + is_mcg_arg || is_mgca_arg } fn check_const_closure(&self) -> bool { @@ -1299,6 +1302,20 @@ fn parse_constness_(&mut self, case: Case, is_closure: bool) -> Const { } } + fn parse_mgca_const_block(&mut self, gate_syntax: bool) -> PResult<'a, AnonConst> { + self.expect_keyword(exp!(Const))?; + let kw_span = self.token.span; + let value = self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?; + if gate_syntax { + self.psess.gated_spans.gate(sym::min_generic_const_args, kw_span.to(value.span)); + } + Ok(AnonConst { + id: ast::DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::AnonConst, + }) + } + /// Parses inline const expressions. fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, Box> { self.expect_keyword(exp!(Const))?; @@ -1306,6 +1323,7 @@ fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, Box> let anon_const = AnonConst { id: DUMMY_NODE_ID, value: self.mk_expr(blk.span, ExprKind::Block(blk, None)), + mgca_disambiguation: MgcaDisambiguation::AnonConst, }; let blk_span = anon_const.value.span; let kind = if pat { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 437f6da67b74..ce9e9c73669e 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -4,8 +4,8 @@ use rustc_ast::token::{self, MetaVarKind, Token, TokenKind}; use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint, - AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, - Path, PathSegment, QSelf, + AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, MgcaDisambiguation, + ParenthesizedArgs, Path, PathSegment, QSelf, }; use rustc_errors::{Applicability, Diag, PResult}; use rustc_span::{BytePos, Ident, Span, kw, sym}; @@ -16,12 +16,13 @@ use super::{Parser, Restrictions, TokenType}; use crate::ast::{PatKind, TyKind}; use crate::errors::{ - self, AttributeOnEmptyType, AttributeOnGenericArg, FnPathFoundNamedParams, - PathFoundAttributeInParams, PathFoundCVariadicParams, PathSingleColon, PathTripleColon, + self, AttributeOnEmptyType, AttributeOnGenericArg, ConstGenericWithoutBraces, + ConstGenericWithoutBracesSugg, FnPathFoundNamedParams, PathFoundAttributeInParams, + PathFoundCVariadicParams, PathSingleColon, PathTripleColon, }; use crate::exp; use crate::parser::{ - CommaRecoveryMode, ExprKind, FnContext, FnParseMode, RecoverColon, RecoverComma, + CommaRecoveryMode, Expr, ExprKind, FnContext, FnParseMode, RecoverColon, RecoverComma, }; /// Specifies how to parse a path. @@ -870,12 +871,75 @@ pub(super) fn expr_is_valid_const_arg(&self, expr: &Box) -> boo /// the caller. pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> { // Parse const argument. - let value = if self.token.kind == token::OpenBrace { - self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)? + let (value, mgca_disambiguation) = if self.token.kind == token::OpenBrace { + let value = self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?; + (value, MgcaDisambiguation::Direct) + } else if self.token.is_keyword(kw::Const) { + // While we could just disambiguate `Direct` from `AnonConst` by + // treating all const block exprs as `AnonConst`, that would + // complicate the DefCollector and likely all other visitors. + // So we strip the const blockiness and just store it as a block + // in the AST with the extra disambiguator on the AnonConst + let value = self.parse_mgca_const_block(true)?; + (value.value, MgcaDisambiguation::AnonConst) } else { - self.handle_unambiguous_unbraced_const_arg()? + self.parse_unambiguous_unbraced_const_arg()? }; - Ok(AnonConst { id: ast::DUMMY_NODE_ID, value }) + Ok(AnonConst { id: ast::DUMMY_NODE_ID, value, mgca_disambiguation }) + } + + /// Attempt to parse a const argument that has not been enclosed in braces. + /// There are a limited number of expressions that are permitted without being + /// enclosed in braces: + /// - Literals. + /// - Single-segment paths (i.e. standalone generic const parameters). + /// All other expressions that can be parsed will emit an error suggesting the expression be + /// wrapped in braces. + pub(super) fn parse_unambiguous_unbraced_const_arg( + &mut self, + ) -> PResult<'a, (Box, MgcaDisambiguation)> { + let start = self.token.span; + let attrs = self.parse_outer_attributes()?; + let (expr, _) = + self.parse_expr_res(Restrictions::CONST_EXPR, attrs).map_err(|mut err| { + err.span_label( + start.shrink_to_lo(), + "while parsing a const generic argument starting here", + ); + err + })?; + if !self.expr_is_valid_const_arg(&expr) { + self.dcx().emit_err(ConstGenericWithoutBraces { + span: expr.span, + sugg: ConstGenericWithoutBracesSugg { + left: expr.span.shrink_to_lo(), + right: expr.span.shrink_to_hi(), + }, + }); + } + + let mgca_disambiguation = self.mgca_direct_lit_hack(&expr); + Ok((expr, mgca_disambiguation)) + } + + /// Under `min_generic_const_args` we still allow *some* anon consts to be written without + /// a `const` block as it makes things quite a lot nicer. This function is useful for contexts + /// where we would like to use `MgcaDisambiguation::Direct` but need to fudge it to be `AnonConst` + /// in the presence of literals. + // + /// FIXME(min_generic_const_args): In the long term it would be nice to have a way to directly + /// represent literals in `hir::ConstArgKind` so that we can remove this special case by not + /// needing an anon const. + pub fn mgca_direct_lit_hack(&self, expr: &Expr) -> MgcaDisambiguation { + match &expr.kind { + ast::ExprKind::Lit(_) => MgcaDisambiguation::AnonConst, + ast::ExprKind::Unary(ast::UnOp::Neg, expr) + if matches!(expr.kind, ast::ExprKind::Lit(_)) => + { + MgcaDisambiguation::AnonConst + } + _ => MgcaDisambiguation::Direct, + } } /// Parse a generic argument in a path segment. @@ -976,7 +1040,11 @@ pub(super) fn parse_generic_arg( GenericArg::Type(_) => GenericArg::Type(self.mk_ty(attr_span, TyKind::Err(guar))), GenericArg::Const(_) => { let error_expr = self.mk_expr(attr_span, ExprKind::Err(guar)); - GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: error_expr }) + GenericArg::Const(AnonConst { + id: ast::DUMMY_NODE_ID, + value: error_expr, + mgca_disambiguation: MgcaDisambiguation::Direct, + }) } GenericArg::Lifetime(lt) => GenericArg::Lifetime(lt), })); diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index c79b99a80e87..676514344586 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -2,9 +2,9 @@ use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnPtrTy, FnRetTy, - GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, - Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, - TyKind, UnsafeBinderTy, + GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MgcaDisambiguation, + MutTy, Mutability, Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, + TraitObjectSyntax, Ty, TyKind, UnsafeBinderTy, }; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, E0516, PResult}; @@ -658,7 +658,19 @@ fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> { }; let ty = if self.eat(exp!(Semi)) { - let mut length = self.parse_expr_anon_const()?; + let mut length = if self.token.is_keyword(kw::Const) + && self.look_ahead(1, |t| *t == token::OpenBrace) + { + // While we could just disambiguate `Direct` from `AnonConst` by + // treating all const block exprs as `AnonConst`, that would + // complicate the DefCollector and likely all other visitors. + // So we strip the const blockiness and just store it as a block + // in the AST with the extra disambiguator on the AnonConst + self.parse_mgca_const_block(false)? + } else { + self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))? + }; + if let Err(e) = self.expect(exp!(CloseBracket)) { // Try to recover from `X` when `X::` works self.check_mistyped_turbofish_with_multiple_type_params(e, &mut length.value)?; @@ -699,8 +711,9 @@ fn maybe_recover_array_ty_without_semi(&mut self, elt_ty: Box) -> PResult<'a _ = self.eat(exp!(Comma)) || self.eat(exp!(Colon)) || self.eat(exp!(Star)); let suggestion_span = self.prev_token.span.with_lo(hi); + // FIXME(mgca): recovery is broken for `const {` args // we first try to parse pattern like `[u8 5]` - let length = match self.parse_expr_anon_const() { + let length = match self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct) { Ok(length) => length, Err(e) => { e.cancel(); @@ -788,7 +801,7 @@ pub(crate) fn parse_pin_and_mut(&mut self) -> (Pinnedness, Mutability) { /// an error type. fn parse_typeof_ty(&mut self, lo: Span) -> PResult<'a, TyKind> { self.expect(exp!(OpenParen))?; - let _expr = self.parse_expr_anon_const()?; + let _expr = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; self.expect(exp!(CloseParen))?; let span = lo.to(self.prev_token.span); let guar = self diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f1a03d5a0610..50e11fdde568 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1222,7 +1222,7 @@ fn visit_generic_arg(&mut self, arg: &'ast GenericArg) { if let TyKind::Path(None, ref path) = ty.kind // We cannot disambiguate multi-segment paths right now as that requires type // checking. - && path.is_potential_trivial_const_arg(false) + && path.is_potential_trivial_const_arg() { let mut check_ns = |ns| { self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns) @@ -4840,9 +4840,12 @@ fn resolve_anon_const(&mut self, constant: &'ast AnonConst, anon_const_kind: Ano constant, anon_const_kind ); - let is_trivial_const_arg = constant - .value - .is_potential_trivial_const_arg(self.r.tcx.features().min_generic_const_args()); + let is_trivial_const_arg = if self.r.tcx.features().min_generic_const_args() { + matches!(constant.mgca_disambiguation, MgcaDisambiguation::Direct) + } else { + constant.value.is_potential_trivial_const_arg() + }; + self.resolve_anon_const_manual(is_trivial_const_arg, anon_const_kind, |this| { this.resolve_expr(&constant.value, None) }) @@ -5023,9 +5026,9 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) { // Constant arguments need to be treated as AnonConst since // that is how they will be later lowered to HIR. if const_args.contains(&idx) { - let is_trivial_const_arg = argument.is_potential_trivial_const_arg( - self.r.tcx.features().min_generic_const_args(), - ); + // FIXME(mgca): legacy const generics doesn't support mgca but maybe + // that's okay. + let is_trivial_const_arg = argument.is_potential_trivial_const_arg(); self.resolve_anon_const_manual( is_trivial_const_arg, AnonConstKind::ConstArg(IsRepeatExpr::No), diff --git a/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs b/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs index 2ff5a0353a0a..27261a4806eb 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs +++ b/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs @@ -10,7 +10,7 @@ trait Parent0 { const K: (); } -fn take0(_: impl Trait0) {} +fn take0(_: impl Trait0) {} //~^ ERROR ambiguous associated constant `K` in bounds of `Trait0` trait Trait1: Parent1 + Parent2 {} diff --git a/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr b/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr index 3541664d1c6a..9ab39e6b8a60 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr @@ -7,14 +7,14 @@ LL | const K: (); | ambiguous `K` from `Parent0` | ambiguous `K` from `Parent0` ... -LL | fn take0(_: impl Trait0) {} - | ^^^^^^^^^^ ambiguous associated constant `K` +LL | fn take0(_: impl Trait0) {} + | ^^^^^^^^^^^^^ ambiguous associated constant `K` | = help: consider introducing a new type parameter `T` and adding `where` constraints: where T: Trait0, - T: Parent0::K = { () }, - T: Parent0::K = { () } + T: Parent0::K = { }, + T: Parent0::K = { } error[E0222]: ambiguous associated constant `C` in bounds of `Trait1` --> $DIR/assoc-const-eq-ambiguity.rs:26:25 diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs index 8334e67ae9a1..7f8b3036c3e8 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs @@ -18,7 +18,7 @@ trait Trait { fn take( _: impl Trait< < fn(&'a str) -> &'a str as Project>::Out as Discard>::Out, - K = { () } + K = const { () } >, ) {} //~^^^ ERROR higher-ranked subtype error diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr index 9fac60763dae..4a4c2b285829 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr @@ -1,14 +1,14 @@ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:19 | -LL | K = { () } - | ^^^^^^ +LL | K = const { () } + | ^^^^^^ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:19 | -LL | K = { () } - | ^^^^^^ +LL | K = const { () } + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs index ef8077b9f44a..d3975bc19ad3 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs @@ -21,7 +21,7 @@ trait Trait { fn take( _: impl Trait< fn(&'a str) -> &'a str as Discard>::Out, - K = { () } + K = const { } >, ) {} diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs index 1ab93ea596a7..2571af57e66b 100644 --- a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs @@ -8,7 +8,7 @@ trait Trait<'a> { const K: &'a (); } -fn take(_: impl for<'r> Trait<'r, K = { &() }>) {} +fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {} //~^ ERROR the type of the associated constant `K` cannot capture late-bound generic parameters //~| NOTE its type cannot capture the late-bound lifetime parameter `'r` //~| NOTE the late-bound lifetime parameter `'r` is defined here diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr index d6a7eb6cfc7d..44304443ac54 100644 --- a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr @@ -1,7 +1,7 @@ error: the type of the associated constant `K` cannot capture late-bound generic parameters --> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:11:35 | -LL | fn take(_: impl for<'r> Trait<'r, K = { &() }>) {} +LL | fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {} | -- ^ its type cannot capture the late-bound lifetime parameter `'r` | | | the late-bound lifetime parameter `'r` is defined here diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs index 0afb95a0b033..242ad385947a 100644 --- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs @@ -15,31 +15,33 @@ trait Trait<'a, T: 'a + ConstParamTy_, const N: usize> { const K: &'a [T; N]; } -fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} -//~^ ERROR the type of the associated constant `K` must not depend on generic parameters -//~| NOTE its type must not depend on the lifetime parameter `'r` -//~| NOTE the lifetime parameter `'r` is defined here -//~| NOTE `K` has type `&'r [A; Q]` -//~| ERROR the type of the associated constant `K` must not depend on generic parameters -//~| NOTE its type must not depend on the type parameter `A` -//~| NOTE the type parameter `A` is defined here -//~| NOTE `K` has type `&'r [A; Q]` -//~| ERROR the type of the associated constant `K` must not depend on generic parameters -//~| NOTE its type must not depend on the const parameter `Q` -//~| NOTE the const parameter `Q` is defined here -//~| NOTE `K` has type `&'r [A; Q]` +fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( + //~^ NOTE the lifetime parameter `'r` is defined here + //~| NOTE the type parameter `A` is defined here + //~| NOTE the const parameter `Q` is defined here + _: impl Trait<'r, A, Q, K = const { loop {} }> + //~^ ERROR the type of the associated constant `K` must not depend on generic parameters + //~| NOTE its type must not depend on the lifetime parameter `'r` + //~| NOTE `K` has type `&'r [A; Q]` + //~| ERROR the type of the associated constant `K` must not depend on generic parameters + //~| NOTE its type must not depend on the type parameter `A` + //~| NOTE `K` has type `&'r [A; Q]` + //~| ERROR the type of the associated constant `K` must not depend on generic parameters + //~| NOTE its type must not depend on the const parameter `Q` + //~| NOTE `K` has type `&'r [A; Q]` +) {} trait Project: ConstParamTy_ { #[type_const] const SELF: Self; } -fn take1(_: impl Project) {} +fn take1(_: impl Project) {} //~^ ERROR the type of the associated constant `SELF` must not depend on `impl Trait` //~| NOTE its type must not depend on `impl Trait` //~| NOTE the `impl Trait` is specified here -fn take2>(_: P) {} +fn take2>(_: P) {} //~^ ERROR the type of the associated constant `SELF` must not depend on generic parameters //~| NOTE its type must not depend on the type parameter `P` //~| NOTE the type parameter `P` is defined here @@ -48,7 +50,7 @@ fn take2>(_: P) {} trait Iface<'r>: ConstParamTy_ { //~^ NOTE the lifetime parameter `'r` is defined here //~| NOTE the lifetime parameter `'r` is defined here - type Assoc: Trait<'r, Self, Q, K = { loop {} }> + type Assoc: Trait<'r, Self, Q, K = const { loop {} }> //~^ ERROR the type of the associated constant `K` must not depend on generic parameters //~| ERROR the type of the associated constant `K` must not depend on generic parameters //~| NOTE its type must not depend on the lifetime parameter `'r` diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr index 229dd10c0beb..b742e68044b0 100644 --- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr @@ -1,42 +1,49 @@ error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:18:77 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | -LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} - | -- the lifetime parameter `'r` is defined here ^ its type must not depend on the lifetime parameter `'r` +LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( + | -- the lifetime parameter `'r` is defined here +... +LL | _: impl Trait<'r, A, Q, K = const { loop {} }> + | ^ its type must not depend on the lifetime parameter `'r` | = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:18:77 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | -LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} - | - the type parameter `A` is defined here ^ its type must not depend on the type parameter `A` +LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( + | - the type parameter `A` is defined here +... +LL | _: impl Trait<'r, A, Q, K = const { loop {} }> + | ^ its type must not depend on the type parameter `A` | = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:18:77 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | -LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} - | - ^ its type must not depend on the const parameter `Q` - | | - | the const parameter `Q` is defined here +LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( + | - the const parameter `Q` is defined here +... +LL | _: impl Trait<'r, A, Q, K = const { loop {} }> + | ^ its type must not depend on the const parameter `Q` | = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `SELF` must not depend on `impl Trait` - --> $DIR/assoc-const-eq-param-in-ty.rs:37:26 + --> $DIR/assoc-const-eq-param-in-ty.rs:39:26 | -LL | fn take1(_: impl Project) {} - | -------------^^^^------ +LL | fn take1(_: impl Project) {} + | -------------^^^^------------ | | | | | its type must not depend on `impl Trait` | the `impl Trait` is specified here error: the type of the associated constant `SELF` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:42:21 + --> $DIR/assoc-const-eq-param-in-ty.rs:44:21 | -LL | fn take2>(_: P) {} +LL | fn take2>(_: P) {} | - ^^^^ its type must not depend on the type parameter `P` | | | the type parameter `P` is defined here @@ -44,28 +51,28 @@ LL | fn take2>(_: P) {} = note: `SELF` has type `P` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here ... -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on the lifetime parameter `'r` | = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` | = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` | | | the const parameter `Q` is defined here @@ -73,30 +80,30 @@ LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here ... -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on the lifetime parameter `'r` | = note: `K` has type `&'r [Self; Q]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` | = note: `K` has type `&'r [Self; Q]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` | | | the const parameter `Q` is defined here diff --git a/tests/ui/associated-consts/assoc-const.rs b/tests/ui/associated-consts/assoc-const.rs index 4eed8bba53b1..6295fd50b8ff 100644 --- a/tests/ui/associated-consts/assoc-const.rs +++ b/tests/ui/associated-consts/assoc-const.rs @@ -14,10 +14,10 @@ impl Foo for Bar { const N: usize = 3; } -const TEST:usize = 3; +const TEST: usize = 3; -fn foo>() {} +fn foo>() {} fn main() { foo::() diff --git a/tests/ui/associated-consts/issue-110933.rs b/tests/ui/associated-consts/issue-110933.rs index 0284369f4d65..731ff1564ce2 100644 --- a/tests/ui/associated-consts/issue-110933.rs +++ b/tests/ui/associated-consts/issue-110933.rs @@ -10,7 +10,7 @@ pub trait Trait { pub fn foo< T: Trait< - ASSOC = { + ASSOC = const { let a = 10_usize; let b: &'_ usize = &a; *b diff --git a/tests/ui/associated-type-bounds/const-projection-err.rs b/tests/ui/associated-type-bounds/const-projection-err.rs index 80845ec3ee86..b230ea77f5fe 100644 --- a/tests/ui/associated-type-bounds/const-projection-err.rs +++ b/tests/ui/associated-type-bounds/const-projection-err.rs @@ -1,10 +1,6 @@ -//@ revisions: stock gce - #![feature(associated_const_equality, min_generic_const_args)] #![allow(incomplete_features)] -#![cfg_attr(gce, feature(generic_const_exprs))] - trait TraitWAssocConst { #[type_const] const A: usize; diff --git a/tests/ui/associated-type-bounds/const-projection-err.gce.stderr b/tests/ui/associated-type-bounds/const-projection-err.stderr similarity index 66% rename from tests/ui/associated-type-bounds/const-projection-err.gce.stderr rename to tests/ui/associated-type-bounds/const-projection-err.stderr index 9ad851d188d3..552b1579e618 100644 --- a/tests/ui/associated-type-bounds/const-projection-err.gce.stderr +++ b/tests/ui/associated-type-bounds/const-projection-err.stderr @@ -1,11 +1,13 @@ error[E0271]: type mismatch resolving `::A == 1` - --> $DIR/const-projection-err.rs:16:11 + --> $DIR/const-projection-err.rs:12:11 | LL | foo::(); - | ^ expected `0`, found `1` + | ^ expected `1`, found `0` | + = note: expected constant `1` + found constant `0` note: required by a bound in `foo` - --> $DIR/const-projection-err.rs:13:28 + --> $DIR/const-projection-err.rs:9:28 | LL | fn foo>() {} | ^^^^^ required by this bound in `foo` diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.rs b/tests/ui/associated-type-bounds/duplicate-bound-err.rs index 72c1ab559bdf..7e86148eb811 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.rs @@ -81,7 +81,9 @@ fn uncallable(_: impl Iterator) {} fn uncallable_const(_: impl Trait) {} -fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} +fn uncallable_rtn( + _: impl Trait, foo(..): Trait> +) {} type MustFail = dyn Iterator; //~^ ERROR [E0719] diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr index a54425c3a295..6484880392d6 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr @@ -100,7 +100,7 @@ LL | iter::empty::() | ----------------------- return type was inferred to be `std::iter::Empty` here error[E0271]: expected `IntoIter` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:110:17 + --> $DIR/duplicate-bound-err.rs:112:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -109,7 +109,7 @@ LL | [2u32].into_iter() | ------------------ return type was inferred to be `std::array::IntoIter` here error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:86:42 + --> $DIR/duplicate-bound-err.rs:88:42 | LL | type MustFail = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -117,7 +117,7 @@ LL | type MustFail = dyn Iterator; | `Item` bound here first error: conflicting associated type bounds for `Item` - --> $DIR/duplicate-bound-err.rs:86:17 + --> $DIR/duplicate-bound-err.rs:88:17 | LL | type MustFail = dyn Iterator; | ^^^^^^^^^^^^^----------^^----------^ @@ -126,7 +126,7 @@ LL | type MustFail = dyn Iterator; | `Item` is specified to be `i32` here error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:95:43 + --> $DIR/duplicate-bound-err.rs:97:43 | LL | type MustFail2 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -134,7 +134,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` bound here first error: conflicting associated type bounds for `ASSOC` - --> $DIR/duplicate-bound-err.rs:95:18 + --> $DIR/duplicate-bound-err.rs:97:18 | LL | type MustFail2 = dyn Trait2; | ^^^^^^^^^^^------------^^------------^ @@ -143,7 +143,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` is specified to be `3` here error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:99:43 + --> $DIR/duplicate-bound-err.rs:101:43 | LL | type MustFail3 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -151,7 +151,7 @@ LL | type MustFail3 = dyn Iterator; | `Item` bound here first error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:102:43 + --> $DIR/duplicate-bound-err.rs:104:43 | LL | type MustFail4 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -159,19 +159,19 @@ LL | type MustFail4 = dyn Trait2; | `ASSOC` bound here first error[E0271]: expected `impl Iterator` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:110:17 + --> $DIR/duplicate-bound-err.rs:112:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` | note: required by a bound in `Trait3::foo::{anon_assoc#0}` - --> $DIR/duplicate-bound-err.rs:106:31 + --> $DIR/duplicate-bound-err.rs:108:31 | LL | fn foo() -> impl Iterator; | ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}` error[E0271]: expected `Empty` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:118:16 + --> $DIR/duplicate-bound-err.rs:120:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -185,7 +185,7 @@ LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: expected `Empty` to be an iterator that yields `u32`, but it yields `i32` - --> $DIR/duplicate-bound-err.rs:119:16 + --> $DIR/duplicate-bound-err.rs:121:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32` @@ -199,7 +199,7 @@ LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:120:22 + --> $DIR/duplicate-bound-err.rs:122:22 | LL | uncallable_const(()); | ---------------- ^^ expected `4`, found `3` @@ -215,7 +215,7 @@ LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:121:22 + --> $DIR/duplicate-bound-err.rs:123:22 | LL | uncallable_const(4u32); | ---------------- ^^^^ expected `3`, found `4` @@ -231,7 +231,7 @@ LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:122:20 + --> $DIR/duplicate-bound-err.rs:124:20 | LL | uncallable_rtn(()); | -------------- ^^ expected `4`, found `3` @@ -241,13 +241,15 @@ LL | uncallable_rtn(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:84:75 + --> $DIR/duplicate-bound-err.rs:85:61 | -LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} - | ^^^^^^^^^ required by this bound in `uncallable_rtn` +LL | fn uncallable_rtn( + | -------------- required by a bound in this function +LL | _: impl Trait, foo(..): Trait> + | ^^^^^^^^^ required by this bound in `uncallable_rtn` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:123:20 + --> $DIR/duplicate-bound-err.rs:125:20 | LL | uncallable_rtn(17u32); | -------------- ^^^^^ expected `3`, found `4` @@ -257,10 +259,12 @@ LL | uncallable_rtn(17u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:84:48 + --> $DIR/duplicate-bound-err.rs:85:34 | -LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} - | ^^^^^^^^^ required by this bound in `uncallable_rtn` +LL | fn uncallable_rtn( + | -------------- required by a bound in this function +LL | _: impl Trait, foo(..): Trait> + | ^^^^^^^^^ required by this bound in `uncallable_rtn` error: aborting due to 25 previous errors diff --git a/tests/ui/associated-type-bounds/duplicate-bound.rs b/tests/ui/associated-type-bounds/duplicate-bound.rs index 3f40e429260f..6ea0daeca2c4 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound.rs @@ -224,7 +224,9 @@ fn uncallable_const(_: impl Trait) {} fn callable_const(_: impl Trait) {} -fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} +fn uncallable_rtn( + _: impl Trait, foo(..): Trait> +) {} fn callable_rtn(_: impl Trait) {} diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs index edadcd7c80ed..f28f3f694ff3 100644 --- a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs @@ -12,7 +12,7 @@ impl AssocConst for (T,) { trait Trait {} -impl Trait for () where (U,): AssocConst {} +impl Trait for () where (U,): AssocConst {} //~^ ERROR associated const equality is incomplete //~| ERROR the type parameter `U` is not constrained by the impl trait diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr index 4106c500215b..092faff93511 100644 --- a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr @@ -1,8 +1,8 @@ error[E0658]: associated const equality is incomplete --> $DIR/unconstrained_impl_param.rs:15:45 | -LL | impl Trait for () where (U,): AssocConst {} - | ^^^^^^^^^ +LL | impl Trait for () where (U,): AssocConst {} + | ^^^^^ | = note: see issue #92827 for more information = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable @@ -11,7 +11,7 @@ LL | impl Trait for () where (U,): AssocConst {} error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates --> $DIR/unconstrained_impl_param.rs:15:6 | -LL | impl Trait for () where (U,): AssocConst {} +LL | impl Trait for () where (U,): AssocConst {} | ^ unconstrained type parameter error[E0282]: type annotations needed diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.rs b/tests/ui/const-generics/mgca/explicit_anon_consts.rs new file mode 100644 index 000000000000..459282776266 --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.rs @@ -0,0 +1,70 @@ +#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] +#![expect(incomplete_features)] + +struct Foo; + +type Adt1 = Foo; +type Adt2 = Foo<{ N }>; +type Adt3 = Foo; +//~^ ERROR: generic parameters may not be used in const operations +type Adt4 = Foo<{ 1 + 1 }>; +//~^ ERROR: complex const arguments must be placed inside of a `const` block +type Adt5 = Foo; + +type Arr = [(); N]; +type Arr2 = [(); { N }]; +type Arr3 = [(); const { N }]; +//~^ ERROR: generic parameters may not be used in const operations +type Arr4 = [(); 1 + 1]; +//~^ ERROR: complex const arguments must be placed inside of a `const` block +type Arr5 = [(); const { 1 + 1 }]; + +fn repeats() { + let _1 = [(); N]; + let _2 = [(); { N }]; + let _3 = [(); const { N }]; + //~^ ERROR: generic parameters may not be used in const operations + let _4 = [(); 1 + 1]; + //~^ ERROR: complex const arguments must be placed inside of a `const` block + let _5 = [(); const { 1 + 1 }]; +} + +#[type_const] +const ITEM1: usize = N; +#[type_const] +const ITEM2: usize = { N }; +#[type_const] +const ITEM3: usize = const { N }; +//~^ ERROR: generic parameters may not be used in const operations +#[type_const] +const ITEM4: usize = { 1 + 1 }; +//~^ ERROR: complex const arguments must be placed inside of a `const` block +#[type_const] +const ITEM5: usize = const { 1 + 1}; + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +fn ace_bounds< + const N: usize, + // We skip the T1 case because it doesn't resolve + // T1: Trait, + T2: Trait, + T3: Trait, + //~^ ERROR: generic parameters may not be used in const operations + T4: Trait, + //~^ ERROR: complex const arguments must be placed inside of a `const` block + T5: Trait, +>() {} + +struct Default1; +struct Default2; +struct Default3; +//~^ ERROR: generic parameters may not be used in const operations +struct Default4; +//~^ ERROR: complex const arguments must be placed inside of a `const` block +struct Default5; + +fn main() {} diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr new file mode 100644 index 000000000000..e4bf49c71efe --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr @@ -0,0 +1,92 @@ +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:8:41 + | +LL | type Adt3 = Foo; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:16:42 + | +LL | type Arr3 = [(); const { N }]; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:25:27 + | +LL | let _3 = [(); const { N }]; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:37:46 + | +LL | const ITEM3: usize = const { N }; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:55:31 + | +LL | T3: Trait, + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:64:58 + | +LL | struct Default3; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:10:33 + | +LL | type Adt4 = Foo<{ 1 + 1 }>; + | ^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:18:34 + | +LL | type Arr4 = [(); 1 + 1]; + | ^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:27:19 + | +LL | let _4 = [(); 1 + 1]; + | ^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:40:38 + | +LL | const ITEM4: usize = { 1 + 1 }; + | ^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:57:23 + | +LL | T4: Trait, + | ^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:66:50 + | +LL | struct Default4; + | ^^^^^^^^^ + +error: aborting due to 12 previous errors + diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs new file mode 100644 index 000000000000..979d10331a59 --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs @@ -0,0 +1,22 @@ +//@ check-pass + +// We allow for literals to implicitly be anon consts still regardless +// of whether a const block is placed around them or not + +#![feature(min_generic_const_args, associated_const_equality)] +#![expect(incomplete_features)] + +trait Trait { + #[type_const] + const ASSOC: isize; +} + +fn ace>() {} +fn repeat_count() { + [(); 1]; +} +type ArrLen = [(); 1]; +struct Foo; +type NormalArg = (Foo<1>, Foo<-1>); + +fn main() {} diff --git a/tests/ui/const-generics/mgca/multi_braced_direct_const_args.rs b/tests/ui/const-generics/mgca/multi_braced_direct_const_args.rs new file mode 100644 index 000000000000..31f54abf31ef --- /dev/null +++ b/tests/ui/const-generics/mgca/multi_braced_direct_const_args.rs @@ -0,0 +1,25 @@ +//@ check-pass + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +struct Foo; + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +type Arr = [(); {{{ N }}}]; +type Arr2 = [(); {{{ ::ASSOC }}}]; +type Ty = Foo<{{{ N }}}>; +type Ty2 = Foo<{{{ ::ASSOC }}}>; +struct Default; +struct Default2::ASSOC }}}>(T); + +fn repeat() { + let _1 = [(); {{{ N }}}]; + let _2 = [(); {{{ ::ASSOC }}}]; +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-not-constparamty.rs b/tests/ui/const-generics/mgca/type_const-not-constparamty.rs index 27b446e6a40d..11db82187b84 100644 --- a/tests/ui/const-generics/mgca/type_const-not-constparamty.rs +++ b/tests/ui/const-generics/mgca/type_const-not-constparamty.rs @@ -4,9 +4,9 @@ struct S; // FIXME(mgca): need support for ctors without anon const -// (we use double-braces to trigger an anon const here) +// (we use a const-block to trigger an anon const here) #[type_const] -const FREE: S = { { S } }; +const FREE: S = const { S }; //~^ ERROR `S` must implement `ConstParamTy` to be used as the type of a const generic parameter trait Tr { @@ -17,9 +17,9 @@ trait Tr { impl Tr for S { // FIXME(mgca): need support for ctors without anon const - // (we use double-braces to trigger an anon const here) + // (we use a const-block to trigger an anon const here) #[type_const] - const N: S = { { S } }; + const N: S = const { S }; //~^ ERROR `S` must implement `ConstParamTy` to be used as the type of a const generic parameter } diff --git a/tests/ui/const-generics/mgca/type_const-not-constparamty.stderr b/tests/ui/const-generics/mgca/type_const-not-constparamty.stderr index 6b13917a95cd..d07bbde1e62e 100644 --- a/tests/ui/const-generics/mgca/type_const-not-constparamty.stderr +++ b/tests/ui/const-generics/mgca/type_const-not-constparamty.stderr @@ -1,7 +1,7 @@ error[E0741]: `S` must implement `ConstParamTy` to be used as the type of a const generic parameter --> $DIR/type_const-not-constparamty.rs:9:13 | -LL | const FREE: S = { { S } }; +LL | const FREE: S = const { S }; | ^ | help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct @@ -13,7 +13,7 @@ LL | struct S; error[E0741]: `S` must implement `ConstParamTy` to be used as the type of a const generic parameter --> $DIR/type_const-not-constparamty.rs:22:14 | -LL | const N: S = { { S } }; +LL | const N: S = const { S }; | ^ | help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs b/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs index d38d5ab7a59f..577fee084dbd 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs @@ -2,10 +2,10 @@ #![feature(min_generic_const_args, generic_const_items)] #[type_const] -const FREE1: usize = std::mem::size_of::(); +const FREE1: usize = const { std::mem::size_of::() }; //~^ ERROR generic parameters may not be used in const operations #[type_const] -const FREE2: usize = I + 1; +const FREE2: usize = const { I + 1 }; //~^ ERROR generic parameters may not be used in const operations pub trait Tr { @@ -21,13 +21,13 @@ pub trait Tr { impl Tr for S { #[type_const] - const N1: usize = std::mem::size_of::(); + const N1: usize = const { std::mem::size_of::() }; //~^ ERROR generic parameters may not be used in const operations #[type_const] - const N2: usize = I + 1; + const N2: usize = const { I + 1 }; //~^ ERROR generic parameters may not be used in const operations #[type_const] - const N3: usize = 2 & X; + const N3: usize = const { 2 & X }; //~^ ERROR generic parameters may not be used in const operations } diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr index 76638f27e96c..8cef77e5b229 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr @@ -1,44 +1,44 @@ error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:5:45 + --> $DIR/type_const-on-generic-expr.rs:5:53 | -LL | const FREE1: usize = std::mem::size_of::(); - | ^ cannot perform const operation using `T` +LL | const FREE1: usize = const { std::mem::size_of::() }; + | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:8:38 + --> $DIR/type_const-on-generic-expr.rs:8:46 | -LL | const FREE2: usize = I + 1; - | ^ cannot perform const operation using `I` +LL | const FREE2: usize = const { I + 1 }; + | ^ cannot perform const operation using `I` | = help: const parameters may only be used as standalone arguments here, i.e. `I` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:24:46 + --> $DIR/type_const-on-generic-expr.rs:24:54 | -LL | const N1: usize = std::mem::size_of::(); - | ^ cannot perform const operation using `T` +LL | const N1: usize = const { std::mem::size_of::() }; + | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:27:39 + --> $DIR/type_const-on-generic-expr.rs:27:47 | -LL | const N2: usize = I + 1; - | ^ cannot perform const operation using `I` +LL | const N2: usize = const { I + 1 }; + | ^ cannot perform const operation using `I` | = help: const parameters may only be used as standalone arguments here, i.e. `I` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:30:27 + --> $DIR/type_const-on-generic-expr.rs:30:35 | -LL | const N3: usize = 2 & X; - | ^ cannot perform const operation using `X` +LL | const N3: usize = const { 2 & X }; + | ^ cannot perform const operation using `X` | = help: const parameters may only be used as standalone arguments here, i.e. `X` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions diff --git a/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs new file mode 100644 index 000000000000..588fa2f913b6 --- /dev/null +++ b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs @@ -0,0 +1,42 @@ +#![feature(adt_const_params)] + +#[derive(Eq, PartialEq, std::marker::ConstParamTy)] +struct Inner; + +struct Foo< + const PARAM_TY: Inner, + //~^ ERROR: unbraced const blocks as const args are experimental + const DEFAULT: usize = const { 1 }, + //~^ ERROR: unbraced const blocks as const args are experimental +>; + +type Array = [(); const { 1 }]; +type NormalTy = Inner; + //~^ ERROR: unbraced const blocks as const args are experimental + +fn repeat() { + [1_u8; const { 1 }]; +} + +fn body_ty() { + let _: Inner; + //~^ ERROR: unbraced const blocks as const args are experimental +} + +fn generic() { + if false { + generic::(); + //~^ ERROR: unbraced const blocks as const args are experimental + } +} + +const NON_TYPE_CONST: usize = const { 1 }; + +#[type_const] +//~^ ERROR: the `#[type_const]` attribute is an experimental feature +const TYPE_CONST: usize = const { 1 }; +//~^ ERROR: unbraced const blocks as const args are experimental + +static STATIC: usize = const { 1 }; + +fn main() {} diff --git a/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr new file mode 100644 index 000000000000..30509ddf9b46 --- /dev/null +++ b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr @@ -0,0 +1,73 @@ +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:7:33 + | +LL | const PARAM_TY: Inner, + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:9:34 + | +LL | const DEFAULT: usize = const { 1 }, + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:14:29 + | +LL | type NormalTy = Inner; + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:22:24 + | +LL | let _: Inner; + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:28:25 + | +LL | generic::(); + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:37:33 + | +LL | const TYPE_CONST: usize = const { 1 }; + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `#[type_const]` attribute is an experimental feature + --> $DIR/unbraced_const_block_const_arg_gated.rs:35:1 + | +LL | #[type_const] + | ^^^^^^^^^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs b/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs index 554e078ccd49..d97b3a9f0929 100644 --- a/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs +++ b/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs @@ -9,6 +9,6 @@ trait Trait { //~^ ERROR using function pointers as const generic parameters is forbidden } -fn take(_: impl Trait) {} +fn take(_: impl Trait) {} fn main() {} diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs index 7f4926fa2b71..a72aaedb980e 100644 --- a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs @@ -9,12 +9,12 @@ impl Pins for NoPin {} pub trait PinA { #[type_const] - const A: &'static () = &(); + const A: &'static () = const { &() }; } pub trait Pins {} -impl Pins for T where T: PinA {} +impl Pins for T where T: PinA {} //~^ ERROR conflicting implementations of trait `Pins<_>` for type `NoPin` pub fn main() {} diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr index 34546349592f..f57fd74ad99d 100644 --- a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr @@ -4,8 +4,8 @@ error[E0119]: conflicting implementations of trait `Pins<_>` for type `NoPin` LL | impl Pins for NoPin {} | --------------------------- first implementation here ... -LL | impl Pins for T where T: PinA {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoPin` +LL | impl Pins for T where T: PinA {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoPin` | = note: downstream crates may implement trait `PinA<_>` for type `NoPin` diff --git a/tests/ui/generic-const-items/associated-const-equality.rs b/tests/ui/generic-const-items/associated-const-equality.rs index 6f5d4985ae53..37cf381e6824 100644 --- a/tests/ui/generic-const-items/associated-const-equality.rs +++ b/tests/ui/generic-const-items/associated-const-equality.rs @@ -17,7 +17,7 @@ impl Owner for () { #[type_const] const C: u32 = N; #[type_const] - const K: u32 = 99 + 1; + const K: u32 = const { 99 + 1 }; // FIXME(mgca): re-enable once we properly support ctors and generics on paths // #[type_const] // const Q: Maybe = Maybe::Nothing; From 29f688a05ff4306f0a0b322a07b702fe933604f3 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 11 Dec 2025 15:49:36 -0800 Subject: [PATCH 571/585] Update to mdbook 0.5 This updates to mdbook 0.5.2 from mdbook 0.4.52. A primary aspect of this change is that it splits the `mdbook` crate into multiple crates, and various API changes and cleanup. There's full release notes and a migration guide at https://github.com/rust-lang/mdBook/blob/master/CHANGELOG.md#mdbook-050. This also includes submodule updates: ## book 2 commits in 8c0eacd5c4acbb650497454f3a58c9e8083202a4..39aeceaa3aeab845bc4517e7a44e48727d3b9dbe 2025-11-18 10:36:41 -0500 to 2025-12-12 11:02:27 -0500 - Synchronize TrplNote name - Update to mdbook 0.5 ## edition-guide 1 commits in 9cf5443d632673c4d41edad5e8ed8be86eeb3b8f..c3c0f0b3da26610138b7ba7663f60cd2c68cf184 2025-11-15 21:51:11 +0000 to 2025-11-28 18:54:18 +0000 - Update to mdbook 0.5 (rust-lang/edition-guide#381) ## nomicon 2 commits in 0fe83ab28985b99aba36a1f0dbde3e08286fefda..9fe8fa599ad228dda74f240cc32b54bc5c1aa3e6 2025-11-15 00:03:14 +0000 to 2025-12-03 11:54:04 +0000 - Remove references to outdated unsafe code guidelines (rust-lang/nomicon#512) - Update to mdbook 0.5 (rust-lang/nomicon#511) ## reference 5 commits in b14b4e40f53ca468beaf2f5d0dfb4f4c4ba6bc7b..50c5de90487b68d429a30cc9466dc8f5b410128f 2025-12-02 21:17:44 +0000 to 2025-12-09 22:19:05 +0000 - UB: update the extra clause for provenance UB during const evaluation (rust-lang/reference#2091) - Remove `[no-mentions]` handler in our triagebot config (rust-lang/reference#2102) - Clarify that omitting `nostack` is a promise from the compiler to the programmer (rust-lang/reference#1999) - Specify that range patterns must be nonempty. (rust-lang/reference#2093) - Update to mdbook 0.5 (rust-lang/reference#2096) ## rust-by-example 1 commits in 111cfae2f9c3a43f7b0ff8fa68c51cc8f930637c..7d21279e40e8f0e91c2a22c5148dd2d745aef8b6 2025-11-27 17:16:42 -0300 to 2025-12-01 15:02:09 -0300 - Update to mdbook 0.5 (rust-lang/rust-by-example#1977) --- src/doc/book | 2 +- src/doc/edition-guide | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc/book.toml | 4 - src/doc/rustc/theme/pagetoc.css | 84 -- src/doc/rustc/theme/pagetoc.js | 104 -- .../src/read-documentation/in-doc-settings.md | 2 +- src/doc/style-guide/book.toml | 4 +- src/doc/unstable-book/book.toml | 1 - src/tools/error_index_generator/Cargo.toml | 3 +- src/tools/error_index_generator/main.rs | 8 +- src/tools/rustbook/Cargo.lock | 911 ++++++------------ src/tools/rustbook/Cargo.toml | 15 +- src/tools/rustbook/src/main.rs | 116 ++- src/tools/tidy/src/deps.rs | 12 +- 17 files changed, 412 insertions(+), 862 deletions(-) delete mode 100644 src/doc/rustc/theme/pagetoc.css delete mode 100644 src/doc/rustc/theme/pagetoc.js diff --git a/src/doc/book b/src/doc/book index 8c0eacd5c4ac..39aeceaa3aea 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 8c0eacd5c4acbb650497454f3a58c9e8083202a4 +Subproject commit 39aeceaa3aeab845bc4517e7a44e48727d3b9dbe diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 9cf5443d6326..c3c0f0b3da26 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 9cf5443d632673c4d41edad5e8ed8be86eeb3b8f +Subproject commit c3c0f0b3da26610138b7ba7663f60cd2c68cf184 diff --git a/src/doc/nomicon b/src/doc/nomicon index 0fe83ab28985..9fe8fa599ad2 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 0fe83ab28985b99aba36a1f0dbde3e08286fefda +Subproject commit 9fe8fa599ad228dda74f240cc32b54bc5c1aa3e6 diff --git a/src/doc/reference b/src/doc/reference index b14b4e40f53c..50c5de90487b 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit b14b4e40f53ca468beaf2f5d0dfb4f4c4ba6bc7b +Subproject commit 50c5de90487b68d429a30cc9466dc8f5b410128f diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 111cfae2f9c3..7d21279e40e8 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 111cfae2f9c3a43f7b0ff8fa68c51cc8f930637c +Subproject commit 7d21279e40e8f0e91c2a22c5148dd2d745aef8b6 diff --git a/src/doc/rustc/book.toml b/src/doc/rustc/book.toml index 34c57a63c97b..9a7c28525f0e 100644 --- a/src/doc/rustc/book.toml +++ b/src/doc/rustc/book.toml @@ -1,13 +1,9 @@ [book] -multilingual = false -src = "src" title = "The rustc book" [output.html] git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/rustc" edit-url-template = "https://github.com/rust-lang/rust/edit/HEAD/src/doc/rustc/{path}" -additional-css = ["theme/pagetoc.css"] -additional-js = ["theme/pagetoc.js"] [output.html.search] use-boolean-and = true diff --git a/src/doc/rustc/theme/pagetoc.css b/src/doc/rustc/theme/pagetoc.css deleted file mode 100644 index fa709194f375..000000000000 --- a/src/doc/rustc/theme/pagetoc.css +++ /dev/null @@ -1,84 +0,0 @@ -/* Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) */ - -:root { - --toc-width: 270px; - --center-content-toc-shift: calc(-1 * var(--toc-width) / 2); -} - -.nav-chapters { - /* adjust width of buttons that bring to the previous or the next page */ - min-width: 50px; -} - -@media only screen { - @media (max-width: 1179px) { - .sidebar-hidden #sidetoc { - display: none; - } - } - - @media (max-width: 1439px) { - .sidebar-visible #sidetoc { - display: none; - } - } - - @media (1180px <= width <= 1439px) { - .sidebar-hidden main { - position: relative; - left: var(--center-content-toc-shift); - } - } - - @media (1440px <= width <= 1700px) { - .sidebar-visible main { - position: relative; - left: var(--center-content-toc-shift); - } - } - - #sidetoc { - margin-left: calc(100% + 20px); - } - #pagetoc { - position: fixed; - /* adjust TOC width */ - width: var(--toc-width); - height: calc(100vh - var(--menu-bar-height) - 0.67em * 4); - overflow: auto; - } - #pagetoc a { - border-left: 1px solid var(--sidebar-bg); - color: var(--fg); - display: block; - padding-bottom: 5px; - padding-top: 5px; - padding-left: 10px; - text-align: left; - text-decoration: none; - } - #pagetoc a:hover, - #pagetoc a.active { - background: var(--sidebar-bg); - color: var(--sidebar-active) !important; - } - #pagetoc .active { - background: var(--sidebar-bg); - color: var(--sidebar-active); - } - #pagetoc .pagetoc-H2 { - padding-left: 20px; - } - #pagetoc .pagetoc-H3 { - padding-left: 40px; - } - #pagetoc .pagetoc-H4 { - padding-left: 60px; - } -} - -@media print { - #sidetoc { - display: none; - } -} diff --git a/src/doc/rustc/theme/pagetoc.js b/src/doc/rustc/theme/pagetoc.js deleted file mode 100644 index 927a5b10749b..000000000000 --- a/src/doc/rustc/theme/pagetoc.js +++ /dev/null @@ -1,104 +0,0 @@ -// Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) - -let activeHref = location.href; -function updatePageToc(elem = undefined) { - let selectedPageTocElem = elem; - const pagetoc = document.getElementById("pagetoc"); - - function getRect(element) { - return element.getBoundingClientRect(); - } - - function overflowTop(container, element) { - return getRect(container).top - getRect(element).top; - } - - function overflowBottom(container, element) { - return getRect(container).bottom - getRect(element).bottom; - } - - // We've not selected a heading to highlight, and the URL needs updating - // so we need to find a heading based on the URL - if (selectedPageTocElem === undefined && location.href !== activeHref) { - activeHref = location.href; - for (const pageTocElement of pagetoc.children) { - if (pageTocElement.href === activeHref) { - selectedPageTocElem = pageTocElement; - } - } - } - - // We still don't have a selected heading, let's try and find the most - // suitable heading based on the scroll position - if (selectedPageTocElem === undefined) { - const margin = window.innerHeight / 3; - - const headers = document.getElementsByClassName("header"); - for (let i = 0; i < headers.length; i++) { - const header = headers[i]; - if (selectedPageTocElem === undefined && getRect(header).top >= 0) { - if (getRect(header).top < margin) { - selectedPageTocElem = header; - } else { - selectedPageTocElem = headers[Math.max(0, i - 1)]; - } - } - // a very long last section's heading is over the screen - if (selectedPageTocElem === undefined && i === headers.length - 1) { - selectedPageTocElem = header; - } - } - } - - // Remove the active flag from all pagetoc elements - for (const pageTocElement of pagetoc.children) { - pageTocElement.classList.remove("active"); - } - - // If we have a selected heading, set it to active and scroll to it - if (selectedPageTocElem !== undefined) { - for (const pageTocElement of pagetoc.children) { - if (selectedPageTocElem.href.localeCompare(pageTocElement.href) === 0) { - pageTocElement.classList.add("active"); - if (overflowTop(pagetoc, pageTocElement) > 0) { - pagetoc.scrollTop = pageTocElement.offsetTop; - } - if (overflowBottom(pagetoc, pageTocElement) < 0) { - pagetoc.scrollTop -= overflowBottom(pagetoc, pageTocElement); - } - } - } - } -} - -if (document.getElementById("sidetoc") === null && - document.getElementsByClassName("header").length > 0) { - // The sidetoc element doesn't exist yet, let's create it - - // Create the empty sidetoc and pagetoc elements - const sidetoc = document.createElement("div"); - const pagetoc = document.createElement("div"); - sidetoc.id = "sidetoc"; - pagetoc.id = "pagetoc"; - sidetoc.appendChild(pagetoc); - - // And append them to the current DOM - const main = document.querySelector('main'); - main.insertBefore(sidetoc, main.firstChild); - - // Populate sidebar on load - window.addEventListener("load", () => { - for (const header of document.getElementsByClassName("header")) { - const link = document.createElement("a"); - link.innerHTML = header.innerHTML; - link.href = header.hash; - link.classList.add("pagetoc-" + header.parentElement.tagName); - document.getElementById("pagetoc").appendChild(link); - link.onclick = () => updatePageToc(link); - } - updatePageToc(); - }); - - // Update page table of contents selected heading on scroll - window.addEventListener("scroll", () => updatePageToc()); -} diff --git a/src/doc/rustdoc/src/read-documentation/in-doc-settings.md b/src/doc/rustdoc/src/read-documentation/in-doc-settings.md index 12928a4f3692..1bcf74e39cd1 100644 --- a/src/doc/rustdoc/src/read-documentation/in-doc-settings.md +++ b/src/doc/rustdoc/src/read-documentation/in-doc-settings.md @@ -4,7 +4,7 @@ Rustdoc's HTML output includes a settings menu, and this chapter describes what each setting in this menu does. It can be accessed by clicking on the gear button -() in the upper right. +() in the upper right. ## Changing displayed theme diff --git a/src/doc/style-guide/book.toml b/src/doc/style-guide/book.toml index 056aec8cdd4f..1ef0af5fcdbf 100644 --- a/src/doc/style-guide/book.toml +++ b/src/doc/style-guide/book.toml @@ -1,8 +1,6 @@ [book] title = "The Rust Style Guide" -author = "The Rust Style Team" -multilingual = false -src = "src" +authors = ["The Rust Style Team"] [output.html] git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/style-guide/" diff --git a/src/doc/unstable-book/book.toml b/src/doc/unstable-book/book.toml index 5dbe90cd10ec..c357949f6c2e 100644 --- a/src/doc/unstable-book/book.toml +++ b/src/doc/unstable-book/book.toml @@ -1,6 +1,5 @@ [book] title = "The Rust Unstable Book" -author = "The Rust Community" [output.html] git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/unstable-book" diff --git a/src/tools/error_index_generator/Cargo.toml b/src/tools/error_index_generator/Cargo.toml index 54fe7f6eb5a9..9d0f3b061d47 100644 --- a/src/tools/error_index_generator/Cargo.toml +++ b/src/tools/error_index_generator/Cargo.toml @@ -5,7 +5,8 @@ edition = "2021" workspace = "../rustbook" [dependencies] -mdbook = { version = "0.4", default-features = false, features = ["search"] } +mdbook-driver = { version = "0.5.1", features = ["search"] } +mdbook-summary = "0.5.1" [[bin]] name = "error_index_generator" diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 58224aed1487..97ac47918c09 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -12,8 +12,10 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; -use mdbook::book::{BookItem, Chapter, parse_summary}; -use mdbook::{Config, MDBook}; +use mdbook_driver::MDBook; +use mdbook_driver::book::{BookItem, Chapter}; +use mdbook_driver::config::Config; +use mdbook_summary::parse_summary; use rustc_errors::codes::DIAGNOSTICS; enum OutputFormat { @@ -121,7 +123,7 @@ fn render_html(output_path: &Path) -> Result<(), Box> { source_path: None, parent_names: Vec::new(), }; - book.book.sections.push(BookItem::Chapter(chapter)); + book.book.items.push(BookItem::Chapter(chapter)); book.build()?; // The error-index used to be generated manually (without mdbook), and the diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index d5aa7a671636..e7b04260e4a9 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -17,19 +17,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ammonia" -version = "4.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e913097e1a2124b46746c980134e8c954bc17a6a59bb3fde96f088d126dde6" -dependencies = [ - "cssparser", - "html5ever", - "maplit", - "tendril", - "url", -] - [[package]] name = "android_system_properties" version = "0.1.5" @@ -110,6 +97,21 @@ dependencies = [ "serde", ] +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitflags" version = "2.10.0" @@ -125,17 +127,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bstr" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" -dependencies = [ - "memchr", - "regex-automata", - "serde", -] - [[package]] name = "bumpalo" version = "3.19.0" @@ -191,16 +182,6 @@ dependencies = [ "anstyle", "clap_lex", "strsim", - "terminal_size", -] - -[[package]] -name = "clap_complete" -version = "4.5.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e602857739c5a4291dfa33b5a298aeac9006185229a700e5810a3ef7272d971" -dependencies = [ - "clap", ] [[package]] @@ -261,29 +242,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "cssparser" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e901edd733a1472f944a45116df3f846f54d37e67e68640ac8bb69689aca2aa" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "phf 0.11.3", - "smallvec", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "darling" version = "0.20.11" @@ -372,17 +330,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "doc-comment" version = "0.3.4" @@ -390,19 +337,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" [[package]] -name = "dtoa" -version = "1.0.10" +name = "ego-tree" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" - -[[package]] -name = "dtoa-short" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" -dependencies = [ - "dtoa", -] +checksum = "b2972feb8dffe7bc8c5463b1dacda1b0dfbed3710e50f977d965429692d74cd8" [[package]] name = "elasticlunr-rs" @@ -416,29 +354,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "env_filter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "jiff", - "log", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -459,7 +374,19 @@ dependencies = [ name = "error_index_generator" version = "0.0.0" dependencies = [ - "mdbook", + "mdbook-driver", + "mdbook-summary", +] + +[[package]] +name = "fancy-regex" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", ] [[package]] @@ -491,13 +418,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "form_urlencoded" -version = "1.2.2" +name = "font-awesome-as-a-crate" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] +checksum = "932dcfbd51320af5f27f1ba02d2e567dec332cac7d2c221ba45d8e767264c4dc" [[package]] name = "futf" @@ -558,9 +482,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" @@ -576,13 +500,12 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "html5ever" -version = "0.35.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4" +checksum = "6452c4751a24e1b99c3260d505eaeee76a050573e61f30ac2c924ddc7236f01e" dependencies = [ "log", "markup5ever", - "match_token", ] [[package]] @@ -624,119 +547,17 @@ dependencies = [ "cc", ] -[[package]] -name = "icu_collections" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" - -[[package]] -name = "icu_properties" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" - -[[package]] -name = "icu_provider" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - [[package]] name = "indexmap" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", "hashbrown", @@ -754,30 +575,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "jiff" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde_core", -] - -[[package]] -name = "jiff-static" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "js-sys" version = "0.3.82" @@ -815,12 +612,6 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" -[[package]] -name = "litemap" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" - [[package]] name = "lock_api" version = "0.4.14" @@ -842,17 +633,11 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - [[package]] name = "markup5ever" -version = "0.35.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3" +checksum = "6c3294c4d74d0742910f8c7b466f44dda9eb2d5742c1e430138df290a1e8451c" dependencies = [ "log", "tendril", @@ -860,58 +645,91 @@ dependencies = [ ] [[package]] -name = "match_token" -version = "0.35.0" +name = "matchers" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "proc-macro2", - "quote", - "syn", + "regex-automata", ] [[package]] -name = "mdbook" -version = "0.4.52" +name = "mdbook-core" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c284d2855916af7c5919cf9ad897cfc77d3c2db6f55429c7cfb769182030ec" +checksum = "39a3873d4afac65583f1acb56ff058df989d5b4a2464bb02c785549727d307ee" dependencies = [ - "ammonia", "anyhow", - "chrono", - "clap", - "clap_complete", + "regex", + "serde", + "serde_json", + "toml 0.9.8", + "tracing", +] + +[[package]] +name = "mdbook-driver" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a229930b29a9908560883e1f386eae25d8a971d259a80f49916a50627f04a42d" +dependencies = [ + "anyhow", + "indexmap", + "mdbook-core", + "mdbook-html", + "mdbook-markdown", + "mdbook-preprocessor", + "mdbook-renderer", + "mdbook-summary", + "regex", + "serde", + "serde_json", + "shlex", + "tempfile", + "toml 0.9.8", + "topological-sort", + "tracing", +] + +[[package]] +name = "mdbook-html" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dee80c03c65e3212fb528b8c9be5568a6a85cf795d03cf9fd6ba39ad52069ca" +dependencies = [ + "anyhow", + "ego-tree", "elasticlunr-rs", - "env_logger", + "font-awesome-as-a-crate", "handlebars", "hex", - "log", - "memchr", - "opener", - "pulldown-cmark 0.10.3", + "html5ever", + "indexmap", + "mdbook-core", + "mdbook-markdown", + "mdbook-renderer", + "pulldown-cmark 0.13.0", "regex", "serde", "serde_json", "sha2", - "shlex", - "tempfile", - "toml 0.5.11", - "topological-sort", + "tracing", ] [[package]] name = "mdbook-i18n-helpers" -version = "0.3.6" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5644bf29b95683ea60979e30188221c374965c3a1dc0ad2d5c69e867dc0c09dc" +checksum = "82a64b6c27dc99a20968cc85a89dcfe0d36f82e2c9bc3b4342a2ffc55158822f" dependencies = [ "anyhow", "chrono", "dateparser", - "mdbook", + "mdbook-preprocessor", + "mdbook-renderer", "polib", - "pulldown-cmark 0.12.2", - "pulldown-cmark-to-cmark 20.0.1", + "pulldown-cmark 0.13.0", + "pulldown-cmark-to-cmark 21.1.0", "regex", "semver", "serde_json", @@ -919,15 +737,50 @@ dependencies = [ "textwrap", ] +[[package]] +name = "mdbook-markdown" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c41bf35212f5d8b83e543aa6a4887dc5709c8489c5fb9ed00f1b51ce1a2cc6" +dependencies = [ + "pulldown-cmark 0.13.0", + "regex", + "tracing", +] + +[[package]] +name = "mdbook-preprocessor" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d87bf40be0597f26f0822f939a64f02bf92c4655ba04490aadbf83601a013bb" +dependencies = [ + "anyhow", + "mdbook-core", + "serde", + "serde_json", +] + +[[package]] +name = "mdbook-renderer" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ed59f225b3ae4283c56bea633db83184627a090d892908bd66990c68e10b43" +dependencies = [ + "anyhow", + "mdbook-core", + "serde", + "serde_json", +] + [[package]] name = "mdbook-spec" version = "0.1.2" dependencies = [ "anyhow", - "mdbook", + "mdbook-markdown", + "mdbook-preprocessor", "once_cell", "pathdiff", - "pulldown-cmark 0.10.3", "railroad", "regex", "semver", @@ -936,6 +789,20 @@ dependencies = [ "walkdir", ] +[[package]] +name = "mdbook-summary" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00d85b291d67a69c92e939450390fe34d6ea418a868c8f7b42f0b300af35a7b" +dependencies = [ + "anyhow", + "mdbook-core", + "memchr", + "pulldown-cmark 0.13.0", + "serde", + "tracing", +] + [[package]] name = "mdbook-trpl" version = "0.1.0" @@ -943,9 +810,10 @@ dependencies = [ "anyhow", "clap", "html_parser", - "mdbook", + "mdbook-preprocessor", "pulldown-cmark 0.12.2", "pulldown-cmark-to-cmark 19.0.1", + "serde", "serde_json", "thiserror 1.0.69", "toml 0.8.23", @@ -974,10 +842,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] -name = "normpath" -version = "1.5.0" +name = "nu-ansi-term" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf23ab2b905654b4cb177e30b629937b3868311d4e1cba859f899c041046e69b" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ "windows-sys 0.61.2", ] @@ -1018,39 +886,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" -[[package]] -name = "onig" -version = "6.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" -dependencies = [ - "bitflags", - "libc", - "once_cell", - "onig_sys", -] - -[[package]] -name = "onig_sys" -version = "69.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc" -dependencies = [ - "cc", - "pkg-config", -] - -[[package]] -name = "opener" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb9024962ab91e00c89d2a14352a8d0fc1a64346bf96f1839b45c09149564e47" -dependencies = [ - "bstr", - "normpath", - "windows-sys 0.60.2", -] - [[package]] name = "parking_lot" version = "0.12.5" @@ -1080,12 +915,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - [[package]] name = "pest" version = "2.8.3" @@ -1129,23 +958,13 @@ dependencies = [ "sha2", ] -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros", - "phf_shared 0.11.3", -] - [[package]] name = "phf" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ - "phf_shared 0.13.1", + "phf_shared", "serde", ] @@ -1155,18 +974,8 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand", + "phf_generator", + "phf_shared", ] [[package]] @@ -1176,29 +985,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ "fastrand", - "phf_shared 0.13.1", -] - -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher", + "phf_shared", ] [[package]] @@ -1211,10 +998,10 @@ dependencies = [ ] [[package]] -name = "pkg-config" -version = "0.3.32" +name = "pin-project-lite" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "polib" @@ -1225,30 +1012,6 @@ dependencies = [ "linereader", ] -[[package]] -name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - -[[package]] -name = "potential_utf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - [[package]] name = "precomputed-hash" version = "0.1.1" @@ -1264,18 +1027,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "pulldown-cmark" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" -dependencies = [ - "bitflags", - "memchr", - "pulldown-cmark-escape 0.10.1", - "unicase", -] - [[package]] name = "pulldown-cmark" version = "0.12.2" @@ -1285,15 +1036,21 @@ dependencies = [ "bitflags", "getopts", "memchr", - "pulldown-cmark-escape 0.11.0", + "pulldown-cmark-escape", "unicase", ] [[package]] -name = "pulldown-cmark-escape" -version = "0.10.1" +name = "pulldown-cmark" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" +checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" +dependencies = [ + "bitflags", + "memchr", + "pulldown-cmark-escape", + "unicase", +] [[package]] name = "pulldown-cmark-escape" @@ -1312,11 +1069,11 @@ dependencies = [ [[package]] name = "pulldown-cmark-to-cmark" -version = "20.0.1" +version = "21.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c0f333311d2d8fda65bcf76af35054e9f38e253332a0289746156a59656988b" +checksum = "8246feae3db61428fd0bb94285c690b460e4517d83152377543ca802357785f1" dependencies = [ - "pulldown-cmark 0.12.2", + "pulldown-cmark 0.13.0", ] [[package]] @@ -1343,21 +1100,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" - [[package]] name = "redox_syscall" version = "0.5.18" @@ -1401,12 +1143,11 @@ name = "rustbook" version = "0.1.0" dependencies = [ "clap", - "env_logger", - "libc", - "mdbook", + "mdbook-driver", "mdbook-i18n-helpers", "mdbook-spec", "mdbook-trpl", + "tracing-subscriber", ] [[package]] @@ -1507,6 +1248,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" +dependencies = [ + "serde_core", +] + [[package]] name = "sha2" version = "0.10.9" @@ -1518,6 +1268,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1542,12 +1301,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - [[package]] name = "string_cache" version = "0.9.0" @@ -1556,7 +1309,7 @@ checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" dependencies = [ "new_debug_unreachable", "parking_lot", - "phf_shared 0.13.1", + "phf_shared", "precomputed-hash", "serde", ] @@ -1567,8 +1320,8 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", + "phf_generator", + "phf_shared", "proc-macro2", "quote", ] @@ -1590,17 +1343,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "syntect" version = "5.3.0" @@ -1608,10 +1350,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "656b45c05d95a5704399aeef6bd0ddec7b2b3531b7c9e900abbf7c4d2190c925" dependencies = [ "bincode", + "fancy-regex", "flate2", "fnv", "once_cell", - "onig", "regex-syntax", "serde", "serde_derive", @@ -1643,16 +1385,6 @@ dependencies = [ "utf-8", ] -[[package]] -name = "terminal_size" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" -dependencies = [ - "rustix", - "windows-sys 0.60.2", -] - [[package]] name = "textwrap" version = "0.16.2" @@ -1700,22 +1432,12 @@ dependencies = [ ] [[package]] -name = "tinystr" -version = "0.8.2" +name = "thread_local" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", + "cfg-if", ] [[package]] @@ -1725,11 +1447,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_edit", ] +[[package]] +name = "toml" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.0.3", + "toml_datetime 0.7.3", + "toml_parser", + "toml_writer", + "winnow", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -1739,6 +1476,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.22.27" @@ -1747,24 +1493,100 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_write", "winnow", ] +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + [[package]] name = "toml_write" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "toml_writer" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" + [[package]] name = "topological-sort" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" +[[package]] +name = "tracing" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + [[package]] name = "typenum" version = "1.19.0" @@ -1795,36 +1617,24 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" -[[package]] -name = "url" -version = "2.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - [[package]] name = "utf-8" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "version_check" version = "0.9.5" @@ -1897,11 +1707,11 @@ dependencies = [ [[package]] name = "web_atoms" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44b72896d90cfd22c495d0ee4960d3dd20ca64180895cb92cd5342ff7482a579" +checksum = "acd0c322f146d0f8aad130ce6c187953889359584497dac6561204c8e17bb43d" dependencies = [ - "phf 0.13.1", + "phf", "phf_codegen", "string_cache", "string_cache_codegen", @@ -2072,86 +1882,3 @@ name = "wit-bindgen" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" - -[[package]] -name = "writeable" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - -[[package]] -name = "yoke" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerotrie" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 1a5b2c29d20b..2815f09105b1 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -8,14 +8,9 @@ license = "MIT OR Apache-2.0" edition = "2021" [dependencies] -clap = "4.0.32" -env_logger = "0.11" -libc = "0.2" -mdbook-trpl = { path = "../../doc/book/packages/mdbook-trpl" } -mdbook-i18n-helpers = "0.3.3" +clap = { version = "4.0.32", features = ["cargo"] } +mdbook-driver = { version = "0.5.2", features = ["search"] } +mdbook-i18n-helpers = "0.4.0" mdbook-spec = { path = "../../doc/reference/mdbook-spec" } - -[dependencies.mdbook] -version = "0.4.52" -default-features = false -features = ["search"] +mdbook-trpl = { path = "../../doc/book/packages/mdbook-trpl" } +tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index 4b510e308c97..541052402820 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -2,15 +2,27 @@ use std::path::{Path, PathBuf}; use clap::{ArgMatches, Command, arg, crate_version}; -use mdbook::MDBook; -use mdbook::errors::Result as Result3; +use mdbook_driver::MDBook; +use mdbook_driver::errors::Result as Result3; use mdbook_i18n_helpers::preprocessors::Gettext; use mdbook_spec::Spec; use mdbook_trpl::{Figure, Listing, Note}; fn main() { let crate_version = concat!("v", crate_version!()); - env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init(); + let filter = tracing_subscriber::EnvFilter::builder() + .with_env_var("MDBOOK_LOG") + .with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into()) + .from_env_lossy(); + tracing_subscriber::fmt() + .without_time() + .with_ansi(std::io::IsTerminal::is_terminal(&std::io::stderr())) + .with_writer(std::io::stderr) + .with_env_filter(filter) + .with_target(std::env::var_os("MDBOOK_LOG").is_some()) + .init(); + + // env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); let d_arg = arg!(-d --"dest-dir" "The output directory for your book\n(Defaults to ./book when omitted)") .required(false) @@ -82,60 +94,22 @@ fn main() { }; } -// Build command implementation -pub fn build(args: &ArgMatches) -> Result3<()> { +fn build(args: &ArgMatches) -> Result3<()> { let book_dir = get_book_dir(args); - let mut book = load_book(&book_dir)?; - - if let Some(lang) = args.get_one::("lang") { - let gettext = Gettext; - book.with_preprocessor(gettext); - book.config.set("book.language", lang).unwrap(); - } - - // Set this to allow us to catch bugs in advance. - book.config.build.create_missing = false; - - if let Some(dest_dir) = args.get_one::("dest-dir") { - book.config.build.build_dir = dest_dir.into(); - } - - // NOTE: Replacing preprocessors using this technique causes error - // messages to be displayed when the original preprocessor doesn't work - // (but it otherwise succeeds). - // - // This should probably be fixed in mdbook to remove the existing - // preprocessor, or this should modify the config and use - // MDBook::load_with_config. - if book.config.get_preprocessor("trpl-note").is_some() { - book.with_preprocessor(Note); - } - - if book.config.get_preprocessor("trpl-listing").is_some() { - book.with_preprocessor(Listing); - } - - if book.config.get_preprocessor("trpl-figure").is_some() { - book.with_preprocessor(Figure); - } - - if book.config.get_preprocessor("spec").is_some() { - let rust_root = args.get_one::("rust-root").cloned(); - book.with_preprocessor(Spec::new(rust_root)?); - } - - book.build()?; - - Ok(()) + let dest_dir = args.get_one::("dest-dir"); + let lang = args.get_one::("lang"); + let rust_root = args.get_one::("rust-root"); + let book = load_book(&book_dir, dest_dir, lang, rust_root.cloned())?; + book.build() } fn test(args: &ArgMatches) -> Result3<()> { let book_dir = get_book_dir(args); + let mut book = load_book(&book_dir, None, None, None)?; let library_paths = args .try_get_one::>("library-path")? .map(|v| v.iter().map(|s| s.as_str()).collect::>()) .unwrap_or_default(); - let mut book = load_book(&book_dir)?; book.test(library_paths) } @@ -148,10 +122,52 @@ fn get_book_dir(args: &ArgMatches) -> PathBuf { } } -fn load_book(book_dir: &Path) -> Result3 { +fn load_book( + book_dir: &Path, + dest_dir: Option<&PathBuf>, + lang: Option<&String>, + rust_root: Option, +) -> Result3 { let mut book = MDBook::load(book_dir)?; book.config.set("output.html.input-404", "").unwrap(); book.config.set("output.html.hash-files", true).unwrap(); + + if let Some(lang) = lang { + let gettext = Gettext; + book.with_preprocessor(gettext); + book.config.set("book.language", lang).unwrap(); + } + + // Set this to allow us to catch bugs in advance. + book.config.build.create_missing = false; + + if let Some(dest_dir) = dest_dir { + book.config.build.build_dir = dest_dir.into(); + } + + // NOTE: Replacing preprocessors using this technique causes error + // messages to be displayed when the original preprocessor doesn't work + // (but it otherwise succeeds). + // + // This should probably be fixed in mdbook to remove the existing + // preprocessor, or this should modify the config and use + // MDBook::load_with_config. + if book.config.contains_key("preprocessor.trpl-note") { + book.with_preprocessor(Note); + } + + if book.config.contains_key("preprocessor.trpl-listing") { + book.with_preprocessor(Listing); + } + + if book.config.contains_key("preprocessor.trpl-figure") { + book.with_preprocessor(Figure); + } + + if book.config.contains_key("preprocessor.spec") { + book.with_preprocessor(Spec::new(rust_root)?); + } + Ok(book) } @@ -159,7 +175,7 @@ fn parse_library_paths(input: &str) -> Result, String> { Ok(input.split(",").map(String::from).collect()) } -fn handle_error(error: mdbook::errors::Error) -> ! { +fn handle_error(error: mdbook_driver::errors::Error) -> ! { eprintln!("Error: {}", error); for cause in error.chain().skip(1) { diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 592ba9c5c794..f374a1e01496 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -222,10 +222,14 @@ pub(crate) struct WorkspaceInfo<'a> { const EXCEPTIONS_RUSTBOOK: ExceptionList = &[ // tidy-alphabetical-start - ("cssparser", "MPL-2.0"), - ("cssparser-macros", "MPL-2.0"), - ("dtoa-short", "MPL-2.0"), - ("mdbook", "MPL-2.0"), + ("font-awesome-as-a-crate", "CC-BY-4.0 AND MIT"), + ("mdbook-core", "MPL-2.0"), + ("mdbook-driver", "MPL-2.0"), + ("mdbook-html", "MPL-2.0"), + ("mdbook-markdown", "MPL-2.0"), + ("mdbook-preprocessor", "MPL-2.0"), + ("mdbook-renderer", "MPL-2.0"), + ("mdbook-summary", "MPL-2.0"), // tidy-alphabetical-end ]; From 0748492e2bb7d48c4c548729b0593c470bc31155 Mon Sep 17 00:00:00 2001 From: delta17920 Date: Wed, 10 Dec 2025 18:17:03 +0000 Subject: [PATCH 572/585] Fix: Prevent macro-expanded extern crates from shadowing extern arguments --- compiler/rustc_resolve/src/ident.rs | 63 ++++++++++--------- compiler/rustc_resolve/src/imports.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 1 + .../ice-inconsistent-resolution-149821.rs | 17 +++++ .../ice-inconsistent-resolution-149821.stderr | 13 ++++ 5 files changed, 65 insertions(+), 31 deletions(-) create mode 100644 tests/ui/resolve/ice-inconsistent-resolution-149821.rs create mode 100644 tests/ui/resolve/ice-inconsistent-resolution-149821.stderr diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e38d4370d5d2..5587fc91216f 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -771,36 +771,39 @@ fn maybe_push_ambiguity( } else { None }; - // Skip ambiguity errors for extern flag bindings "overridden" - // by extern item bindings. - // FIXME: Remove with lang team approval. - let issue_145575_hack = Some(binding) == extern_prelude_flag_binding - && extern_prelude_item_binding.is_some() - && extern_prelude_item_binding != Some(innermost_binding); - if let Some(kind) = ambiguity_error_kind - && !issue_145575_hack - { - let misc = |f: Flags| { - if f.contains(Flags::MISC_SUGGEST_CRATE) { - AmbiguityErrorMisc::SuggestCrate - } else if f.contains(Flags::MISC_SUGGEST_SELF) { - AmbiguityErrorMisc::SuggestSelf - } else if f.contains(Flags::MISC_FROM_PRELUDE) { - AmbiguityErrorMisc::FromPrelude - } else { - AmbiguityErrorMisc::None - } - }; - self.ambiguity_errors.push(AmbiguityError { - kind, - ident: orig_ident, - b1: innermost_binding, - b2: binding, - warning: false, - misc1: misc(innermost_flags), - misc2: misc(flags), - }); - return true; + if let Some(kind) = ambiguity_error_kind { + // Skip ambiguity errors for extern flag bindings "overridden" + // by extern item bindings. + // FIXME: Remove with lang team approval. + let issue_145575_hack = Some(binding) == extern_prelude_flag_binding + && extern_prelude_item_binding.is_some() + && extern_prelude_item_binding != Some(innermost_binding); + + if issue_145575_hack { + self.issue_145575_hack_applied = true; + } else { + let misc = |f: Flags| { + if f.contains(Flags::MISC_SUGGEST_CRATE) { + AmbiguityErrorMisc::SuggestCrate + } else if f.contains(Flags::MISC_SUGGEST_SELF) { + AmbiguityErrorMisc::SuggestSelf + } else if f.contains(Flags::MISC_FROM_PRELUDE) { + AmbiguityErrorMisc::FromPrelude + } else { + AmbiguityErrorMisc::None + } + }; + self.ambiguity_errors.push(AmbiguityError { + kind, + ident: orig_ident, + b1: innermost_binding, + b2: binding, + warning: false, + misc1: misc(innermost_flags), + misc2: misc(flags), + }); + return true; + } } false diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4ef87af56050..4e0f3db59821 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1170,7 +1170,7 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option { privacy_errors: Vec> = Vec::new(), /// Ambiguity errors are delayed for deduplication. ambiguity_errors: Vec> = Vec::new(), + issue_145575_hack_applied: bool = false, /// `use` injections are delayed for better placement and deduplication. use_injections: Vec> = Vec::new(), /// Crate-local macro expanded `macro_export` referred to by a module-relative path. diff --git a/tests/ui/resolve/ice-inconsistent-resolution-149821.rs b/tests/ui/resolve/ice-inconsistent-resolution-149821.rs new file mode 100644 index 000000000000..19b8a2f4330c --- /dev/null +++ b/tests/ui/resolve/ice-inconsistent-resolution-149821.rs @@ -0,0 +1,17 @@ +//@ edition: 2024 + +mod m { + use crate::*; + use core; +} + +macro_rules! define_other_core { + () => { + extern crate std as core; + //~^ ERROR macro-expanded `extern crate` items cannot shadow names passed with `--extern` + }; +} + +define_other_core! {} + +fn main() {} diff --git a/tests/ui/resolve/ice-inconsistent-resolution-149821.stderr b/tests/ui/resolve/ice-inconsistent-resolution-149821.stderr new file mode 100644 index 000000000000..cd75a2f3e19b --- /dev/null +++ b/tests/ui/resolve/ice-inconsistent-resolution-149821.stderr @@ -0,0 +1,13 @@ +error: macro-expanded `extern crate` items cannot shadow names passed with `--extern` + --> $DIR/ice-inconsistent-resolution-149821.rs:10:9 + | +LL | extern crate std as core; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | define_other_core! {} + | --------------------- in this macro invocation + | + = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + From 0a3fd242879bdd53747289db422c11a403333bcb Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Fri, 12 Dec 2025 20:34:54 +0300 Subject: [PATCH 573/585] Support attribute inheritance in delegation --- compiler/rustc_ast_lowering/src/delegation.rs | 156 +++++++++++++++--- compiler/rustc_middle/src/ty/mod.rs | 14 +- compiler/rustc_resolve/src/late.rs | 30 +++- tests/pretty/auxiliary/to-reuse-functions.rs | 14 ++ tests/pretty/delegation-inherit-attributes.pp | 61 +++++++ tests/pretty/delegation-inherit-attributes.rs | 56 +++++++ 6 files changed, 305 insertions(+), 26 deletions(-) create mode 100644 tests/pretty/auxiliary/to-reuse-functions.rs create mode 100644 tests/pretty/delegation-inherit-attributes.pp create mode 100644 tests/pretty/delegation-inherit-attributes.rs diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 0e7db7c9503c..82bade8829a2 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -43,13 +43,15 @@ use hir::{BodyId, HirId}; use rustc_abi::ExternAbi; use rustc_ast::*; +use rustc_attr_parsing::{AttributeParser, ShouldEmit}; use rustc_errors::ErrorGuaranteed; +use rustc_hir::Target; use rustc_hir::attrs::{AttributeKind, InlineAttr}; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; -use rustc_middle::ty::{Asyncness, ResolverAstLowering}; +use rustc_middle::ty::{Asyncness, DelegationFnSigAttrs, ResolverAstLowering}; use rustc_span::symbol::kw; -use rustc_span::{Ident, Span, Symbol}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode}; @@ -62,6 +64,41 @@ pub(crate) struct DelegationResults<'hir> { pub generics: &'hir hir::Generics<'hir>, } +struct AttributeAdditionInfo { + pub equals: fn(&hir::Attribute) -> bool, + pub kind: AttributeAdditionKind, +} + +enum AttributeAdditionKind { + Default { factory: fn(Span) -> hir::Attribute }, + Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute }, +} + +const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO; + +static ATTRIBUTES_ADDITIONS: &[AttributeAdditionInfo] = &[ + AttributeAdditionInfo { + equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::MustUse { .. })), + kind: AttributeAdditionKind::Inherit { + factory: |span, original_attribute| { + let reason = match original_attribute { + hir::Attribute::Parsed(AttributeKind::MustUse { reason, .. }) => *reason, + _ => None, + }; + + hir::Attribute::Parsed(AttributeKind::MustUse { span, reason }) + }, + flag: DelegationFnSigAttrs::MUST_USE, + }, + }, + AttributeAdditionInfo { + equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))), + kind: AttributeAdditionKind::Default { + factory: |span| hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span)), + }, + }, +]; + impl<'hir> LoweringContext<'_, 'hir> { fn is_method(&self, def_id: DefId, span: Span) -> bool { match self.tcx.def_kind(def_id) { @@ -88,7 +125,7 @@ pub(crate) fn lower_delegation( let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl); match sig_id { Ok(sig_id) => { - self.add_inline_attribute_if_needed(span); + self.add_attributes_if_needed(span, sig_id); let is_method = self.is_method(sig_id, span); let (param_count, c_variadic) = self.param_count(sig_id); @@ -103,29 +140,100 @@ pub(crate) fn lower_delegation( } } - fn add_inline_attribute_if_needed(&mut self, span: Span) { - const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO; - let create_inline_attr_slice = - || [hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span))]; + fn add_attributes_if_needed(&mut self, span: Span, sig_id: DefId) { + let new_attributes = self.create_new_attributes( + ATTRIBUTES_ADDITIONS, + span, + sig_id, + self.attrs.get(&PARENT_ID), + ); - let new_attributes = match self.attrs.get(&PARENT_ID) { - Some(attrs) => { - // Check if reuse already specifies any inline attribute, if so, do nothing - if attrs - .iter() - .any(|a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..)))) - { - return; - } + if new_attributes.is_empty() { + return; + } - self.arena.alloc_from_iter( - attrs.into_iter().map(|a| a.clone()).chain(create_inline_attr_slice()), - ) - } - None => self.arena.alloc_from_iter(create_inline_attr_slice()), + let new_arena_allocated_attributes = match self.attrs.get(&PARENT_ID) { + Some(existing_attrs) => self.arena.alloc_from_iter( + existing_attrs.iter().map(|a| a.clone()).chain(new_attributes.into_iter()), + ), + None => self.arena.alloc_from_iter(new_attributes.into_iter()), }; - self.attrs.insert(PARENT_ID, new_attributes); + self.attrs.insert(PARENT_ID, new_arena_allocated_attributes); + } + + fn create_new_attributes( + &self, + candidate_additions: &[AttributeAdditionInfo], + span: Span, + sig_id: DefId, + existing_attrs: Option<&&[hir::Attribute]>, + ) -> Vec { + let local_original_attributes = self.parse_local_original_attributes(sig_id); + + candidate_additions + .iter() + .filter_map(|addition_info| { + if let Some(existing_attrs) = existing_attrs + && existing_attrs + .iter() + .any(|existing_attr| (addition_info.equals)(existing_attr)) + { + return None; + } + + match addition_info.kind { + AttributeAdditionKind::Default { factory } => Some(factory(span)), + AttributeAdditionKind::Inherit { flag, factory } => { + let original_attribute = match sig_id.as_local() { + Some(local_id) => self + .resolver + .delegation_fn_sigs + .get(&local_id) + .is_some_and(|sig| sig.attrs_flags.contains(flag)) + .then(|| { + local_original_attributes + .as_ref() + .map(|attrs| { + attrs + .iter() + .find(|base_attr| (addition_info.equals)(base_attr)) + }) + .flatten() + }) + .flatten(), + None => self + .tcx + .get_all_attrs(sig_id) + .iter() + .find(|base_attr| (addition_info.equals)(base_attr)), + }; + + original_attribute.map(|a| factory(span, a)) + } + } + }) + .collect::>() + } + + fn parse_local_original_attributes(&self, sig_id: DefId) -> Option> { + if let Some(local_id) = sig_id.as_local() + && let Some(info) = self.resolver.delegation_fn_sigs.get(&local_id) + && !info.to_inherit_attrs.is_empty() + { + Some(AttributeParser::parse_limited_all( + self.tcx.sess, + info.to_inherit_attrs.as_slice(), + None, + Target::Fn, + DUMMY_SP, + DUMMY_NODE_ID, + Some(self.tcx.features()), + ShouldEmit::Nothing, + )) + } else { + None + } } fn get_delegation_sig_id( @@ -220,7 +328,9 @@ fn lower_delegation_sig( // We are not forwarding the attributes, as the delegation fn sigs are collected on the ast, // and here we need the hir attributes. let default_safety = - if sig.target_feature || self.tcx.def_kind(parent) == DefKind::ForeignMod { + if sig.attrs_flags.contains(DelegationFnSigAttrs::TARGET_FEATURE) + || self.tcx.def_kind(parent) == DefKind::ForeignMod + { hir::Safety::Unsafe } else { hir::Safety::Safe diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6ca4949910f2..418335a89347 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -25,6 +25,7 @@ pub use generics::*; pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; +use rustc_ast::AttrVec; use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree}; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; @@ -221,13 +222,24 @@ pub struct ResolverAstLowering { pub delegation_fn_sigs: LocalDefIdMap, } +bitflags::bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + pub struct DelegationFnSigAttrs: u8 { + const TARGET_FEATURE = 1 << 0; + const MUST_USE = 1 << 1; + } +} + +pub const DELEGATION_INHERIT_ATTRS_START: DelegationFnSigAttrs = DelegationFnSigAttrs::MUST_USE; + #[derive(Debug)] pub struct DelegationFnSig { pub header: ast::FnHeader, pub param_count: usize, pub has_self: bool, pub c_variadic: bool, - pub target_feature: bool, + pub attrs_flags: DelegationFnSigAttrs, + pub to_inherit_attrs: AttrVec, } #[derive(Clone, Copy, Debug, HashStable)] diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f1a03d5a0610..cc17ca9c026d 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -28,7 +28,9 @@ 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::{AssocTag, DelegationFnSig, Visibility}; +use rustc_middle::ty::{ + AssocTag, DELEGATION_INHERIT_ATTRS_START, DelegationFnSig, DelegationFnSigAttrs, Visibility, +}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint; @@ -5294,13 +5296,37 @@ fn collect_fn_info( id: NodeId, attrs: &[Attribute], ) { + static NAMES_TO_FLAGS: &[(Symbol, DelegationFnSigAttrs)] = &[ + (sym::target_feature, DelegationFnSigAttrs::TARGET_FEATURE), + (sym::must_use, DelegationFnSigAttrs::MUST_USE), + ]; + + let mut to_inherit_attrs = AttrVec::new(); + let mut attrs_flags = DelegationFnSigAttrs::empty(); + + 'attrs_loop: for attr in attrs { + for &(name, flag) in NAMES_TO_FLAGS { + if attr.has_name(name) { + attrs_flags.set(flag, true); + + if flag.bits() >= DELEGATION_INHERIT_ATTRS_START.bits() { + to_inherit_attrs.push(attr.clone()); + } + + continue 'attrs_loop; + } + } + } + let sig = DelegationFnSig { header, param_count: decl.inputs.len(), has_self: decl.has_self(), c_variadic: decl.c_variadic(), - target_feature: attrs.iter().any(|attr| attr.has_name(sym::target_feature)), + attrs_flags, + to_inherit_attrs, }; + self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig); } } diff --git a/tests/pretty/auxiliary/to-reuse-functions.rs b/tests/pretty/auxiliary/to-reuse-functions.rs new file mode 100644 index 000000000000..55d6ecf035e3 --- /dev/null +++ b/tests/pretty/auxiliary/to-reuse-functions.rs @@ -0,0 +1,14 @@ +//@ edition:2021 + +#[must_use] +#[cold] +pub unsafe fn unsafe_fn_extern() -> usize { 1 } + +#[must_use = "extern_fn_extern: some reason"] +#[deprecated] +pub extern "C" fn extern_fn_extern() -> usize { 1 } + +pub const fn const_fn_extern() -> usize { 1 } + +#[must_use] +pub async fn async_fn_extern() { } diff --git a/tests/pretty/delegation-inherit-attributes.pp b/tests/pretty/delegation-inherit-attributes.pp new file mode 100644 index 000000000000..772e177b8883 --- /dev/null +++ b/tests/pretty/delegation-inherit-attributes.pp @@ -0,0 +1,61 @@ +//@ edition:2021 +//@ aux-crate:to_reuse_functions=to-reuse-functions.rs +//@ pretty-mode:hir +//@ pretty-compare-only +//@ pp-exact:delegation-inherit-attributes.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] +#[attr = MacroUse {arguments: UseAll}] +extern crate std; +#[prelude_import] +use std::prelude::rust_2021::*; + +extern crate to_reuse_functions; + +mod to_reuse { + #[attr = MustUse {reason: "foo: some reason"}] + #[attr = Cold] + fn foo(x: usize) -> usize { x } + + #[attr = MustUse] + #[attr = Cold] + fn foo_no_reason(x: usize) -> usize { x } + + #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = Cold] + fn bar(x: usize) -> usize { x } +} + +#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] +#[attr = MustUse {reason: "foo: some reason"}] +#[attr = Inline(Hint)] +fn foo1(arg0: _) -> _ { to_reuse::foo(self + 1) } + +#[attr = MustUse] +#[attr = Inline(Hint)] +fn foo_no_reason(arg0: _) -> _ { to_reuse::foo_no_reason(self + 1) } + +#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] +#[attr = MustUse {reason: "some reason"}] +#[attr = Inline(Hint)] +fn foo2(arg0: _) -> _ { to_reuse::foo(self + 1) } + +#[attr = Inline(Hint)] +fn bar(arg0: _) -> _ { to_reuse::bar(arg0) } + +#[attr = MustUse] +#[attr = Inline(Hint)] +unsafe fn unsafe_fn_extern() -> _ { to_reuse_functions::unsafe_fn_extern() } +#[attr = MustUse {reason: "extern_fn_extern: some reason"}] +#[attr = Inline(Hint)] +extern "C" fn extern_fn_extern() + -> _ { to_reuse_functions::extern_fn_extern() } +#[attr = Inline(Hint)] +const fn const_fn_extern() -> _ { to_reuse_functions::const_fn_extern() } +#[attr = MustUse {reason: "some reason"}] +#[attr = Inline(Hint)] +async fn async_fn_extern() -> _ { to_reuse_functions::async_fn_extern() } + + +fn main() { } diff --git a/tests/pretty/delegation-inherit-attributes.rs b/tests/pretty/delegation-inherit-attributes.rs new file mode 100644 index 000000000000..fe74b9a55a7d --- /dev/null +++ b/tests/pretty/delegation-inherit-attributes.rs @@ -0,0 +1,56 @@ +//@ edition:2021 +//@ aux-crate:to_reuse_functions=to-reuse-functions.rs +//@ pretty-mode:hir +//@ pretty-compare-only +//@ pp-exact:delegation-inherit-attributes.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +extern crate to_reuse_functions; + +mod to_reuse { + #[must_use = "foo: some reason"] + #[cold] + pub fn foo(x: usize) -> usize { + x + } + + #[must_use] + #[cold] + pub fn foo_no_reason(x: usize) -> usize { + x + } + + #[cold] + #[deprecated] + pub fn bar(x: usize) -> usize { + x + } +} + +#[deprecated] +reuse to_reuse::foo as foo1 { + self + 1 +} + +reuse to_reuse::foo_no_reason { + self + 1 +} + +#[deprecated] +#[must_use = "some reason"] +reuse to_reuse::foo as foo2 { + self + 1 +} + +reuse to_reuse::bar; + +reuse to_reuse_functions::unsafe_fn_extern; +reuse to_reuse_functions::extern_fn_extern; +reuse to_reuse_functions::const_fn_extern; +#[must_use = "some reason"] +reuse to_reuse_functions::async_fn_extern; + + +fn main() {} From 146711fc249aec2272d565878e9139fa75f81288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Dec 2025 00:43:46 +0000 Subject: [PATCH 574/585] Use `let...else` instead of `match foo { ... _ => return };` and `if let ... else return` --- compiler/rustc_ast/src/ast.rs | 7 +- compiler/rustc_ast/src/attr/mod.rs | 19 ++- .../src/diagnostics/conflict_errors.rs | 7 +- .../src/diagnostics/explain_borrow.rs | 14 +-- .../rustc_borrowck/src/diagnostics/mod.rs | 14 +-- .../src/diagnostics/mutability_errors.rs | 9 +- .../src/diagnostics/region_errors.rs | 50 +++----- .../src/polonius/legacy/accesses.rs | 11 +- .../src/debuginfo/unwind.rs | 6 +- .../src/optimize/peephole.rs | 6 +- .../rustc_codegen_gcc/src/intrinsic/simd.rs | 31 +++-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 5 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 5 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 5 +- compiler/rustc_hir_analysis/src/collect.rs | 14 +-- .../src/collect/item_bounds.rs | 25 ++-- .../errors/wrong_number_of_generic_args.rs | 15 +-- .../src/hir_ty_lowering/errors.rs | 6 +- compiler/rustc_hir_typeck/src/callee.rs | 9 +- compiler/rustc_hir_typeck/src/demand.rs | 7 +- .../rustc_hir_typeck/src/expr_use_visitor.rs | 16 +-- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 23 ++-- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 7 +- .../src/fn_ctxt/suggestions.rs | 20 ++- compiler/rustc_hir_typeck/src/inline_asm.rs | 7 +- .../rustc_hir_typeck/src/method/suggest.rs | 6 +- compiler/rustc_lint/src/builtin.rs | 7 +- ..._expr_fragment_specifier_2024_migration.rs | 6 +- compiler/rustc_middle/src/ty/diagnostics.rs | 9 +- compiler/rustc_middle/src/ty/mod.rs | 4 +- compiler/rustc_middle/src/ty/sty.rs | 15 +-- .../rustc_mir_dataflow/src/move_paths/mod.rs | 14 +-- .../rustc_mir_dataflow/src/value_analysis.rs | 7 +- compiler/rustc_mir_transform/src/gvn.rs | 45 ++++--- .../rustc_mir_transform/src/promote_consts.rs | 10 +- .../src/solve/eval_ctxt/mod.rs | 14 +-- .../src/solve/normalizes_to/mod.rs | 14 +-- .../src/solve/trait_goals.rs | 79 ++++++------ .../rustc_resolve/src/late/diagnostics.rs | 114 +++++++++--------- 39 files changed, 282 insertions(+), 400 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e348cc1ab281..67152f5d2462 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1534,11 +1534,10 @@ pub fn to_ty(&self) -> Option> { // then type of result is trait object. // Otherwise we don't assume the result type. ExprKind::Binary(binop, lhs, rhs) if binop.node == BinOpKind::Add => { - if let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) { - TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None) - } else { + let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) else { return None; - } + }; + TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None) } ExprKind::Underscore => TyKind::Infer, diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index a5e630a09afe..c53188a22aed 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -447,20 +447,17 @@ fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option { thin_vec![PathSegment::path_root(span)] }; loop { - if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) = + let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) = iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() - { - segments.push(PathSegment::from_ident(Ident::new(name, span))); - } else { + else { return None; - } - if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = - iter.peek() - { - iter.next(); - } else { + }; + segments.push(PathSegment::from_ident(Ident::new(name, span))); + let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = iter.peek() + else { break; - } + }; + iter.next(); } let span = span.with_hi(segments.last().unwrap().ident.span.hi()); Path { span, segments, tokens: None } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2999d1f2926c..5cfe9db009bf 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -561,11 +561,8 @@ fn suggest_ref_for_dbg_args( VarDebugInfoContents::Place(ref p) => p == place, _ => false, }); - let arg_name = if let Some(var_info) = var_info { - var_info.name - } else { - return; - }; + let Some(var_info) = var_info else { return }; + let arg_name = var_info.name; struct MatchArgFinder { expr_span: Span, match_arg_span: Option, diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index bfdfa896cd2b..8e18bf557758 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -850,16 +850,10 @@ fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool { // will only ever have one item at any given time, but by using a vector, we can pop from // it which simplifies the termination logic. let mut queue = vec![location]; - let mut target = - if let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = stmt { - if let Some(local) = place.as_local() { - local - } else { - return false; - } - } else { - return false; - }; + let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = stmt else { + return false; + }; + let Some(mut target) = place.as_local() else { return false }; debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue); while let Some(current_location) = queue.pop() { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index e13c1c712d8d..e725b13434a1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1124,16 +1124,12 @@ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpan use self::UseSpans::*; debug!("borrow_spans: use_span={:?} location={:?}", use_span, location); - let target = match self.body[location.block].statements.get(location.statement_index) { - Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) => { - if let Some(local) = place.as_local() { - local - } else { - return OtherUse(use_span); - } - } - _ => return OtherUse(use_span), + let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = + self.body[location.block].statements.get(location.statement_index) + else { + return OtherUse(use_span); }; + let Some(target) = place.as_local() else { return OtherUse(use_span) }; if self.body.local_kind(target) != LocalKind::Temp { // operands are always temporaries. diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 7d72de7efa4a..e9039d4311b6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -142,12 +142,11 @@ pub(crate) fn report_mutability_error( } else { item_msg = access_place_desc; let local_info = self.body.local_decls[local].local_info(); - if let LocalInfo::StaticRef { def_id, .. } = *local_info { - let static_name = &self.infcx.tcx.item_name(def_id); - reason = format!(", as `{static_name}` is an immutable static item"); - } else { + let LocalInfo::StaticRef { def_id, .. } = *local_info else { bug!("is_ref_to_static return true, but not ref to static?"); - } + }; + let static_name = &self.infcx.tcx.item_name(def_id); + reason = format!(", as `{static_name}` is an immutable static item"); } } PlaceRef { local, projection: [proj_base @ .., ProjectionElem::Deref] } => { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index f4bbdabf7f21..9c2b9139367a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -847,11 +847,9 @@ fn add_static_impl_trait_suggestion( let fn_returns = self.infcx.tcx.return_type_impl_or_dyn_traits(suitable_region.scope); - let param = if let Some(param) = + let Some(param) = find_param_with_region(self.infcx.tcx, self.mir_def_id(), f, outlived_f) - { - param - } else { + else { return; }; @@ -930,37 +928,27 @@ fn maybe_suggest_constrain_dyn_trait_impl( let tcx = self.infcx.tcx; - let instance = if let ConstraintCategory::CallArgument(Some(func_ty)) = category { - let (fn_did, args) = match func_ty.kind() { - ty::FnDef(fn_did, args) => (fn_did, args), - _ => return, - }; - debug!(?fn_did, ?args); + let ConstraintCategory::CallArgument(Some(func_ty)) = category else { return }; + let ty::FnDef(fn_did, args) = func_ty.kind() else { return }; + debug!(?fn_did, ?args); - // Only suggest this on function calls, not closures - let ty = tcx.type_of(fn_did).instantiate_identity(); - debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind()); - if let ty::Closure(_, _) = ty.kind() { - return; - } - - if let Ok(Some(instance)) = ty::Instance::try_resolve( - tcx, - self.infcx.typing_env(self.infcx.param_env), - *fn_did, - self.infcx.resolve_vars_if_possible(args), - ) { - instance - } else { - return; - } - } else { + // Only suggest this on function calls, not closures + let ty = tcx.type_of(fn_did).instantiate_identity(); + debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind()); + if let ty::Closure(_, _) = ty.kind() { + return; + } + let Ok(Some(instance)) = ty::Instance::try_resolve( + tcx, + self.infcx.typing_env(self.infcx.param_env), + *fn_did, + self.infcx.resolve_vars_if_possible(args), + ) else { return; }; - let param = match find_param_with_region(tcx, self.mir_def_id(), f, o) { - Some(param) => param, - None => return, + let Some(param) = find_param_with_region(tcx, self.mir_def_id(), f, o) else { + return; }; debug!(?param); diff --git a/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs index edd7ca578b72..dc174775af2e 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs @@ -67,12 +67,11 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: match context { PlaceContext::NonMutatingUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => { - let path = match self.move_data.rev_lookup.find(place.as_ref()) { - LookupResult::Exact(path) | LookupResult::Parent(Some(path)) => path, - _ => { - // There's no path access to emit. - return; - } + let (LookupResult::Exact(path) | LookupResult::Parent(Some(path))) = + self.move_data.rev_lookup.find(place.as_ref()) + else { + // There's no path access to emit. + return; }; debug!("AccessFactsExtractor - emit path access ({path:?}, {location:?})"); self.facts.path_accessed_at_base.push((path, self.location_to_index(location))); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index ecaf88a26259..33ffe4cc4e9c 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -130,11 +130,9 @@ pub(crate) fn add_function( return; } - let unwind_info = if let Some(unwind_info) = + let Some(unwind_info) = context.compiled_code().unwrap().create_unwind_info(module.isa()).unwrap() - { - unwind_info - } else { + else { return; }; diff --git a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs index c93fe9352103..f38c1f96e6ed 100644 --- a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs +++ b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs @@ -29,11 +29,7 @@ pub(crate) fn maybe_known_branch_taken( arg: Value, test_zero: bool, ) -> Option { - let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) { - arg_inst - } else { - return None; - }; + let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) else { return None }; match bcx.func.dfg.insts[arg_inst] { InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index c7ed887b30d0..39b4bb3ebefa 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -774,24 +774,23 @@ macro_rules! return_error { return Err(()); }}; } - let (elem_ty_str, elem_ty, cast_type) = if let ty::Float(ref f) = *in_elem.kind() { - let elem_ty = bx.cx.type_float_from_ty(*f); - match f.bit_width() { - 16 => ("", elem_ty, Some(bx.cx.double_type)), - 32 => ("f", elem_ty, None), - 64 => ("", elem_ty, None), - _ => { - return_error!(InvalidMonomorphization::FloatingPointVector { - span, - name, - f_ty: *f, - in_ty - }); - } - } - } else { + let ty::Float(ref f) = *in_elem.kind() else { return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); }; + let elem_ty = bx.cx.type_float_from_ty(*f); + let (elem_ty_str, elem_ty, cast_type) = match f.bit_width() { + 16 => ("", elem_ty, Some(bx.cx.double_type)), + 32 => ("f", elem_ty, None), + 64 => ("", elem_ty, None), + _ => { + return_error!(InvalidMonomorphization::FloatingPointVector { + span, + name, + f_ty: *f, + in_ty + }); + } + }; let vec_ty = bx.cx.type_vector(elem_ty, in_len); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 33541f7b695f..e43bd8c2feef 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1756,11 +1756,10 @@ macro_rules! return_error { }}; } - let elem_ty = if let ty::Float(f) = in_elem.kind() { - bx.cx.type_float_from_ty(*f) - } else { + let ty::Float(f) = in_elem.kind() else { return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); }; + let elem_ty = bx.cx.type_float_from_ty(*f); let vec_ty = bx.type_vector(elem_ty, in_len); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 0ab0cb0ef88a..bfbe7bc20052 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -721,11 +721,10 @@ pub fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { }; // First read the ret symbol from the attribute - let ret_symbol = if let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity { - p1.segments.first().unwrap().ident - } else { + let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity else { span_bug!(attr.span(), "rustc_autodiff attribute must contain the return activity"); }; + let ret_symbol = p1.segments.first().unwrap().ident; // Then parse it into an actual DiffActivity let Ok(ret_activity) = DiffActivity::from_str(ret_symbol.as_str()) else { diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index c548cea537f4..8d2cc23f9763 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -788,11 +788,10 @@ pub fn compile_declarative_macro( let lhs_span = lhs_tt.span(); // Convert the lhs into `MatcherLoc` form, which is better for doing the // actual matching. - let lhs = if let mbe::TokenTree::Delimited(.., delimited) = lhs_tt { - mbe::macro_parser::compute_locs(&delimited.tts) - } else { + let mbe::TokenTree::Delimited(.., delimited) = lhs_tt else { return dummy_syn_ext(guar.unwrap()); }; + let lhs = mbe::macro_parser::compute_locs(&delimited.tts); if let Some(args) = args { let args_span = args.span(); let mbe::TokenTree::Delimited(.., delimited) = args else { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 3cfcac5c7291..2e06684e0c7a 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1551,15 +1551,15 @@ fn const_param_default<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> ty::EarlyBinder<'tcx, Const<'tcx>> { - let default_ct = match tcx.hir_node_by_def_id(def_id) { - hir::Node::GenericParam(hir::GenericParam { - kind: hir::GenericParamKind::Const { default: Some(ct), .. }, - .. - }) => ct, - _ => span_bug!( + let hir::Node::GenericParam(hir::GenericParam { + kind: hir::GenericParamKind::Const { default: Some(default_ct), .. }, + .. + }) = tcx.hir_node_by_def_id(def_id) + else { + span_bug!( tcx.def_span(def_id), "`const_param_default` expected a generic parameter with a constant" - ), + ) }; let icx = ItemCtxt::new(tcx, def_id); let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 6b51e3157961..7025f7ac84b0 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -188,29 +188,26 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( for (param, var) in std::iter::zip(&generics.own_params, gat_vars) { let existing = match var.kind() { ty::GenericArgKind::Lifetime(re) => { - if let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = + let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = re.kind() - { - mapping.insert(bv.var, tcx.mk_param_from_def(param)) - } else { + else { return None; - } + }; + mapping.insert(bv.var, tcx.mk_param_from_def(param)) } ty::GenericArgKind::Type(ty) => { - if let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() { - mapping.insert(bv.var, tcx.mk_param_from_def(param)) - } else { + let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() else { return None; - } + }; + mapping.insert(bv.var, tcx.mk_param_from_def(param)) } ty::GenericArgKind::Const(ct) => { - if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = + let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = ct.kind() - { - mapping.insert(bv.var, tcx.mk_param_from_def(param)) - } else { + else { return None; - } + }; + mapping.insert(bv.var, tcx.mk_param_from_def(param)) } }; diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index 30324da3c651..d835a7bbb8d2 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -763,9 +763,8 @@ fn suggest_moving_args_from_assoc_fn_to_trait( &self, err: &mut Diag<'_, impl EmissionGuarantee>, ) { - let trait_ = match self.tcx.trait_of_assoc(self.def_id) { - Some(def_id) => def_id, - None => return, + let Some(trait_) = self.tcx.trait_of_assoc(self.def_id) else { + return; }; // Skip suggestion when the associated function is itself generic, it is unclear @@ -1077,15 +1076,11 @@ fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_, impl EmissionGuar /// Builds the `type defined here` message. fn show_definition(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { - let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) { - if self.tcx.sess.source_map().is_span_accessible(def_span) { - def_span.into() - } else { - return; - } - } else { + let Some(def_span) = self.tcx.def_ident_span(self.def_id) else { return }; + if !self.tcx.sess.source_map().is_span_accessible(def_span) { return; }; + let mut spans: MultiSpan = def_span.into(); let msg = { let def_kind = self.tcx.def_descr(self.def_id); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 600684d4f514..5fc201db68e5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -1749,10 +1749,8 @@ fn generics_args_err_extend<'a>( GenericsArgsErrExtend::SelfTyAlias { def_id, span } => { let ty = tcx.at(span).type_of(def_id).instantiate_identity(); let span_of_impl = tcx.span_of_impl(def_id); - let def_id = match *ty.kind() { - ty::Adt(self_def, _) => self_def.did(), - _ => return, - }; + let ty::Adt(self_def, _) = *ty.kind() else { return }; + let def_id = self_def.did(); let type_name = tcx.item_name(def_id); let span_of_ty = tcx.def_ident_span(def_id); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index f59fcab46661..714c6a104a9e 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -458,15 +458,14 @@ fn identify_bad_closure_def_and_call( { // Actually need to unwrap one more layer of HIR to get to // the _real_ closure... - if let hir::Node::Expr(&hir::Expr { + let hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), .. }) = self.tcx.parent_hir_node(parent_hir_id) - { - fn_decl_span - } else { + else { return; - } + }; + fn_decl_span } else { return; }; diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index f1e74028f4ce..3f214b4d2fcc 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -415,11 +415,8 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { }); Some(self.resolve_vars_if_possible(possible_rcvr_ty)) }); - if let Some(rcvr_ty) = possible_rcvr_ty { - rcvr_ty - } else { - return false; - } + let Some(rcvr_ty) = possible_rcvr_ty else { return false }; + rcvr_ty } }; diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 561230c193ce..27b66d07f98e 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -1561,19 +1561,15 @@ fn cat_deref( base_place: PlaceWithHirId<'tcx>, ) -> Result, Cx::Error> { let base_curr_ty = base_place.place.ty(); - let deref_ty = match self + let Some(deref_ty) = self .cx .structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty) .builtin_deref(true) - { - Some(ty) => ty, - None => { - debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); - return Err(self.cx.report_bug( - self.cx.tcx().hir_span(node), - "explicit deref of non-derefable type", - )); - } + else { + debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); + return Err(self + .cx + .report_bug(self.cx.tcx().hir_span(node), "explicit deref of non-derefable type")); }; let mut projections = base_place.place.projections; projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty }); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 854202c31270..5c04f2b5f63c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -48,33 +48,28 @@ pub(crate) fn adjust_fulfillment_error_for_expr_obligation( }; let uninstantiated_pred = match flavor { - ClauseFlavor::Where => { + ClauseFlavor::Where if let Some(pred) = self .tcx .predicates_of(def_id) .instantiate_identity(self.tcx) .predicates .into_iter() - .nth(idx) - { - pred - } else { - return false; - } + .nth(idx) => + { + pred } - ClauseFlavor::Const => { + ClauseFlavor::Const if let Some((pred, _)) = self .tcx .const_conditions(def_id) .instantiate_identity(self.tcx) .into_iter() - .nth(idx) - { - pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe) - } else { - return false; - } + .nth(idx) => + { + pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe) } + _ => return false, }; let generics = self.tcx.generics_of(def_id); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 57da450d832c..d04133ccee97 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1467,11 +1467,8 @@ fn label_fn_like( _ => None, } }); - if let Some(new_def_id) = new_def_id { - def_id = new_def_id; - } else { - return; - } + let Some(new_def_id) = new_def_id else { return }; + def_id = new_def_id; } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1adcd91cc3ee..d51b052e0d1b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1795,7 +1795,7 @@ pub(crate) fn suggest_associated_const( Some(ty), hir::Path { segments: [segment], .. }, )) - | hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => { + | hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) if let Some(self_ty) = self.typeck_results.borrow().node_type_opt(ty.hir_id) && let Ok(pick) = self.probe_for_name( Mode::Path, @@ -1805,12 +1805,9 @@ pub(crate) fn suggest_associated_const( self_ty, expr.hir_id, ProbeScope::TraitsInScope, - ) - { - (pick.item, segment) - } else { - return false; - } + ) => + { + (pick.item, segment) } hir::ExprKind::Path(QPath::Resolved( None, @@ -1821,16 +1818,15 @@ pub(crate) fn suggest_associated_const( if old_item_name != segment.ident.name { return false; } - if let Some(item) = self + let Some(item) = self .tcx .associated_items(self.tcx.parent(old_def_id)) .filter_by_name_unhygienic(capitalized_name) .next() - { - (*item, segment) - } else { + else { return false; - } + }; + (*item, segment) } _ => return false, }; diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index 6460bd72c797..6626c3edb546 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -121,13 +121,12 @@ fn get_asm_ty( len, ) }; - if let Some(len) = len.try_to_target_usize(self.tcx()) { - (len, ty) - } else { + let Some(len) = len.try_to_target_usize(self.tcx()) else { return Err(NonAsmTypeReason::UnevaluatedSIMDArrayLength( field.did, len, )); - } + }; + (len, ty) } _ => (fields.len() as u64, elem_ty), }; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 4b9ad345210d..d31cd8569bb7 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3543,10 +3543,8 @@ fn suggest_await_before_method( span: Span, return_type: Option>, ) { - let output_ty = match self.err_ctxt().get_impl_future_output_ty(ty) { - Some(output_ty) => self.resolve_vars_if_possible(output_ty), - _ => return, - }; + let Some(output_ty) = self.err_ctxt().get_impl_future_output_ty(ty) else { return }; + let output_ty = self.resolve_vars_if_possible(output_ty); let method_exists = self.method_exists_for_diagnostic(item_name, output_ty, call.hir_id, return_type); debug!("suggest_await_before_method: is_method_exist={}", method_exists); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 87b208923ddb..810760e9f53e 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1072,11 +1072,8 @@ fn get_transmute_from_to<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, ) -> Option<(Ty<'tcx>, Ty<'tcx>)> { - let def = if let hir::ExprKind::Path(ref qpath) = expr.kind { - cx.qpath_res(qpath, expr.hir_id) - } else { - return None; - }; + let hir::ExprKind::Path(ref qpath) = expr.kind else { return None }; + let def = cx.qpath_res(qpath, expr.hir_id); if let Res::Def(DefKind::Fn, did) = def { if !def_id_is_transmute(cx, did) { return None; diff --git a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs index f20605c91495..9220702c21f1 100644 --- a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs +++ b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs @@ -120,10 +120,8 @@ fn check_tokens(&mut self, cx: &crate::EarlyContext<'_>, tokens: &TokenStream) { fn check_ident_token(&mut self, cx: &crate::EarlyContext<'_>, token: &Token) { debug!("check_ident_token: {:?}", token); - let (sym, edition) = match token.kind { - TokenKind::Ident(sym, _) => (sym, Edition::Edition2024), - _ => return, - }; + let TokenKind::Ident(sym, _) = token.kind else { return }; + let edition = Edition::Edition2024; debug!("token.span.edition(): {:?}", token.span.edition()); if token.span.edition() >= edition { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 2e64fc290fcc..279c34cb275d 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -706,12 +706,9 @@ fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result, Self::Error> { | Bound(_, _) | Placeholder(_) | Error(_) => { - if let Some(placeholder) = self.placeholder { - // We replace these with infer (which is passed in from an infcx). - placeholder - } else { - return Err(()); - } + let Some(placeholder) = self.placeholder else { return Err(()) }; + // We replace these with infer (which is passed in from an infcx). + placeholder } Alias(Opaque, AliasTy { def_id, .. }) => { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6ca4949910f2..4e7e1da03e9f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2395,9 +2395,7 @@ fn typetree_from_ty_impl_inner<'tcx>( } if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() { - let inner_ty = if let Some(inner) = ty.builtin_deref(true) { - inner - } else { + let Some(inner_ty) = ty.builtin_deref(true) else { return TypeTree::new(); }; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 72573d96dc54..852a0017687f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1528,18 +1528,13 @@ pub fn find_async_drop_impl_coroutine)>( let mut cor_ty = self; let mut ty = cor_ty; loop { - if let ty::Coroutine(def_id, args) = ty.kind() { - cor_ty = ty; - f(ty); - if tcx.is_async_drop_in_place_coroutine(*def_id) { - ty = args.first().unwrap().expect_ty(); - continue; - } else { - return cor_ty; - } - } else { + let ty::Coroutine(def_id, args) = ty.kind() else { return cor_ty }; + cor_ty = ty; + f(ty); + if !tcx.is_async_drop_in_place_coroutine(*def_id) { return cor_ty; } + ty = args.first().unwrap().expect_ty(); } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index 6faef3e974a0..800d4e406cf0 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -100,11 +100,8 @@ pub fn find_descendant( move_paths: &IndexSlice>, f: impl Fn(MovePathIndex) -> bool, ) -> Option { - let mut todo = if let Some(child) = self.first_child { - vec![child] - } else { - return None; - }; + let Some(child) = self.first_child else { return None }; + let mut todo = vec![child]; while let Some(mpi) = todo.pop() { if f(mpi) { @@ -331,11 +328,10 @@ pub fn find(&self, place: PlaceRef<'tcx>) -> LookupResult { MoveSubPathResult::Stop => None, }; - if let Some(&subpath) = subpath { - result = subpath; - } else { + let Some(&subpath) = subpath else { return LookupResult::Parent(Some(result)); - } + }; + result = subpath; } LookupResult::Exact(result) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index b1ff7ffc60ed..daf304c1bf9d 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -721,11 +721,8 @@ pub fn for_each_aliasing_place( // Enum variant fields and enum discriminants alias each another. self.for_each_variant_sibling(index, sub, f); } - if let Some(sub) = sub { - index = sub - } else { - return; - } + let Some(sub) = sub else { return }; + index = sub; } self.for_each_value_inside(index, f); } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index ebfeba5ad225..92c74e7fc276 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -590,31 +590,30 @@ fn eval_to_const_inner(&mut self, value: VnIndex) -> Option> { let fields = fields.iter().map(|&f| self.eval_to_const(f)).collect::>>()?; let variant = if ty.ty.is_enum() { Some(variant) } else { None }; - if matches!(ty.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) - { - let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; - let variant_dest = if let Some(variant) = variant { - self.ecx.project_downcast(&dest, variant).discard_err()? - } else { - dest.clone() - }; - for (field_index, op) in fields.into_iter().enumerate() { - let field_dest = self - .ecx - .project_field(&variant_dest, FieldIdx::from_usize(field_index)) - .discard_err()?; - self.ecx.copy_op(op, &field_dest).discard_err()?; - } - self.ecx - .write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest) - .discard_err()?; - self.ecx - .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) - .discard_err()?; - dest.into() - } else { + let (BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) = ty.backend_repr + else { return None; + }; + let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; + let variant_dest = if let Some(variant) = variant { + self.ecx.project_downcast(&dest, variant).discard_err()? + } else { + dest.clone() + }; + for (field_index, op) in fields.into_iter().enumerate() { + let field_dest = self + .ecx + .project_field(&variant_dest, FieldIdx::from_usize(field_index)) + .discard_err()?; + self.ecx.copy_op(op, &field_dest).discard_err()?; } + self.ecx + .write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest) + .discard_err()?; + self.ecx + .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) + .discard_err()?; + dest.into() } Union(active_field, field) => { let field = self.eval_to_const(field)?; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 6b0c331ff541..7d631e96c32a 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -410,14 +410,8 @@ fn validate_ref(&mut self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] // is allowed right now. - if let ty::Array(_, len) = ty.kind() { - match len.try_to_target_usize(self.tcx) { - Some(0) => {} - _ => return Err(Unpromotable), - } - } else { - return Err(Unpromotable); - } + let ty::Array(_, len) = ty.kind() else { return Err(Unpromotable) }; + let Some(0) = len.try_to_target_usize(self.tcx) else { return Err(Unpromotable) }; } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 8d0a3ac94d5a..1c79a2fd65de 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -810,18 +810,16 @@ pub(super) fn next_term_infer_of_kind(&mut self, term: I::Term) -> I::Term { pub(super) fn term_is_fully_unconstrained(&self, goal: Goal>) -> bool { let universe_of_term = match goal.predicate.term.kind() { ty::TermKind::Ty(ty) => { - if let ty::Infer(ty::TyVar(vid)) = ty.kind() { - self.delegate.universe_of_ty(vid).unwrap() - } else { + let ty::Infer(ty::TyVar(vid)) = ty.kind() else { return false; - } + }; + self.delegate.universe_of_ty(vid).unwrap() } ty::TermKind::Const(ct) => { - if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { - self.delegate.universe_of_ct(vid).unwrap() - } else { + let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() else { return false; - } + }; + self.delegate.universe_of_ct(vid).unwrap() } }; diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index c65e0bb25897..70c28421c57e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -445,17 +445,15 @@ fn consider_builtin_fn_trait_candidates( goal_kind: ty::ClosureKind, ) -> Result, NoSolution> { let cx = ecx.cx(); - let tupled_inputs_and_output = - match structural_traits::extract_tupled_inputs_and_output_from_callable( + let Some(tupled_inputs_and_output) = + structural_traits::extract_tupled_inputs_and_output_from_callable( cx, goal.predicate.self_ty(), goal_kind, - )? { - Some(tupled_inputs_and_output) => tupled_inputs_and_output, - None => { - return ecx.forced_ambiguity(MaybeCause::Ambiguity); - } - }; + )? + else { + return ecx.forced_ambiguity(MaybeCause::Ambiguity); + }; let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output); // A built-in `Fn` impl only holds if the output is sized. diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 168921655a39..651f073efb82 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -360,17 +360,15 @@ fn consider_builtin_fn_trait_candidates( } let cx = ecx.cx(); - let tupled_inputs_and_output = - match structural_traits::extract_tupled_inputs_and_output_from_callable( + let Some(tupled_inputs_and_output) = + structural_traits::extract_tupled_inputs_and_output_from_callable( cx, goal.predicate.self_ty(), goal_kind, - )? { - Some(a) => a, - None => { - return ecx.forced_ambiguity(MaybeCause::Ambiguity); - } - }; + )? + else { + return ecx.forced_ambiguity(MaybeCause::Ambiguity); + }; let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output); // A built-in `Fn` impl only holds if the output is sized. @@ -1409,42 +1407,39 @@ pub(super) fn merge_trait_candidates( let where_bounds: Vec<_> = candidates .extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_))) .collect(); - if let Some((response, info)) = self.try_merge_candidates(&where_bounds) { - match info { - // If there's an always applicable candidate, the result of all - // other candidates does not matter. This means we can ignore - // them when checking whether we've reached a fixpoint. - // - // We always prefer the first always applicable candidate, even if a - // later candidate is also always applicable and would result in fewer - // reruns. We could slightly improve this by e.g. searching for another - // always applicable candidate which doesn't depend on any cycle heads. - // - // NOTE: This is optimization is observable in case there is an always - // applicable global candidate and another non-global candidate which only - // applies because of a provisional result. I can't even think of a test - // case where this would occur and even then, this would not be unsound. - // Supporting this makes the code more involved, so I am just going to - // ignore this for now. - MergeCandidateInfo::AlwaysApplicable(i) => { - for (j, c) in where_bounds.into_iter().enumerate() { - if i != j { - self.ignore_candidate_head_usages(c.head_usages) - } - } - // If a where-bound does not apply, we don't actually get a - // candidate for it. We manually track the head usages - // of all failed `ParamEnv` candidates instead. - self.ignore_candidate_head_usages( - failed_candidate_info.param_env_head_usages, - ); - } - MergeCandidateInfo::EqualResponse => {} - } - return Ok((response, Some(TraitGoalProvenVia::ParamEnv))); - } else { + let Some((response, info)) = self.try_merge_candidates(&where_bounds) else { return Ok((self.bail_with_ambiguity(&where_bounds), None)); }; + match info { + // If there's an always applicable candidate, the result of all + // other candidates does not matter. This means we can ignore + // them when checking whether we've reached a fixpoint. + // + // We always prefer the first always applicable candidate, even if a + // later candidate is also always applicable and would result in fewer + // reruns. We could slightly improve this by e.g. searching for another + // always applicable candidate which doesn't depend on any cycle heads. + // + // NOTE: This is optimization is observable in case there is an always + // applicable global candidate and another non-global candidate which only + // applies because of a provisional result. I can't even think of a test + // case where this would occur and even then, this would not be unsound. + // Supporting this makes the code more involved, so I am just going to + // ignore this for now. + MergeCandidateInfo::AlwaysApplicable(i) => { + for (j, c) in where_bounds.into_iter().enumerate() { + if i != j { + self.ignore_candidate_head_usages(c.head_usages) + } + } + // If a where-bound does not apply, we don't actually get a + // candidate for it. We manually track the head usages + // of all failed `ParamEnv` candidates instead. + self.ignore_candidate_head_usages(failed_candidate_info.param_env_head_usages); + } + MergeCandidateInfo::EqualResponse => {} + } + return Ok((response, Some(TraitGoalProvenVia::ParamEnv))); } // Next, prefer any alias bound (nested or otherwise). diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 069944b638c7..233a4c48862a 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1537,86 +1537,80 @@ fn get_single_associated_item( /// Given `where ::Baz: String`, suggest `where T: Bar`. fn restrict_assoc_type_in_where_clause(&self, span: Span, err: &mut Diag<'_>) -> bool { // Detect that we are actually in a `where` predicate. - let (bounded_ty, bounds, where_span) = if let Some(ast::WherePredicate { + let Some(ast::WherePredicate { kind: ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate { bounded_ty, bound_generic_params, bounds, }), - span, + span: where_span, .. }) = self.diag_metadata.current_where_predicate - { - if !bound_generic_params.is_empty() { - return false; - } - (bounded_ty, bounds, span) - } else { + else { return false; }; + if !bound_generic_params.is_empty() { + return false; + } // Confirm that the target is an associated type. - let (ty, _, path) = if let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind { - // use this to verify that ident is a type param. - let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { - return false; - }; - if !matches!( - partial_res.full_res(), - Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _)) - ) { - return false; - } - (&qself.ty, qself.position, path) - } else { + let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind else { return false }; + // use this to verify that ident is a type param. + let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { return false }; + if !matches!( + partial_res.full_res(), + Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _)) + ) { + return false; + } + + let peeled_ty = qself.ty.peel_refs(); + let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind else { return false }; + // Confirm that the `SelfTy` is a type parameter. + let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else { return false; }; - - let peeled_ty = ty.peel_refs(); - if let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind { - // Confirm that the `SelfTy` is a type parameter. - let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else { + if !matches!( + partial_res.full_res(), + Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _)) + ) { + return false; + } + let ([ast::PathSegment { args: None, .. }], [ast::GenericBound::Trait(poly_trait_ref)]) = + (&type_param_path.segments[..], &bounds[..]) + else { + return false; + }; + let [ast::PathSegment { ident, args: None, id }] = + &poly_trait_ref.trait_ref.path.segments[..] + else { + return false; + }; + if poly_trait_ref.modifiers != ast::TraitBoundModifiers::NONE { + return false; + } + if ident.span == span { + let Some(partial_res) = self.r.partial_res_map.get(&id) else { return false; }; - if !matches!( - partial_res.full_res(), - Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _)) - ) { + if !matches!(partial_res.full_res(), Some(hir::def::Res::Def(..))) { return false; } - if let ( - [ast::PathSegment { args: None, .. }], - [ast::GenericBound::Trait(poly_trait_ref)], - ) = (&type_param_path.segments[..], &bounds[..]) - && let [ast::PathSegment { ident, args: None, id }] = - &poly_trait_ref.trait_ref.path.segments[..] - && poly_trait_ref.modifiers == ast::TraitBoundModifiers::NONE - { - if ident.span == span { - let Some(partial_res) = self.r.partial_res_map.get(&id) else { - return false; - }; - if !matches!(partial_res.full_res(), Some(hir::def::Res::Def(..))) { - return false; - } - let Some(new_where_bound_predicate) = - mk_where_bound_predicate(path, poly_trait_ref, ty) - else { - return false; - }; - err.span_suggestion_verbose( - *where_span, - format!("constrain the associated type to `{ident}`"), - where_bound_predicate_to_string(&new_where_bound_predicate), - Applicability::MaybeIncorrect, - ); - } - return true; - } + let Some(new_where_bound_predicate) = + mk_where_bound_predicate(path, poly_trait_ref, &qself.ty) + else { + return false; + }; + err.span_suggestion_verbose( + *where_span, + format!("constrain the associated type to `{ident}`"), + where_bound_predicate_to_string(&new_where_bound_predicate), + Applicability::MaybeIncorrect, + ); } - false + true } /// Check if the source is call expression and the first argument is `self`. If true, From a49c17538009294569a4658d61283823ab6adea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Dec 2025 00:54:18 +0000 Subject: [PATCH 575/585] `#![deny(clippy::manual_let_else)]` in some rustc modules --- compiler/rustc_ast/src/lib.rs | 1 + compiler/rustc_borrowck/src/lib.rs | 1 + compiler/rustc_const_eval/src/lib.rs | 1 + compiler/rustc_hir/src/lib.rs | 1 + compiler/rustc_hir_analysis/src/lib.rs | 1 + compiler/rustc_hir_typeck/src/lib.rs | 1 + compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_next_trait_solver/src/lib.rs | 1 + compiler/rustc_resolve/src/lib.rs | 1 + 10 files changed, 10 insertions(+) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index cbdc89f9deed..10a8e181c840 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -6,6 +6,7 @@ // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(array_windows))] +#![deny(clippy::manual_let_else)] #![doc(test(attr(deny(warnings), allow(internal_features))))] #![feature(associated_type_defaults)] #![feature(box_patterns)] diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8d61ffde116c..d82357fca2d4 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,6 +2,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(file_buffered)] diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 2fce4b8c0566..6c74ed2a5121 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,5 +1,6 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] +#![deny(clippy::manual_let_else)] #![feature(array_try_map)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 7a5776f0d5a9..c27954b6d14e 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -4,6 +4,7 @@ // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(debug_closure_helpers))] +#![deny(clippy::manual_let_else)] #![feature(associated_type_defaults)] #![feature(closure_track_caller)] #![feature(const_default)] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 538fb8c7df1e..79c5fbab1ffa 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -59,6 +59,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![cfg_attr(bootstrap, feature(debug_closure_helpers))] +#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(gen_blocks)] #![feature(if_let_guard)] diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index d3ef1d63e8ba..9ca5ddd494ae 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 4e7a3e405176..49929a0a9bc7 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -22,6 +22,7 @@ // tidy-alphabetical-start #![allow(internal_features)] #![cfg_attr(bootstrap, feature(array_windows))] +#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 5f62d44df6b6..ee3e89e57bd4 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -30,6 +30,7 @@ #![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::untranslatable_diagnostic)] #![cfg_attr(bootstrap, feature(array_windows))] +#![deny(clippy::manual_let_else)] #![feature(allocator_api)] #![feature(assert_matches)] #![feature(associated_type_defaults)] diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index 5fa29b7d9f81..117751810e29 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -8,6 +8,7 @@ #![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::usage_of_type_ir_inherent)] #![allow(rustc::usage_of_type_ir_traits)] +#![deny(clippy::manual_let_else)] // tidy-alphabetical-end pub mod canonical; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0b4ec6956bd1..38cf83dc23f7 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -10,6 +10,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![deny(clippy::manual_let_else)] #![feature(arbitrary_self_types)] #![feature(assert_matches)] #![feature(box_patterns)] From 97c774215165b7422c2e6e18e52fc5d63f8669ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 12 Dec 2025 17:55:26 +0000 Subject: [PATCH 576/585] revert one change from rustc_next_trait_solver --- compiler/rustc_next_trait_solver/src/lib.rs | 1 - .../src/solve/eval_ctxt/mod.rs | 14 ++++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index 117751810e29..5fa29b7d9f81 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -8,7 +8,6 @@ #![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::usage_of_type_ir_inherent)] #![allow(rustc::usage_of_type_ir_traits)] -#![deny(clippy::manual_let_else)] // tidy-alphabetical-end pub mod canonical; diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 1c79a2fd65de..8d0a3ac94d5a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -810,16 +810,18 @@ pub(super) fn next_term_infer_of_kind(&mut self, term: I::Term) -> I::Term { pub(super) fn term_is_fully_unconstrained(&self, goal: Goal>) -> bool { let universe_of_term = match goal.predicate.term.kind() { ty::TermKind::Ty(ty) => { - let ty::Infer(ty::TyVar(vid)) = ty.kind() else { + if let ty::Infer(ty::TyVar(vid)) = ty.kind() { + self.delegate.universe_of_ty(vid).unwrap() + } else { return false; - }; - self.delegate.universe_of_ty(vid).unwrap() + } } ty::TermKind::Const(ct) => { - let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() else { + if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { + self.delegate.universe_of_ct(vid).unwrap() + } else { return false; - }; - self.delegate.universe_of_ct(vid).unwrap() + } } }; From 1b9b4f4dc69302c80925ed910e7e94766d88db63 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Sat, 13 Dec 2025 10:12:17 +0100 Subject: [PATCH 577/585] time: Test and document time precision edge-case There is a slight edge case when adding and subtracting a `Duration` from a `SystemTime`, namely when the duration itself is finer/smaller than the time precision on the operating systems. On most (if not all non-Windows) operating systems, the precision of `Duration` aligns with the `SystemTime`, both being one nanosecond. However, on Windows, this time precision is 100ns, meaning that adding or subtracting a `Duration` whose value is `< Duration::new(0, 100)` will result in that method behaving like an addition/subtracting of `Duration::ZERO`, due to the `Duration` getting rounded-down to the zero value. --- library/std/src/time.rs | 32 ++++++++++++++++++++++++++------ library/std/tests/time.rs | 17 ++++++++++++----- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 0bda83af4dfb..67c144be14f6 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -514,7 +514,9 @@ impl SystemTime { /// Represents the maximum value representable by [`SystemTime`] on this platform. /// /// This value differs a lot between platforms, but it is always the case - /// that any positive addition to [`SystemTime::MAX`] will fail. + /// that any positive addition of a [`Duration`], whose value is greater + /// than or equal to the time precision of the operating system, to + /// [`SystemTime::MAX`] will fail. /// /// # Examples /// @@ -525,8 +527,13 @@ impl SystemTime { /// // Adding zero will change nothing. /// assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX)); /// - /// // But adding just 1ns will already fail. - /// assert_eq!(SystemTime::MAX.checked_add(Duration::new(0, 1)), None); + /// // But adding just one second will already fail ... + /// // + /// // Keep in mind that this in fact may succeed, if the Duration is + /// // smaller than the time precision of the operating system, which + /// // happens to be 1ns on most operating systems, with Windows being the + /// // notable exception by using 100ns, hence why this example uses 1s. + /// assert_eq!(SystemTime::MAX.checked_add(Duration::new(1, 0)), None); /// /// // Utilize this for saturating arithmetic to improve error handling. /// // In this case, we will use a certificate with a timestamp in the @@ -543,7 +550,9 @@ impl SystemTime { /// Represents the minimum value representable by [`SystemTime`] on this platform. /// /// This value differs a lot between platforms, but it is always the case - /// that any positive subtraction from [`SystemTime::MIN`] will fail. + /// that any positive subtraction of a [`Duration`] from, whose value is + /// greater than or equal to the time precision of the operating system, to + /// [`SystemTime::MIN`] will fail. /// /// Depending on the platform, this may be either less than or equal to /// [`SystemTime::UNIX_EPOCH`], depending on whether the operating system @@ -560,8 +569,13 @@ impl SystemTime { /// // Subtracting zero will change nothing. /// assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN)); /// - /// // But subtracting just 1ns will already fail. - /// assert_eq!(SystemTime::MIN.checked_sub(Duration::new(0, 1)), None); + /// // But subtracting just one second will already fail. + /// // + /// // Keep in mind that this in fact may succeed, if the Duration is + /// // smaller than the time precision of the operating system, which + /// // happens to be 1ns on most operating systems, with Windows being the + /// // notable exception by using 100ns, hence why this example uses 1s. + /// assert_eq!(SystemTime::MIN.checked_sub(Duration::new(1, 0)), None); /// /// // Utilize this for saturating arithmetic to improve error handling. /// // In this case, we will use a cache expiry as a practical example. @@ -651,6 +665,9 @@ pub fn elapsed(&self) -> Result { /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None` /// otherwise. + /// + /// In the case that the `duration` is smaller than the time precision of the operating + /// system, `Some(self)` will be returned. #[stable(feature = "time_checked_add", since = "1.34.0")] pub fn checked_add(&self, duration: Duration) -> Option { self.0.checked_add_duration(&duration).map(SystemTime) @@ -659,6 +676,9 @@ pub fn checked_add(&self, duration: Duration) -> Option { /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None` /// otherwise. + /// + /// In the case that the `duration` is smaller than the time precision of the operating + /// system, `Some(self)` will be returned. #[stable(feature = "time_checked_add", since = "1.34.0")] pub fn checked_sub(&self, duration: Duration) -> Option { self.0.checked_sub_duration(&duration).map(SystemTime) diff --git a/library/std/tests/time.rs b/library/std/tests/time.rs index 31cc7171fe52..0ef89bb09c63 100644 --- a/library/std/tests/time.rs +++ b/library/std/tests/time.rs @@ -250,15 +250,22 @@ fn system_time_duration_since_max_range_on_unix() { #[test] fn system_time_max_min() { + #[cfg(not(target_os = "windows"))] + /// Most (all?) non-Windows systems have nanosecond precision. + const MIN_INTERVAL: Duration = Duration::new(0, 1); + #[cfg(target_os = "windows")] + /// Windows' time precision is at 100ns. + const MIN_INTERVAL: Duration = Duration::new(0, 100); + // First, test everything with checked_* and Duration::ZERO. assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX)); assert_eq!(SystemTime::MAX.checked_sub(Duration::ZERO), Some(SystemTime::MAX)); assert_eq!(SystemTime::MIN.checked_add(Duration::ZERO), Some(SystemTime::MIN)); assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN)); - // Now do the same again with checked_* but try by ± a single nanosecond. - assert!(SystemTime::MAX.checked_add(Duration::new(0, 1)).is_none()); - assert!(SystemTime::MAX.checked_sub(Duration::new(0, 1)).is_some()); - assert!(SystemTime::MIN.checked_add(Duration::new(0, 1)).is_some()); - assert!(SystemTime::MIN.checked_sub(Duration::new(0, 1)).is_none()); + // Now do the same again with checked_* but try by ± the lowest time precision. + assert!(SystemTime::MAX.checked_add(MIN_INTERVAL).is_none()); + assert!(SystemTime::MAX.checked_sub(MIN_INTERVAL).is_some()); + assert!(SystemTime::MIN.checked_add(MIN_INTERVAL).is_some()); + assert!(SystemTime::MIN.checked_sub(MIN_INTERVAL).is_none()); } From 0ecf91a701b0c4258dba75acde7dadf0586c7ed2 Mon Sep 17 00:00:00 2001 From: nxsaken Date: Sat, 13 Dec 2025 14:00:44 +0400 Subject: [PATCH 578/585] Use an explicit receiver in `DropGuard::dismiss` --- library/core/src/mem/drop_guard.rs | 10 +++++----- library/coretests/tests/mem.rs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/core/src/mem/drop_guard.rs b/library/core/src/mem/drop_guard.rs index 013134727b7f..74bf35390745 100644 --- a/library/core/src/mem/drop_guard.rs +++ b/library/core/src/mem/drop_guard.rs @@ -79,30 +79,30 @@ pub const fn new(inner: T, f: F) -> Self { /// /// let value = String::from("Nori likes chicken"); /// let guard = DropGuard::new(value, |s| println!("{s}")); - /// assert_eq!(guard.dismiss(), "Nori likes chicken"); + /// assert_eq!(DropGuard::dismiss(guard), "Nori likes chicken"); /// ``` #[unstable(feature = "drop_guard", issue = "144426")] #[rustc_const_unstable(feature = "const_drop_guard", issue = "none")] #[inline] - pub const fn dismiss(self) -> T + pub const fn dismiss(guard: Self) -> T where F: [const] Destruct, { // First we ensure that dropping the guard will not trigger // its destructor - let mut this = ManuallyDrop::new(self); + let mut guard = ManuallyDrop::new(guard); // Next we manually read the stored value from the guard. // // SAFETY: this is safe because we've taken ownership of the guard. - let value = unsafe { ManuallyDrop::take(&mut this.inner) }; + let value = unsafe { ManuallyDrop::take(&mut guard.inner) }; // Finally we drop the stored closure. We do this *after* having read // the value, so that even if the closure's `drop` function panics, // unwinding still tries to drop the value. // // SAFETY: this is safe because we've taken ownership of the guard. - unsafe { ManuallyDrop::drop(&mut this.f) }; + unsafe { ManuallyDrop::drop(&mut guard.f) }; value } } diff --git a/library/coretests/tests/mem.rs b/library/coretests/tests/mem.rs index 00582109aa2c..5247e01fba01 100644 --- a/library/coretests/tests/mem.rs +++ b/library/coretests/tests/mem.rs @@ -815,7 +815,7 @@ fn drop_guard_into_inner() { let dropped = Cell::new(false); let value = DropGuard::new(42, |_| dropped.set(true)); let guard = DropGuard::new(value, |_| dropped.set(true)); - let inner = guard.dismiss(); + let inner = DropGuard::dismiss(guard); assert_eq!(dropped.get(), false); assert_eq!(*inner, 42); } @@ -837,7 +837,7 @@ fn drop_guard_always_drops_value_if_closure_drop_unwinds() { // run the destructor of the value we passed, which we validate. let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { let guard = DropGuard::new(value_with_tracked_destruction, closure_that_panics_on_drop); - guard.dismiss(); + DropGuard::dismiss(guard); })); assert!(value_was_dropped); } From d80348b6c9c72c8d9bd32e764c531958160d6327 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Sat, 13 Dec 2025 10:09:20 +0100 Subject: [PATCH 579/585] time: Fix Windows' `SystemTime::checked_sub` The Windows implementation of `SystemTime::checked_sub` contains a bug, namely that it does not return `None` on values below 1601. This bug stems from the fact that internally, the time gets converted to an i64, with zero representing the anchor in 1601. Of course, performing checked subtraction on a signed integer generally works fine. However, the resulting value delivers undefined behavior on Windows systems. To mitigate this issue, we try to convert the resulting i64 to an u64 because a negative value should obviously fail there. --- library/std/src/sys/pal/windows/time.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index 88f4d4cdbd61..6cccf090a3fc 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -111,8 +111,13 @@ pub fn checked_add_duration(&self, other: &Duration) -> Option { } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?; - Some(SystemTime::from_intervals(intervals)) + // Windows does not support times before 1601, hence why we don't + // support negatives. In order to tackle this, we try to convert the + // resulting value into an u64, which should obviously fail in the case + // that the value is below zero. + let intervals: u64 = + self.intervals().checked_sub(checked_dur2intervals(other)?)?.try_into().ok()?; + Some(SystemTime::from_intervals(intervals as i64)) } } From d484f9361eef9078b729990fd1ba8a40af8bdb6f Mon Sep 17 00:00:00 2001 From: Eli Ozcan <62805599+elijah629@users.noreply.github.com> Date: Sat, 13 Dec 2025 17:12:28 +0000 Subject: [PATCH 580/585] Fix typo in armv7a-vex-v5 documentation --- src/doc/rustc/src/platform-support/armv7a-vex-v5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md index 3677f8931dd6..68fbec2ff4b4 100644 --- a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md +++ b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md @@ -21,7 +21,7 @@ This target is cross-compiled. Dynamic linking is unsupported. `#![no_std]` crates can be built using `build-std` to build `core` and `panic_abort` and optionally `alloc`. Unwinding panics are not yet supported on this target. -`std` has only partial support due platform limitations. Notably: +`std` has only partial support due to platform limitations. Notably: - `std::process` and `std::net` are unimplemented. `std::thread` only supports sleeping and yielding, as this is a single-threaded environment. - `std::time` has full support for `Instant`, but no support for `SystemTime`. - `std::io` has full support for `stdin`/`stdout`/`stderr`. `stdout` and `stderr` both write to to USB channel 1 on this platform and are not differentiated. From 48b0f834ea3cbf04be98f6329f231bd8eaf4488f Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 12 Dec 2025 17:51:30 -0500 Subject: [PATCH 581/585] Update cargo submodule --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 2c283a9a5c59..e91b2baa632c 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 2c283a9a5c5968eeb9a8f12313f04feb1ff8dfac +Subproject commit e91b2baa632c0c7e84216c91ecfe107c37d887c1 From 065e4c1c8a4701d605518f80b26bf031a22f3756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 13 Dec 2025 17:33:34 +0100 Subject: [PATCH 582/585] ignore windows --- tests/ui/eii/codegen_cross_crate.rs | 2 ++ tests/ui/eii/codegen_single_crate.rs | 2 ++ tests/ui/eii/default/call_default.rs | 2 ++ tests/ui/eii/default/call_impl.rs | 2 ++ tests/ui/eii/default/local_crate.rs | 2 ++ tests/ui/eii/default/local_crate_explicit.rs | 2 ++ tests/ui/eii/default/local_crate_explicit.stderr | 2 +- tests/ui/eii/duplicate/duplicate1.rs | 2 ++ tests/ui/eii/duplicate/duplicate2.rs | 2 ++ tests/ui/eii/duplicate/duplicate3.rs | 2 ++ tests/ui/eii/multiple_impls.rs | 2 ++ tests/ui/eii/privacy1.rs | 2 ++ tests/ui/eii/same-symbol.rs | 2 ++ 13 files changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/ui/eii/codegen_cross_crate.rs b/tests/ui/eii/codegen_cross_crate.rs index 760c960297e0..a1fa617491bd 100644 --- a/tests/ui/eii/codegen_cross_crate.rs +++ b/tests/ui/eii/codegen_cross_crate.rs @@ -3,6 +3,8 @@ //@ aux-build: codegen2.rs //@ compile-flags: -O //@ ignore-backends: gcc +// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows // Tests whether calling EIIs works with the declaration in another crate. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/codegen_single_crate.rs b/tests/ui/eii/codegen_single_crate.rs index 00e0abca65f3..8e85c354bba1 100644 --- a/tests/ui/eii/codegen_single_crate.rs +++ b/tests/ui/eii/codegen_single_crate.rs @@ -1,6 +1,8 @@ //@ run-pass //@ check-run-results //@ ignore-backends: gcc +// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows // Tests whether calling EIIs works with the declaration in the same crate. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/default/call_default.rs b/tests/ui/eii/default/call_default.rs index 7b39f6d225af..b479baa80444 100644 --- a/tests/ui/eii/default/call_default.rs +++ b/tests/ui/eii/default/call_default.rs @@ -3,6 +3,8 @@ //@ run-pass //@ check-run-results //@ ignore-backends: gcc +// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows // Functions can have target-cpu applied. On apple-darwin this is super important, // since you can have binaries which mix x86 and aarch64 code that are compatible // with both architectures. So we can't just reject target_cpu on EIIs since apple diff --git a/tests/ui/eii/default/call_impl.rs b/tests/ui/eii/default/call_impl.rs index 2e1cd5e7a966..94b2aa552a1e 100644 --- a/tests/ui/eii/default/call_impl.rs +++ b/tests/ui/eii/default/call_impl.rs @@ -4,6 +4,8 @@ //@ run-pass //@ check-run-results //@ ignore-backends: gcc +// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows // Tests EIIs with default implementations. // When an explicit implementation is given in one dependency, and the declaration is in another, // the explicit implementation is preferred. diff --git a/tests/ui/eii/default/local_crate.rs b/tests/ui/eii/default/local_crate.rs index f229f3cabf0c..d98c2fac4234 100644 --- a/tests/ui/eii/default/local_crate.rs +++ b/tests/ui/eii/default/local_crate.rs @@ -1,6 +1,8 @@ //@ run-pass //@ check-run-results //@ ignore-backends: gcc +// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows // Tests EIIs with default implementations. // In the same crate, when there's no explicit declaration, the default should be called. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/default/local_crate_explicit.rs b/tests/ui/eii/default/local_crate_explicit.rs index e9d879b61c92..a4cc54fcd31f 100644 --- a/tests/ui/eii/default/local_crate_explicit.rs +++ b/tests/ui/eii/default/local_crate_explicit.rs @@ -1,6 +1,8 @@ //@ run-pass //@ check-run-results //@ ignore-backends: gcc +// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows // Tests EIIs with default implementations. // In the same crate, the explicit implementation should get priority. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/default/local_crate_explicit.stderr b/tests/ui/eii/default/local_crate_explicit.stderr index 4102b35bcb5e..d80acf14c516 100644 --- a/tests/ui/eii/default/local_crate_explicit.stderr +++ b/tests/ui/eii/default/local_crate_explicit.stderr @@ -1,5 +1,5 @@ warning: function `decl1` is never used - --> $DIR/local_crate_explicit.rs:9:8 + --> $DIR/local_crate_explicit.rs:11:8 | LL | pub fn decl1(x: u64) { | ^^^^^ diff --git a/tests/ui/eii/duplicate/duplicate1.rs b/tests/ui/eii/duplicate/duplicate1.rs index 2e12d700b0a6..3269778aca0c 100644 --- a/tests/ui/eii/duplicate/duplicate1.rs +++ b/tests/ui/eii/duplicate/duplicate1.rs @@ -2,6 +2,8 @@ //@ aux-build: impl1.rs //@ aux-build: impl2.rs //@ ignore-backends: gcc +// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows // tests that EIIs error properly, even if the conflicting implementations live in another crate. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/duplicate2.rs b/tests/ui/eii/duplicate/duplicate2.rs index 157871d2a3db..4c883d28d74a 100644 --- a/tests/ui/eii/duplicate/duplicate2.rs +++ b/tests/ui/eii/duplicate/duplicate2.rs @@ -3,6 +3,8 @@ //@ aux-build: impl2.rs //@ aux-build: impl3.rs //@ ignore-backends: gcc +// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows // Tests the error message when there are multiple implementations of an EII in many crates. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/duplicate3.rs b/tests/ui/eii/duplicate/duplicate3.rs index 5ac5ae7ff3d4..b04676074509 100644 --- a/tests/ui/eii/duplicate/duplicate3.rs +++ b/tests/ui/eii/duplicate/duplicate3.rs @@ -4,6 +4,8 @@ //@ aux-build: impl3.rs //@ aux-build: impl4.rs //@ ignore-backends: gcc +// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows // Tests the error message when there are multiple implementations of an EII in many crates. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/multiple_impls.rs b/tests/ui/eii/multiple_impls.rs index ec3244137390..c02c783223ac 100644 --- a/tests/ui/eii/multiple_impls.rs +++ b/tests/ui/eii/multiple_impls.rs @@ -1,6 +1,8 @@ //@ run-pass //@ check-run-results //@ ignore-backends: gcc +// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows // Tests whether one function could implement two EIIs. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/privacy1.rs b/tests/ui/eii/privacy1.rs index fc13a27c061e..b5bbf68bfdaf 100644 --- a/tests/ui/eii/privacy1.rs +++ b/tests/ui/eii/privacy1.rs @@ -2,6 +2,8 @@ //@ check-run-results //@ aux-build: codegen1.rs //@ ignore-backends: gcc +// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows // Tests whether re-exports work. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/same-symbol.rs b/tests/ui/eii/same-symbol.rs index d24e5c4266bb..baf36ff4f5a0 100644 --- a/tests/ui/eii/same-symbol.rs +++ b/tests/ui/eii/same-symbol.rs @@ -1,6 +1,8 @@ //@ run-pass //@ check-run-results //@ ignore-backends: gcc +// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows #![feature(extern_item_impls)] pub mod a { From 98e10289ceccdfc93ce5d9fe82b04f125aeb8ede Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Sun, 14 Dec 2025 10:54:27 +0800 Subject: [PATCH 583/585] Enable to ping LoongArch group via triagebot --- triagebot.toml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 3182122bdeb0..1a1f71bd2edd 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -96,6 +96,17 @@ Thanks! <3 """ label = "O-ARM" +[ping.loongarch] +message = """\ +Hey LoongArch Group! This bug has been identified as a good "LoongArch candidate". +In case it's useful, here are some [instructions] for tackling these sorts of +bugs. Maybe take a look? +Thanks! <3 + +[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/loongarch.html +""" +label = "O-loongarch" + [ping.risc-v] message = """\ Hey RISC-V Group! This bug has been identified as a good "RISC-V candidate". From 9dcd2efaa32782e1f5ec8cd689085d2f5ef9c2d8 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 15 Dec 2025 04:25:42 +0000 Subject: [PATCH 584/585] Prepare for merging from rust-lang/rust This updates the rust-version file to 0208ee09be465f69005a7a12c28d5eccac7d5f34. --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 7a84872f266d..dcf82c94aaee 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -dfe1b8c97bcde283102f706d5dcdc3649e5e12e3 +0208ee09be465f69005a7a12c28d5eccac7d5f34 From 964d2922ff8873ea227a6157a0d93e1006a8c28f Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 15 Dec 2025 04:30:49 +0000 Subject: [PATCH 585/585] Format code --- src/tools/rust-analyzer/crates/ide-completion/src/lib.rs | 1 - src/tools/rust-analyzer/crates/parser/src/lib.rs | 4 ++-- src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs | 1 - src/tools/rust-analyzer/crates/project-model/src/lib.rs | 1 - 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index c9d5971cd0e3..33ab43fa614a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -2,7 +2,6 @@ // It's useful to refer to code that is private in doc comments. #![allow(rustdoc::private_intra_doc_links)] - #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #[cfg(feature = "in-rust-tree")] diff --git a/src/tools/rust-analyzer/crates/parser/src/lib.rs b/src/tools/rust-analyzer/crates/parser/src/lib.rs index 81cdc188012c..4478bf4e3733 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lib.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lib.rs @@ -24,9 +24,9 @@ #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_lexer as rustc_lexer; #[cfg(feature = "in-rust-tree")] -extern crate rustc_lexer; -#[cfg(feature = "in-rust-tree")] extern crate rustc_driver as _; +#[cfg(feature = "in-rust-tree")] +extern crate rustc_lexer; mod event; mod frontmatter; diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs index 8e1faca00a1b..85b250eddfd4 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs @@ -11,7 +11,6 @@ feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span) )] #![allow(internal_features)] - #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #[cfg(feature = "in-rust-tree")] diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs index 0d89e13ed374..3414b52d4514 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs @@ -17,7 +17,6 @@ // It's useful to refer to code that is private in doc comments. #![allow(rustdoc::private_intra_doc_links)] - #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #[cfg(feature = "in-rust-tree")]

() -> impl Fn + '_ {} | +++ -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/opaque-used-in-extraneous-argument.rs:5:34 | LL | fn frob() -> impl Fn + '_ {} @@ -90,5 +90,5 @@ LL + open_parent() error: aborting due to 7 previous errors -Some errors have detailed explanations: E0061, E0106, E0412, E0658. +Some errors have detailed explanations: E0061, E0106, E0425, E0658. For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/implied-bounds/references-err.stderr b/tests/ui/implied-bounds/references-err.stderr index df83fce3bdef..9ecda02b1d51 100644 --- a/tests/ui/implied-bounds/references-err.stderr +++ b/tests/ui/implied-bounds/references-err.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `DoesNotExist` in this scope +error[E0425]: cannot find type `DoesNotExist` in this scope --> $DIR/references-err.rs:14:18 | LL | type Assoc = DoesNotExist; @@ -6,4 +6,4 @@ LL | type Assoc = DoesNotExist; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/imports/glob-conflict-cross-crate-2.stderr b/tests/ui/imports/glob-conflict-cross-crate-2.stderr index aebb2d59d063..41912ed63f42 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-2.stderr +++ b/tests/ui/imports/glob-conflict-cross-crate-2.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `C` in this scope +error[E0425]: cannot find type `C` in this scope --> $DIR/glob-conflict-cross-crate-2.rs:8:13 | LL | let _a: C = 1; @@ -6,4 +6,4 @@ LL | let _a: C = 1; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/imports/glob-resolve1.stderr b/tests/ui/imports/glob-resolve1.stderr index 30dddba9e918..1356255a0850 100644 --- a/tests/ui/imports/glob-resolve1.stderr +++ b/tests/ui/imports/glob-resolve1.stderr @@ -68,7 +68,7 @@ help: consider importing this function LL + use other::import; | -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/glob-resolve1.rs:33:11 | LL | pub enum B { @@ -83,7 +83,7 @@ note: enum `bar::A` exists but is inaccessible LL | enum A { | ^^^^^^ not accessible -error[E0412]: cannot find type `C` in this scope +error[E0425]: cannot find type `C` in this scope --> $DIR/glob-resolve1.rs:34:11 | LL | pub enum B { @@ -98,7 +98,7 @@ note: struct `bar::C` exists but is inaccessible LL | struct C; | ^^^^^^^^^ not accessible -error[E0412]: cannot find type `D` in this scope +error[E0425]: cannot find type `D` in this scope --> $DIR/glob-resolve1.rs:35:11 | LL | pub enum B { @@ -115,5 +115,5 @@ LL | type D = isize; error: aborting due to 8 previous errors -Some errors have detailed explanations: E0412, E0423, E0425. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0423, E0425. +For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/imports/import-alias-issue-121168.edition2015.stderr b/tests/ui/imports/import-alias-issue-121168.edition2015.stderr index 47001fc1a529..8dee8e513444 100644 --- a/tests/ui/imports/import-alias-issue-121168.edition2015.stderr +++ b/tests/ui/imports/import-alias-issue-121168.edition2015.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Foo` in this scope +error[E0425]: cannot find type `Foo` in this scope --> $DIR/import-alias-issue-121168.rs:11:12 | LL | let _: Foo = todo!(); @@ -11,4 +11,4 @@ LL + use nice_crate_name::Foo; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/imports/import-alias-issue-121168.edition2018.stderr b/tests/ui/imports/import-alias-issue-121168.edition2018.stderr index e14e700c33d8..00b30b4c618f 100644 --- a/tests/ui/imports/import-alias-issue-121168.edition2018.stderr +++ b/tests/ui/imports/import-alias-issue-121168.edition2018.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Foo` in this scope +error[E0425]: cannot find type `Foo` in this scope --> $DIR/import-alias-issue-121168.rs:11:12 | LL | let _: Foo = todo!(); @@ -13,4 +13,4 @@ LL + use import_alias_issue_121168_extern::Foo; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/imports/import-alias-issue-121168.edition2021.stderr b/tests/ui/imports/import-alias-issue-121168.edition2021.stderr index e14e700c33d8..00b30b4c618f 100644 --- a/tests/ui/imports/import-alias-issue-121168.edition2021.stderr +++ b/tests/ui/imports/import-alias-issue-121168.edition2021.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Foo` in this scope +error[E0425]: cannot find type `Foo` in this scope --> $DIR/import-alias-issue-121168.rs:11:12 | LL | let _: Foo = todo!(); @@ -13,4 +13,4 @@ LL + use import_alias_issue_121168_extern::Foo; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/imports/inaccessible_type_aliases.stderr b/tests/ui/imports/inaccessible_type_aliases.stderr index 9afcfb21487b..1e463e923fc1 100644 --- a/tests/ui/imports/inaccessible_type_aliases.stderr +++ b/tests/ui/imports/inaccessible_type_aliases.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Foo` in this scope +error[E0425]: cannot find type `Foo` in this scope --> $DIR/inaccessible_type_aliases.rs:12:12 | LL | let x: Foo = 100; @@ -13,7 +13,7 @@ LL | type Foo = u64; LL | type Foo = u64; | ^^^^^^^^^^^^^^^ `b::Foo`: not accessible -error[E0412]: cannot find type `Bar` in this scope +error[E0425]: cannot find type `Bar` in this scope --> $DIR/inaccessible_type_aliases.rs:13:12 | LL | let y: Bar = 100; @@ -27,4 +27,4 @@ LL | type Bar = u64; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/imports/issue-4366-2.stderr b/tests/ui/imports/issue-4366-2.stderr index 517a434ebe37..6736b39a4070 100644 --- a/tests/ui/imports/issue-4366-2.stderr +++ b/tests/ui/imports/issue-4366-2.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Bar` in this scope +error[E0425]: cannot find type `Bar` in this scope --> $DIR/issue-4366-2.rs:16:21 | LL | fn sub() -> Bar { 1 } @@ -28,5 +28,5 @@ LL + use foo::foo; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0412, E0423. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0423, E0425. +For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/issues/issue-30589.stderr b/tests/ui/issues/issue-30589.stderr index 6f97a189cead..43d80896edf8 100644 --- a/tests/ui/issues/issue-30589.stderr +++ b/tests/ui/issues/issue-30589.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `DecoderError` in this scope +error[E0425]: cannot find type `DecoderError` in this scope --> $DIR/issue-30589.rs:3:23 | LL | impl fmt::Display for DecoderError { @@ -6,4 +6,4 @@ LL | impl fmt::Display for DecoderError { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/issues/issue-36836.stderr b/tests/ui/issues/issue-36836.stderr index e5c943c7c3d8..2d9a97df9052 100644 --- a/tests/ui/issues/issue-36836.stderr +++ b/tests/ui/issues/issue-36836.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Bar` in this scope +error[E0425]: cannot find type `Bar` in this scope --> $DIR/issue-36836.rs:13:17 | LL | impl Foo for Bar {} @@ -6,4 +6,4 @@ LL | impl Foo for Bar {} error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr b/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr index dd5119318ff4..b4225a813bd2 100644 --- a/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr +++ b/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/cannot-transmute-unnormalizable-type.rs:7:5 | LL | Missing: Trait, @@ -15,5 +15,5 @@ LL | std::mem::transmute::, Option<&Other>>(None); error: aborting due to 2 previous errors -Some errors have detailed explanations: E0412, E0512. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0512. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/layout/issue-84108.stderr b/tests/ui/layout/issue-84108.stderr index 08acc3d3b257..3d3bc003e21a 100644 --- a/tests/ui/layout/issue-84108.stderr +++ b/tests/ui/layout/issue-84108.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `OsStr` in this scope +error[E0425]: cannot find type `OsStr` in this scope --> $DIR/issue-84108.rs:6:24 | LL | static FOO: (dyn AsRef, u8) = ("hello", 42); @@ -9,7 +9,7 @@ help: consider importing this struct LL + use std::ffi::OsStr; | -error[E0412]: cannot find type `Path` in this scope +error[E0425]: cannot find type `Path` in this scope --> $DIR/issue-84108.rs:9:14 | LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42); @@ -40,5 +40,5 @@ LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42); error: aborting due to 4 previous errors -Some errors have detailed explanations: E0277, E0308, E0412. +Some errors have detailed explanations: E0277, E0308, E0425. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/layout/malformed-unsized-type-in-union.stderr b/tests/ui/layout/malformed-unsized-type-in-union.stderr index bdfabc0b1519..d819a2b368ed 100644 --- a/tests/ui/layout/malformed-unsized-type-in-union.stderr +++ b/tests/ui/layout/malformed-unsized-type-in-union.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/malformed-unsized-type-in-union.rs:3:34 | LL | union W { s: dyn Iterator } @@ -18,5 +18,5 @@ LL | union W { s: std::mem::ManuallyDrop> } error: aborting due to 2 previous errors -Some errors have detailed explanations: E0412, E0740. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0740. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/layout/thaw-transmute-invalid-enum.stderr b/tests/ui/layout/thaw-transmute-invalid-enum.stderr index 2b89159c2633..f57f0a2ad698 100644 --- a/tests/ui/layout/thaw-transmute-invalid-enum.stderr +++ b/tests/ui/layout/thaw-transmute-invalid-enum.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Subset` in this scope +error[E0425]: cannot find type `Subset` in this scope --> $DIR/thaw-transmute-invalid-enum.rs:35:41 | LL | assert::is_transmutable::(); @@ -75,5 +75,5 @@ LL | a: std::mem::ManuallyDrop, error: aborting due to 7 previous errors -Some errors have detailed explanations: E0412, E0517, E0658, E0740. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0517, E0658, E0740. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/layout/transmute-to-tail-with-err.stderr b/tests/ui/layout/transmute-to-tail-with-err.stderr index cff408127179..484ab5aebd18 100644 --- a/tests/ui/layout/transmute-to-tail-with-err.stderr +++ b/tests/ui/layout/transmute-to-tail-with-err.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/transmute-to-tail-with-err.rs:3:26 | LL | struct Bar(Box>); @@ -20,5 +20,5 @@ LL | let x: Bar = unsafe { std::mem::transmute(()) }; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0412, E0512. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0512. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/lifetimes/elided-lifetime-in-const-param-type.stderr b/tests/ui/lifetimes/elided-lifetime-in-const-param-type.stderr index c7f3c0cc0cd6..d8d867be507a 100644 --- a/tests/ui/lifetimes/elided-lifetime-in-const-param-type.stderr +++ b/tests/ui/lifetimes/elided-lifetime-in-const-param-type.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `c` in this scope +error[E0425]: cannot find type `c` in this scope --> $DIR/elided-lifetime-in-const-param-type.rs:8:27 | LL | type A = dyn for D; @@ -16,5 +16,5 @@ LL | type A = dyn for D; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0412, E0658. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0658. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/lifetimes/issue-83907-invalid-fn-like-path.stderr b/tests/ui/lifetimes/issue-83907-invalid-fn-like-path.stderr index e57933da558f..a44c9c316984 100644 --- a/tests/ui/lifetimes/issue-83907-invalid-fn-like-path.stderr +++ b/tests/ui/lifetimes/issue-83907-invalid-fn-like-path.stderr @@ -6,7 +6,7 @@ LL | static STATIC_VAR_FIVE: &One(); | | | help: provide a definition for the static: `= ;` -error[E0412]: cannot find type `One` in this scope +error[E0425]: cannot find type `One` in this scope --> $DIR/issue-83907-invalid-fn-like-path.rs:3:26 | LL | static STATIC_VAR_FIVE: &One(); @@ -14,4 +14,4 @@ LL | static STATIC_VAR_FIVE: &One(); error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/lint/issue-35075.stderr b/tests/ui/lint/issue-35075.stderr index f1f27152c2ff..427095132daf 100644 --- a/tests/ui/lint/issue-35075.stderr +++ b/tests/ui/lint/issue-35075.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Foo` in this scope +error[E0425]: cannot find type `Foo` in this scope --> $DIR/issue-35075.rs:3:12 | LL | inner: Foo @@ -10,7 +10,7 @@ LL - inner: Foo LL + inner: Baz | -error[E0412]: cannot find type `Foo` in this scope +error[E0425]: cannot find type `Foo` in this scope --> $DIR/issue-35075.rs:7:9 | LL | Foo(Foo) @@ -24,4 +24,4 @@ LL + Foo(Baz) error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/lint/recommend-literal.rs b/tests/ui/lint/recommend-literal.rs index 453cbf28569e..45f9ae0a7bdf 100644 --- a/tests/ui/lint/recommend-literal.rs +++ b/tests/ui/lint/recommend-literal.rs @@ -8,10 +8,10 @@ fn main() { //~^ ERROR cannot find type `long` in this scope //~| HELP perhaps you intended to use this type let v1: Boolean = true; - //~^ ERROR: cannot find type `Boolean` in this scope [E0412] + //~^ ERROR: cannot find type `Boolean` in this scope [E0425] //~| HELP perhaps you intended to use this type let v2: Bool = true; - //~^ ERROR: cannot find type `Bool` in this scope [E0412] + //~^ ERROR: cannot find type `Bool` in this scope [E0425] //~| HELP a builtin type with a similar name exists //~| HELP perhaps you intended to use this type } diff --git a/tests/ui/lint/recommend-literal.stderr b/tests/ui/lint/recommend-literal.stderr index 263071ca9a75..6b6dd134e1d2 100644 --- a/tests/ui/lint/recommend-literal.stderr +++ b/tests/ui/lint/recommend-literal.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `double` in this scope +error[E0425]: cannot find type `double` in this scope --> $DIR/recommend-literal.rs:1:13 | LL | type Real = double; @@ -7,7 +7,7 @@ LL | type Real = double; | not found in this scope | help: perhaps you intended to use this type: `f64` -error[E0412]: cannot find type `long` in this scope +error[E0425]: cannot find type `long` in this scope --> $DIR/recommend-literal.rs:7:12 | LL | let y: long = 74802374902374923; @@ -16,7 +16,7 @@ LL | let y: long = 74802374902374923; | not found in this scope | help: perhaps you intended to use this type: `i64` -error[E0412]: cannot find type `Boolean` in this scope +error[E0425]: cannot find type `Boolean` in this scope --> $DIR/recommend-literal.rs:10:13 | LL | let v1: Boolean = true; @@ -25,7 +25,7 @@ LL | let v1: Boolean = true; | not found in this scope | help: perhaps you intended to use this type: `bool` -error[E0412]: cannot find type `Bool` in this scope +error[E0425]: cannot find type `Bool` in this scope --> $DIR/recommend-literal.rs:13:13 | LL | let v2: Bool = true; @@ -42,7 +42,7 @@ LL - let v2: Bool = true; LL + let v2: bool = true; | -error[E0412]: cannot find type `boolean` in this scope +error[E0425]: cannot find type `boolean` in this scope --> $DIR/recommend-literal.rs:19:9 | LL | fn z(a: boolean) { @@ -51,7 +51,7 @@ LL | fn z(a: boolean) { | not found in this scope | help: perhaps you intended to use this type: `bool` -error[E0412]: cannot find type `byte` in this scope +error[E0425]: cannot find type `byte` in this scope --> $DIR/recommend-literal.rs:24:11 | LL | fn a() -> byte { @@ -60,7 +60,7 @@ LL | fn a() -> byte { | not found in this scope | help: perhaps you intended to use this type: `u8` -error[E0412]: cannot find type `float` in this scope +error[E0425]: cannot find type `float` in this scope --> $DIR/recommend-literal.rs:31:12 | LL | width: float, @@ -69,7 +69,7 @@ LL | width: float, | not found in this scope | help: perhaps you intended to use this type: `f32` -error[E0412]: cannot find type `int` in this scope +error[E0425]: cannot find type `int` in this scope --> $DIR/recommend-literal.rs:34:19 | LL | depth: Option, @@ -85,7 +85,7 @@ help: you might be missing a type parameter LL | struct Data { | +++++ -error[E0412]: cannot find type `short` in this scope +error[E0425]: cannot find type `short` in this scope --> $DIR/recommend-literal.rs:40:16 | LL | impl Stuff for short {} @@ -96,4 +96,4 @@ LL | impl Stuff for short {} error: aborting due to 9 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/lint/use_suggestion_json.stderr b/tests/ui/lint/use_suggestion_json.stderr index 20975864341d..6f2d7b461f76 100644 --- a/tests/ui/lint/use_suggestion_json.stderr +++ b/tests/ui/lint/use_suggestion_json.stderr @@ -2,71 +2,67 @@ "$message_type": "diagnostic", "message": "cannot find type `Iter` in this scope", "code": { - "code": "E0412", - "explanation": "A used type name is not in scope. + "code": "E0425", + "explanation": "An unresolved name was used. Erroneous code examples: -```compile_fail,E0412 -impl Something {} // error: type name `Something` is not in scope +```compile_fail,E0425 +something_that_doesnt_exist::foo; +// error: unresolved name `something_that_doesnt_exist::foo` // or: trait Foo { - fn bar(N); // error: type name `N` is not in scope + fn bar() { + Self; // error: unresolved name `Self` + } } // or: -fn foo(x: T) {} // type name `T` is not in scope +let x = unknown_variable; // error: unresolved name `unknown_variable` ``` -To fix this error, please verify you didn't misspell the type name, you did -declare it or imported it into the scope. Examples: +Please verify that the name wasn't misspelled and ensure that the +identifier being referred to is valid for the given situation. Example: ``` -struct Something; - -impl Something {} // ok! - -// or: - -trait Foo { - type N; - - fn bar(_: Self::N); // ok! -} - -// or: - -fn foo(x: T) {} // ok! -``` - -Another case that causes this error is when a type is imported into a parent -module. To fix this, you can follow the suggestion and use File directly or -`use super::File;` which will import the types from the parent namespace. An -example that causes this error is below: - -```compile_fail,E0412 -use std::fs::File; - -mod foo { - fn some_function(f: File) {} +enum something_that_does_exist { + Foo, } ``` -``` -use std::fs::File; +Or: -mod foo { - // either - use super::File; - // or - // use std::fs::File; - fn foo(f: File) {} -} -# fn main() {} // don't insert it for us; that'll break imports ``` +mod something_that_does_exist { + pub static foo : i32 = 0i32; +} + +something_that_does_exist::foo; // ok! +``` + +Or: + +``` +let unknown_variable = 12u32; +let x = unknown_variable; // ok! +``` + +If the item is not defined in the current module, it must be imported using a +`use` statement, like so: + +``` +# mod foo { pub fn bar() {} } +# fn main() { +use foo::bar; +bar(); +# } +``` + +If the item you are importing is not defined in some super-module of the +current module, then it must also be declared as public (e.g., `pub fn`). " }, "level": "error", @@ -403,7 +399,7 @@ mod foo { "rendered": null } ], - "rendered": "\u001b[1m\u001b[91merror[E0412]\u001b[0m\u001b[1m: cannot find type `Iter` in this scope\u001b[0m + "rendered": "\u001b[1m\u001b[91merror[E0425]\u001b[0m\u001b[1m: cannot find type `Iter` in this scope\u001b[0m \u001b[1m\u001b[94m--> \u001b[0m$DIR/use_suggestion_json.rs:13:12 \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94mLL\u001b[0m \u001b[1m\u001b[94m|\u001b[0m let x: Iter; @@ -436,11 +432,11 @@ mod foo { } { "$message_type": "diagnostic", - "message": "For more information about this error, try `rustc --explain E0412`.", + "message": "For more information about this error, try `rustc --explain E0425`.", "code": null, "level": "failure-note", "spans": [], "children": [], - "rendered": "\u001b[1mFor more information about this error, try `rustc --explain E0412`.\u001b[0m + "rendered": "\u001b[1mFor more information about this error, try `rustc --explain E0425`.\u001b[0m " } diff --git a/tests/ui/macros/macro-context.stderr b/tests/ui/macros/macro-context.stderr index 2efc0b136bc1..edddfef9de3b 100644 --- a/tests/ui/macros/macro-context.stderr +++ b/tests/ui/macros/macro-context.stderr @@ -42,7 +42,7 @@ LL | m!(); | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `i` in this scope +error[E0425]: cannot find type `i` in this scope --> $DIR/macro-context.rs:3:13 | LL | () => ( i ; typeof ); @@ -80,8 +80,7 @@ LL | let i = m!(); error: aborting due to 7 previous errors -Some errors have detailed explanations: E0412, E0425. -For more information about an error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. Future incompatibility report: Future breakage diagnostic: error: trailing semicolon in macro used in expression position --> $DIR/macro-context.rs:3:15 diff --git a/tests/ui/match/issue-82866.stderr b/tests/ui/match/issue-82866.stderr index f9e3360a525f..f2b63c6a0ea5 100644 --- a/tests/ui/match/issue-82866.stderr +++ b/tests/ui/match/issue-82866.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find value `x` in this scope LL | match x { | ^ not found in this scope -error[E0412]: cannot find type `v` in this scope +error[E0425]: cannot find type `v` in this scope --> $DIR/issue-82866.rs:4:16 | LL | Some::(v) => (), @@ -12,5 +12,4 @@ LL | Some::(v) => (), error: aborting due to 2 previous errors -Some errors have detailed explanations: E0412, E0425. -For more information about an error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/mir/gvn-nonsensical-coroutine-layout.rs b/tests/ui/mir/gvn-nonsensical-coroutine-layout.rs index f0d174cd01b0..1b387b3820e4 100644 --- a/tests/ui/mir/gvn-nonsensical-coroutine-layout.rs +++ b/tests/ui/mir/gvn-nonsensical-coroutine-layout.rs @@ -4,7 +4,7 @@ pub enum Request { TestSome(T), - //~^ ERROR cannot find type `T` in this scope [E0412] + //~^ ERROR cannot find type `T` in this scope [E0425] } pub async fn handle_event(event: Request) { diff --git a/tests/ui/mir/gvn-nonsensical-coroutine-layout.stderr b/tests/ui/mir/gvn-nonsensical-coroutine-layout.stderr index abc7b16ca741..c22c996160e5 100644 --- a/tests/ui/mir/gvn-nonsensical-coroutine-layout.stderr +++ b/tests/ui/mir/gvn-nonsensical-coroutine-layout.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/gvn-nonsensical-coroutine-layout.rs:6:14 | LL | TestSome(T), @@ -22,5 +22,5 @@ LL + use std::error::Request; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0412, E0574. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0574. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr b/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr index 5c5936d48e31..2ce695ce79d9 100644 --- a/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr +++ b/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr @@ -4,7 +4,7 @@ error: at least one trait must be specified LL | unsafe extern "C" fn foo(_: Bar, _: ...) -> impl {} | ^^^^ -error[E0412]: cannot find type `Bar` in this scope +error[E0425]: cannot find type `Bar` in this scope --> $DIR/issue-83499-input-output-iteration-ice.rs:7:29 | LL | unsafe extern "C" fn foo(_: Bar, _: ...) -> impl {} @@ -12,4 +12,4 @@ LL | unsafe extern "C" fn foo(_: Bar, _: ...) -> impl {} error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/mir/meaningless-bound.stderr b/tests/ui/mir/meaningless-bound.stderr index dc08def83b66..73f8f9dcbcdb 100644 --- a/tests/ui/mir/meaningless-bound.stderr +++ b/tests/ui/mir/meaningless-bound.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `b` in this scope +error[E0425]: cannot find type `b` in this scope --> $DIR/meaningless-bound.rs:6:5 | LL | b: Sized, @@ -15,5 +15,5 @@ LL | Self: Sized, error: aborting due to 2 previous errors -Some errors have detailed explanations: E0411, E0412. +Some errors have detailed explanations: E0411, E0425. For more information about an error, try `rustc --explain E0411`. diff --git a/tests/ui/mir/mir-build-2021-closure-capture-ice-110453-1.stderr b/tests/ui/mir/mir-build-2021-closure-capture-ice-110453-1.stderr index 468da0227d3d..8c8f1ad85d28 100644 --- a/tests/ui/mir/mir-build-2021-closure-capture-ice-110453-1.stderr +++ b/tests/ui/mir/mir-build-2021-closure-capture-ice-110453-1.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `B` in this scope +error[E0425]: cannot find type `B` in this scope --> $DIR/mir-build-2021-closure-capture-ice-110453-1.rs:12:18 | LL | pub struct C(B); @@ -11,4 +11,4 @@ LL + use crate::B; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/mir/mir-build-2021-closure-capture-ice-110453-2.stderr b/tests/ui/mir/mir-build-2021-closure-capture-ice-110453-2.stderr index 8fe4981eb3f2..10505991de97 100644 --- a/tests/ui/mir/mir-build-2021-closure-capture-ice-110453-2.stderr +++ b/tests/ui/mir/mir-build-2021-closure-capture-ice-110453-2.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `as_str` in this scope +error[E0425]: cannot find type `as_str` in this scope --> $DIR/mir-build-2021-closure-capture-ice-110453-2.rs:8:47 | LL | pub fn dup(f: impl Fn(i32) -> i32) -> impl Fn(as_str) -> i32 { @@ -6,4 +6,4 @@ LL | pub fn dup(f: impl Fn(i32) -> i32) -> impl Fn(as_str) -> i32 { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/missing/missing-items/missing-type-parameter2.stderr b/tests/ui/missing/missing-items/missing-type-parameter2.stderr index 3c132e769eae..c361ed79cc79 100644 --- a/tests/ui/missing/missing-items/missing-type-parameter2.stderr +++ b/tests/ui/missing/missing-items/missing-type-parameter2.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `N` in this scope +error[E0425]: cannot find type `N` in this scope --> $DIR/missing-type-parameter2.rs:3:8 | LL | struct X(); @@ -17,7 +17,7 @@ help: you might be missing a type parameter LL | impl X {} | +++ -error[E0412]: cannot find type `N` in this scope +error[E0425]: cannot find type `N` in this scope --> $DIR/missing-type-parameter2.rs:6:28 | LL | impl X {} @@ -35,7 +35,7 @@ help: you might be missing a type parameter LL | impl X {} | +++ -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/missing-type-parameter2.rs:11:20 | LL | struct X(); @@ -54,7 +54,7 @@ help: you might be missing a type parameter LL | fn foo(_: T) where T: Send {} | +++ -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/missing-type-parameter2.rs:11:11 | LL | struct X(); @@ -73,7 +73,7 @@ help: you might be missing a type parameter LL | fn foo(_: T) where T: Send {} | +++ -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/missing-type-parameter2.rs:15:24 | LL | struct X(); @@ -122,5 +122,5 @@ LL | impl X<{ N }> {} error: aborting due to 8 previous errors -Some errors have detailed explanations: E0412, E0747. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0747. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/offset-of/offset-of-enum.stderr b/tests/ui/offset-of/offset-of-enum.stderr index 362296a22e8f..cc1b1aa10d24 100644 --- a/tests/ui/offset-of/offset-of-enum.stderr +++ b/tests/ui/offset-of/offset-of-enum.stderr @@ -7,7 +7,7 @@ LL | offset_of!(Alpha::One, 0); | not a type | help: try using the variant's enum: `Alpha` -error[E0412]: cannot find type `Beta` in this scope +error[E0425]: cannot find type `Beta` in this scope --> $DIR/offset-of-enum.rs:18:16 | LL | offset_of!(Beta, One); @@ -43,5 +43,5 @@ LL | offset_of!(Alpha, NonExistent); error: aborting due to 6 previous errors -Some errors have detailed explanations: E0412, E0573, E0599, E0609, E0795. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0573, E0599, E0609, E0795. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/offset-of/offset-of-self.stderr b/tests/ui/offset-of/offset-of-self.stderr index 57afb6b9282e..cd78fe492b80 100644 --- a/tests/ui/offset-of/offset-of-self.stderr +++ b/tests/ui/offset-of/offset-of-self.stderr @@ -4,7 +4,7 @@ error: offset_of expects dot-separated field and variant names LL | offset_of!(Self, Self::v); | ^^^^^^^ -error[E0412]: cannot find type `S` in module `self` +error[E0425]: cannot find type `S` in module `self` --> $DIR/offset-of-self.rs:33:26 | LL | offset_of!(self::S, v); @@ -59,5 +59,5 @@ LL | offset_of!(S, v.self); error: aborting due to 7 previous errors -Some errors have detailed explanations: E0411, E0412, E0609, E0616. +Some errors have detailed explanations: E0411, E0425, E0609, E0616. For more information about an error, try `rustc --explain E0411`. diff --git a/tests/ui/parallel-rustc/ty-variance-issue-124423.stderr b/tests/ui/parallel-rustc/ty-variance-issue-124423.stderr index 81ba66c42faa..bf9ad85dfc5c 100644 --- a/tests/ui/parallel-rustc/ty-variance-issue-124423.stderr +++ b/tests/ui/parallel-rustc/ty-variance-issue-124423.stderr @@ -237,7 +237,7 @@ help: consider introducing lifetime `'a` here LL | fn elided4<'a>(_: &impl Copy + 'a) -> new { x(x) } | ++++ -error[E0412]: cannot find type `new` in this scope +error[E0425]: cannot find type `new` in this scope --> $DIR/ty-variance-issue-124423.rs:48:36 | LL | fn elided4(_: &impl Copy + 'a) -> new { x(x) } @@ -282,5 +282,5 @@ note: if you're trying to build a new `Box<_, _>` consider using one of the foll error: aborting due to 30 previous errors -Some errors have detailed explanations: E0121, E0224, E0261, E0412, E0599. -For more information about an error, try `rustc --explain E0121`. \ No newline at end of file +Some errors have detailed explanations: E0121, E0224, E0261, E0425, E0599. +For more information about an error, try `rustc --explain E0121`. diff --git a/tests/ui/parser/associated-path-shl.stderr b/tests/ui/parser/associated-path-shl.stderr index 71ee93f4835f..42b7c6a73aef 100644 --- a/tests/ui/parser/associated-path-shl.stderr +++ b/tests/ui/parser/associated-path-shl.stderr @@ -1,28 +1,28 @@ -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/associated-path-shl.rs:4:14 | LL | let _: <::B>::C; | ^ not found in this scope -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/associated-path-shl.rs:5:15 | LL | let _ = <::B>::C; | ^ not found in this scope -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/associated-path-shl.rs:6:11 | LL | let <::B>::C; | ^ not found in this scope -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/associated-path-shl.rs:7:17 | LL | let 0 ..= <::B>::C; | ^ not found in this scope -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/associated-path-shl.rs:8:7 | LL | <::B>::C; @@ -30,4 +30,4 @@ LL | <::B>::C; error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/const-param-decl-on-type-instead-of-impl.stderr b/tests/ui/parser/const-param-decl-on-type-instead-of-impl.stderr index 855163e3d3bd..db7c76dc1aa9 100644 --- a/tests/ui/parser/const-param-decl-on-type-instead-of-impl.stderr +++ b/tests/ui/parser/const-param-decl-on-type-instead-of-impl.stderr @@ -30,7 +30,7 @@ LL | path::path::Struct::() | = help: you might be missing a crate named `path` -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/const-param-decl-on-type-instead-of-impl.rs:8:15 | LL | fn banana(a: >::BAR) {} @@ -46,5 +46,5 @@ LL | let _: () = 42; error: aborting due to 6 previous errors -Some errors have detailed explanations: E0308, E0412, E0433. +Some errors have detailed explanations: E0308, E0425, E0433. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/dyn-trait-compatibility.stderr b/tests/ui/parser/dyn-trait-compatibility.stderr index a57c033c1e13..d15bf3c97f65 100644 --- a/tests/ui/parser/dyn-trait-compatibility.stderr +++ b/tests/ui/parser/dyn-trait-compatibility.stderr @@ -1,28 +1,28 @@ -error[E0412]: cannot find type `dyn` in this scope +error[E0425]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:3:11 | LL | type A0 = dyn; | ^^^ not found in this scope -error[E0412]: cannot find type `dyn` in this scope +error[E0425]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:7:11 | LL | type A2 = dyn; | ^^^ not found in this scope -error[E0412]: cannot find type `dyn` in this scope +error[E0425]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:7:15 | LL | type A2 = dyn; | ^^^ not found in this scope -error[E0412]: cannot find type `dyn` in this scope +error[E0425]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:7:20 | LL | type A2 = dyn; | ^^^ not found in this scope -error[E0412]: cannot find type `dyn` in this scope +error[E0425]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:11:11 | LL | type A3 = dyn<::dyn>; @@ -34,7 +34,7 @@ error[E0405]: cannot find trait `dyn` in this scope LL | type A3 = dyn<::dyn>; | ^^^ not found in this scope -error[E0412]: cannot find type `dyn` in this scope +error[E0425]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:11:16 | LL | type A3 = dyn<::dyn>; @@ -50,5 +50,5 @@ LL | type A1 = dyn::dyn; error: aborting due to 8 previous errors -Some errors have detailed explanations: E0405, E0412, E0433. +Some errors have detailed explanations: E0405, E0425, E0433. For more information about an error, try `rustc --explain E0405`. diff --git a/tests/ui/parser/fn-field-parse-error-ice.stderr b/tests/ui/parser/fn-field-parse-error-ice.stderr index 6f033e2b0c6f..74ab1b004ccb 100644 --- a/tests/ui/parser/fn-field-parse-error-ice.stderr +++ b/tests/ui/parser/fn-field-parse-error-ice.stderr @@ -17,7 +17,7 @@ help: escape `fn` to use it as an identifier LL | inner : dyn r#fn () | ++ -error[E0412]: cannot find type `dyn` in this scope +error[E0425]: cannot find type `dyn` in this scope --> $DIR/fn-field-parse-error-ice.rs:5:13 | LL | inner : dyn fn () @@ -25,4 +25,4 @@ LL | inner : dyn fn () error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/recover/recover-fn-ptr-with-generics.stderr b/tests/ui/parser/recover/recover-fn-ptr-with-generics.stderr index 9023856ef248..b69e07cc3a1a 100644 --- a/tests/ui/parser/recover/recover-fn-ptr-with-generics.stderr +++ b/tests/ui/parser/recover/recover-fn-ptr-with-generics.stderr @@ -88,13 +88,13 @@ error: expected identifier, found `>` LL | type QuiteBroken = fn(); | ^ expected identifier -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/recover-fn-ptr-with-generics.rs:5:27 | LL | type Identity = fn(T) -> T; | ^ not found in this scope -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/recover-fn-ptr-with-generics.rs:5:33 | LL | type Identity = fn(T) -> T; @@ -108,4 +108,4 @@ LL | let _: extern "C" fn<'a: 'static>(); error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/unmatched-langle-1.rs b/tests/ui/parser/unmatched-langle-1.rs index fdf2ae398014..51072c13ba5b 100644 --- a/tests/ui/parser/unmatched-langle-1.rs +++ b/tests/ui/parser/unmatched-langle-1.rs @@ -5,5 +5,5 @@ fn main() { foo::<<<>(); //~^ ERROR: unmatched angle brackets //~| ERROR: cannot find function `foo` in this scope [E0425] - //~| ERROR: cannot find type `Ty` in this scope [E0412] + //~| ERROR: cannot find type `Ty` in this scope [E0425] } diff --git a/tests/ui/parser/unmatched-langle-1.stderr b/tests/ui/parser/unmatched-langle-1.stderr index 3411a05fb589..efe6c9b33210 100644 --- a/tests/ui/parser/unmatched-langle-1.stderr +++ b/tests/ui/parser/unmatched-langle-1.stderr @@ -10,7 +10,7 @@ LL - foo::<<<>(); LL + foo::>(); | -error[E0412]: cannot find type `Ty` in this scope +error[E0425]: cannot find type `Ty` in this scope --> $DIR/unmatched-langle-1.rs:5:14 | LL | foo::<<<>(); @@ -24,5 +24,4 @@ LL | foo::<<<>(); error: aborting due to 3 previous errors -Some errors have detailed explanations: E0412, E0425. -For more information about an error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/where_with_bound.stderr b/tests/ui/parser/where_with_bound.stderr index 06b611e1cd00..1e490f2ddcd1 100644 --- a/tests/ui/parser/where_with_bound.stderr +++ b/tests/ui/parser/where_with_bound.stderr @@ -4,7 +4,7 @@ error: generic parameters on `where` clauses are reserved for future use LL | fn foo() where ::Item: ToString, T: Iterator { } | ^^^ currently unsupported -error[E0412]: cannot find type `Item` in the crate root +error[E0425]: cannot find type `Item` in the crate root --> $DIR/where_with_bound.rs:2:24 | LL | fn foo() where ::Item: ToString, T: Iterator { } @@ -12,4 +12,4 @@ LL | fn foo() where ::Item: ToString, T: Iterator { } error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/pattern/usefulness/issue-119493-type-error-ice.stderr b/tests/ui/pattern/usefulness/issue-119493-type-error-ice.stderr index 1c560aa2ca81..06e13aa2ea01 100644 --- a/tests/ui/pattern/usefulness/issue-119493-type-error-ice.stderr +++ b/tests/ui/pattern/usefulness/issue-119493-type-error-ice.stderr @@ -1,10 +1,10 @@ -error[E0412]: cannot find type `NonExistent` in this scope +error[E0425]: cannot find type `NonExistent` in this scope --> $DIR/issue-119493-type-error-ice.rs:5:16 | LL | struct Foo(NonExistent); | ^^^^^^^^^^^ not found in this scope -error[E0412]: cannot find type `NonExistent` in this scope +error[E0425]: cannot find type `NonExistent` in this scope --> $DIR/issue-119493-type-error-ice.rs:5:16 | LL | struct Foo(NonExistent); @@ -27,5 +27,5 @@ LL | type U = impl Copy; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0412, E0658. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0658. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/privacy/privacy-ns1.stderr b/tests/ui/privacy/privacy-ns1.stderr index 58e276a75a71..dd4a1e93020b 100644 --- a/tests/ui/privacy/privacy-ns1.stderr +++ b/tests/ui/privacy/privacy-ns1.stderr @@ -52,7 +52,7 @@ help: consider importing this function LL + use foo2::Bar; | -error[E0412]: cannot find type `Bar` in this scope +error[E0425]: cannot find type `Bar` in this scope --> $DIR/privacy-ns1.rs:53:17 | LL | pub struct Baz; @@ -90,5 +90,5 @@ LL | let _x: Box; error: aborting due to 4 previous errors -Some errors have detailed explanations: E0412, E0423, E0425, E0747. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0423, E0425, E0747. +For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/privacy/sysroot-private.default.stderr b/tests/ui/privacy/sysroot-private.default.stderr index 692b1bbd4db3..66712a59e7b2 100644 --- a/tests/ui/privacy/sysroot-private.default.stderr +++ b/tests/ui/privacy/sysroot-private.default.stderr @@ -4,7 +4,7 @@ error[E0405]: cannot find trait `Equivalent` in this scope LL | trait Trait2: Equivalent {} | ^^^^^^^^^^ not found in this scope -error[E0412]: cannot find type `K` in this scope +error[E0425]: cannot find type `K` in this scope --> $DIR/sysroot-private.rs:32:35 | LL | fn trait_member(val: &T, key: &K) -> bool { @@ -36,5 +36,5 @@ LL | memchr2(b'a', b'b', buf) error: aborting due to 4 previous errors -Some errors have detailed explanations: E0220, E0405, E0412, E0425. +Some errors have detailed explanations: E0220, E0405, E0425. For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr b/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr index dc2d890a082c..94b85b995c47 100644 --- a/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr +++ b/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr @@ -4,7 +4,7 @@ error[E0405]: cannot find trait `Equivalent` in this scope LL | trait Trait2: Equivalent {} | ^^^^^^^^^^ not found in this scope -error[E0412]: cannot find type `K` in this scope +error[E0425]: cannot find type `K` in this scope --> $DIR/sysroot-private.rs:32:35 | LL | fn trait_member(val: &T, key: &K) -> bool { @@ -36,5 +36,5 @@ LL | memchr2(b'a', b'b', buf) error: aborting due to 4 previous errors -Some errors have detailed explanations: E0220, E0405, E0412, E0425. +Some errors have detailed explanations: E0220, E0405, E0425. For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/proc-macro/attributes-on-modules-fail.stderr b/tests/ui/proc-macro/attributes-on-modules-fail.stderr index 74c797aacd9e..1dc87fd0d551 100644 --- a/tests/ui/proc-macro/attributes-on-modules-fail.stderr +++ b/tests/ui/proc-macro/attributes-on-modules-fail.stderr @@ -46,7 +46,7 @@ LL | mod inner; = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0412]: cannot find type `Y` in this scope +error[E0425]: cannot find type `Y` in this scope --> $DIR/attributes-on-modules-fail.rs:11:14 | LL | type A = Y; @@ -57,7 +57,7 @@ help: consider importing this struct LL + use Y; | -error[E0412]: cannot find type `X` in this scope +error[E0425]: cannot find type `X` in this scope --> $DIR/attributes-on-modules-fail.rs:15:10 | LL | type A = X; @@ -70,5 +70,5 @@ LL + use m::X; error: aborting due to 7 previous errors -Some errors have detailed explanations: E0412, E0658, E0774. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0658, E0774. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/proc-macro/empty-where-clause.stderr b/tests/ui/proc-macro/empty-where-clause.stderr index 192a2b30f0dc..5588ed5f36e2 100644 --- a/tests/ui/proc-macro/empty-where-clause.stderr +++ b/tests/ui/proc-macro/empty-where-clause.stderr @@ -1,16 +1,16 @@ -error[E0412]: cannot find type `MissingType1` in this scope +error[E0425]: cannot find type `MissingType1` in this scope --> $DIR/empty-where-clause.rs:8:12 | LL | field: MissingType1 | ^^^^^^^^^^^^ not found in this scope -error[E0412]: cannot find type `MissingType2` in this scope +error[E0425]: cannot find type `MissingType2` in this scope --> $DIR/empty-where-clause.rs:12:20 | LL | struct TupleStruct(MissingType2) where; | ^^^^^^^^^^^^ not found in this scope -error[E0412]: cannot find type `MissingType3` in this scope +error[E0425]: cannot find type `MissingType3` in this scope --> $DIR/empty-where-clause.rs:15:13 | LL | Variant(MissingType3) @@ -18,4 +18,4 @@ LL | Variant(MissingType3) error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/proc-macro/generate-mod.stderr b/tests/ui/proc-macro/generate-mod.stderr index 47210c63c2b2..af90df2c3dc3 100644 --- a/tests/ui/proc-macro/generate-mod.stderr +++ b/tests/ui/proc-macro/generate-mod.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `FromOutside` in this scope +error[E0425]: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:11:1 | LL | generate_mod::check!(); @@ -8,7 +8,7 @@ LL | generate_mod::check!(); FromOutside = note: this error originates in the macro `generate_mod::check` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `Outer` in this scope +error[E0425]: cannot find type `Outer` in this scope --> $DIR/generate-mod.rs:11:1 | LL | generate_mod::check!(); @@ -18,7 +18,7 @@ LL | generate_mod::check!(); Outer = note: this error originates in the macro `generate_mod::check` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `FromOutside` in this scope +error[E0425]: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:14:1 | LL | #[generate_mod::check_attr] @@ -28,7 +28,7 @@ LL | #[generate_mod::check_attr] FromOutside = note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `OuterAttr` in this scope +error[E0425]: cannot find type `OuterAttr` in this scope --> $DIR/generate-mod.rs:14:1 | LL | #[generate_mod::check_attr] @@ -81,7 +81,7 @@ LL | #[derive(generate_mod::CheckDerive)] error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. Future incompatibility report: Future breakage diagnostic: error: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:18:10 diff --git a/tests/ui/proc-macro/issue-83510.stderr b/tests/ui/proc-macro/issue-83510.stderr index 50209a8facb9..755d6e3a03ee 100644 --- a/tests/ui/proc-macro/issue-83510.stderr +++ b/tests/ui/proc-macro/issue-83510.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Foo` in this scope +error[E0425]: cannot find type `Foo` in this scope --> $DIR/issue-83510.rs:7:1 | LL | issue_83510::dance_like_you_want_to_ice!(); @@ -35,5 +35,5 @@ LL | issue_83510::dance_like_you_want_to_ice!(); error: aborting due to 4 previous errors -Some errors have detailed explanations: E0404, E0405, E0412, E0658. +Some errors have detailed explanations: E0404, E0405, E0425, E0658. For more information about an error, try `rustc --explain E0404`. diff --git a/tests/ui/proc-macro/macro-rules-derive.stderr b/tests/ui/proc-macro/macro-rules-derive.stderr index e7cd4474618f..05ad9e559ad1 100644 --- a/tests/ui/proc-macro/macro-rules-derive.stderr +++ b/tests/ui/proc-macro/macro-rules-derive.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `MissingType` in this scope +error[E0425]: cannot find type `MissingType` in this scope --> $DIR/macro-rules-derive.rs:10:20 | LL | field: MissingType @@ -11,4 +11,4 @@ LL | produce_it!(MyName); error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/proc-macro/mixed-site-span.stderr b/tests/ui/proc-macro/mixed-site-span.stderr index b215ef03dc78..d5cf484f6dd0 100644 --- a/tests/ui/proc-macro/mixed-site-span.stderr +++ b/tests/ui/proc-macro/mixed-site-span.stderr @@ -576,7 +576,7 @@ LL | proc_macro_rules!(); | = note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `ItemUse` in crate `$crate` +error[E0425]: cannot find type `ItemUse` in crate `$crate` --> $DIR/mixed-site-span.rs:23:9 | LL | proc_macro_rules!(); @@ -609,5 +609,5 @@ LL | local_def; error: aborting due to 52 previous errors -Some errors have detailed explanations: E0412, E0425, E0426, E0432. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0426, E0432. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/proc-macro/span-from-proc-macro.stderr b/tests/ui/proc-macro/span-from-proc-macro.stderr index 945a5620fac4..0605c727733b 100644 --- a/tests/ui/proc-macro/span-from-proc-macro.stderr +++ b/tests/ui/proc-macro/span-from-proc-macro.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `MissingType` in this scope +error[E0425]: cannot find type `MissingType` in this scope --> $DIR/auxiliary/span-from-proc-macro.rs:33:20 | LL | pub fn error_from_attribute(_args: TokenStream, _input: TokenStream) -> TokenStream { @@ -12,7 +12,7 @@ LL | field: MissingType LL | #[error_from_attribute] | ----------------------- in this attribute macro expansion -error[E0412]: cannot find type `OtherMissingType` in this scope +error[E0425]: cannot find type `OtherMissingType` in this scope --> $DIR/auxiliary/span-from-proc-macro.rs:42:21 | LL | pub fn error_from_derive(_input: TokenStream) -> TokenStream { @@ -58,5 +58,5 @@ LL | error_from_bang!(); error: aborting due to 4 previous errors -Some errors have detailed explanations: E0308, E0412, E0425. +Some errors have detailed explanations: E0308, E0425. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/recursion/recursive-reexports.stderr b/tests/ui/recursion/recursive-reexports.stderr index 71653d26a18d..04805d145fee 100644 --- a/tests/ui/recursion/recursive-reexports.stderr +++ b/tests/ui/recursion/recursive-reexports.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `S` in crate `recursive_reexports` +error[E0425]: cannot find type `S` in crate `recursive_reexports` --> $DIR/recursive-reexports.rs:5:32 | LL | fn f() -> recursive_reexports::S {} @@ -6,4 +6,4 @@ LL | fn f() -> recursive_reexports::S {} error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/regions/outlives-with-missing.stderr b/tests/ui/regions/outlives-with-missing.stderr index 0e3aaaf5fdbd..b8762e9cb8f3 100644 --- a/tests/ui/regions/outlives-with-missing.stderr +++ b/tests/ui/regions/outlives-with-missing.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/outlives-with-missing.rs:10:9 | LL | impl HandlerWrapper { @@ -9,4 +9,4 @@ LL | T: Send + Sync + 'static, error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/dont-compute-arg-names-for-non-fn.stderr b/tests/ui/resolve/dont-compute-arg-names-for-non-fn.stderr index a1a8bb575e14..01a3293b7361 100644 --- a/tests/ui/resolve/dont-compute-arg-names-for-non-fn.stderr +++ b/tests/ui/resolve/dont-compute-arg-names-for-non-fn.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Bar` in this scope +error[E0425]: cannot find type `Bar` in this scope --> $DIR/dont-compute-arg-names-for-non-fn.rs:8:14 | LL | impl Foo for Bar {} @@ -11,4 +11,4 @@ LL | impl Foo for Self::Bar {} error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/editions-crate-root-2015.stderr b/tests/ui/resolve/editions-crate-root-2015.stderr index 3d203c8ed967..989ee547a7c6 100644 --- a/tests/ui/resolve/editions-crate-root-2015.stderr +++ b/tests/ui/resolve/editions-crate-root-2015.stderr @@ -20,13 +20,13 @@ help: you might be missing a crate named `nonexistant`, add it to your project a LL + extern crate nonexistant; | -error[E0412]: cannot find type `nonexistant` in the crate root +error[E0425]: cannot find type `nonexistant` in the crate root --> $DIR/editions-crate-root-2015.rs:11:25 | LL | fn bare_global(_: ::nonexistant) { | ^^^^^^^^^^^ not found in the crate root -error[E0412]: cannot find type `nonexistant` in the crate root +error[E0425]: cannot find type `nonexistant` in the crate root --> $DIR/editions-crate-root-2015.rs:14:29 | LL | fn bare_crate(_: crate::nonexistant) { @@ -34,5 +34,5 @@ LL | fn bare_crate(_: crate::nonexistant) { error: aborting due to 4 previous errors -Some errors have detailed explanations: E0412, E0433. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0433. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/editions-crate-root-2018.stderr b/tests/ui/resolve/editions-crate-root-2018.stderr index 967a5a2fca15..1bcef3396199 100644 --- a/tests/ui/resolve/editions-crate-root-2018.stderr +++ b/tests/ui/resolve/editions-crate-root-2018.stderr @@ -10,13 +10,13 @@ error[E0433]: failed to resolve: could not find `nonexistant` in the crate root LL | fn crate_inner(_: crate::nonexistant::Foo) { | ^^^^^^^^^^^ could not find `nonexistant` in the crate root -error[E0412]: cannot find crate `nonexistant` in the list of imported crates +error[E0425]: cannot find crate `nonexistant` in the list of imported crates --> $DIR/editions-crate-root-2018.rs:11:25 | LL | fn bare_global(_: ::nonexistant) { | ^^^^^^^^^^^ not found in the list of imported crates -error[E0412]: cannot find type `nonexistant` in the crate root +error[E0425]: cannot find type `nonexistant` in the crate root --> $DIR/editions-crate-root-2018.rs:14:29 | LL | fn bare_crate(_: crate::nonexistant) { @@ -24,5 +24,5 @@ LL | fn bare_crate(_: crate::nonexistant) { error: aborting due to 4 previous errors -Some errors have detailed explanations: E0412, E0433. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0433. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/issue-21221-1.rs b/tests/ui/resolve/issue-21221-1.rs index 690feab2b2e1..881bcabd73ac 100644 --- a/tests/ui/resolve/issue-21221-1.rs +++ b/tests/ui/resolve/issue-21221-1.rs @@ -46,7 +46,7 @@ impl Mul for Foo { } // BEFORE, we got: -// error: use of undeclared type name `Mul` [E0412] +// error: use of undeclared type name `Mul` [E0425] // AFTER, we get: // error: type name `Mul` is not in scope. Maybe you meant: // help: ... diff --git a/tests/ui/resolve/issue-21221-1.stderr b/tests/ui/resolve/issue-21221-1.stderr index 7537d91fe8dc..c1716f18de86 100644 --- a/tests/ui/resolve/issue-21221-1.stderr +++ b/tests/ui/resolve/issue-21221-1.stderr @@ -13,7 +13,7 @@ LL + use mul1::Mul; LL + use mul2::Mul; | -error[E0412]: cannot find type `Mul` in this scope +error[E0425]: cannot find type `Mul` in this scope --> $DIR/issue-21221-1.rs:59:16 | LL | fn getMul() -> Mul { @@ -58,5 +58,5 @@ LL + use std::ops::Div; error: aborting due to 4 previous errors -Some errors have detailed explanations: E0405, E0412. +Some errors have detailed explanations: E0405, E0425. For more information about an error, try `rustc --explain E0405`. diff --git a/tests/ui/resolve/issue-35675.stderr b/tests/ui/resolve/issue-35675.stderr index 994d0fa6a755..6a6db22f89ee 100644 --- a/tests/ui/resolve/issue-35675.stderr +++ b/tests/ui/resolve/issue-35675.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Apple` in this scope +error[E0425]: cannot find type `Apple` in this scope --> $DIR/issue-35675.rs:8:29 | LL | fn should_return_fruit() -> Apple { @@ -50,7 +50,7 @@ LL | fn foo() -> Ok { | not a type | help: try using the variant's enum: `std::result::Result` -error[E0412]: cannot find type `Variant3` in this scope +error[E0425]: cannot find type `Variant3` in this scope --> $DIR/issue-35675.rs:25:13 | LL | fn bar() -> Variant3 { @@ -73,5 +73,5 @@ LL | fn qux() -> Some { error: aborting due to 7 previous errors -Some errors have detailed explanations: E0412, E0425, E0573. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0573. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs b/tests/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs index c377ecea94d0..235eae9f517a 100644 --- a/tests/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs +++ b/tests/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs @@ -2,5 +2,5 @@ fn main() {} trait Foo { fn fn_with_type_named_same_as_local_in_param(b: b); - //~^ ERROR cannot find type `b` in this scope [E0412] + //~^ ERROR cannot find type `b` in this scope [E0425] } diff --git a/tests/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr b/tests/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr index 60ef13551a17..1db2a0a707b0 100644 --- a/tests/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr +++ b/tests/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `b` in this scope +error[E0425]: cannot find type `b` in this scope --> $DIR/issue-69401-trait-fn-no-body-ty-local.rs:4:53 | LL | fn fn_with_type_named_same_as_local_in_param(b: b); @@ -6,4 +6,4 @@ LL | fn fn_with_type_named_same_as_local_in_param(b: b); error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/issue-85348.rs b/tests/ui/resolve/issue-85348.rs index 3a33c1934084..d0704bcddef5 100644 --- a/tests/ui/resolve/issue-85348.rs +++ b/tests/ui/resolve/issue-85348.rs @@ -1,7 +1,7 @@ // Checks whether shadowing a const parameter leads to an ICE (#85348). impl ArrayWindowsExample { -//~^ ERROR: cannot find type `ArrayWindowsExample` in this scope [E0412] +//~^ ERROR: cannot find type `ArrayWindowsExample` in this scope [E0425] fn next() { let mut N; //~^ ERROR: let bindings cannot shadow const parameters [E0530] diff --git a/tests/ui/resolve/issue-85348.stderr b/tests/ui/resolve/issue-85348.stderr index 42b43f825d10..bf44a570ab8c 100644 --- a/tests/ui/resolve/issue-85348.stderr +++ b/tests/ui/resolve/issue-85348.stderr @@ -7,7 +7,7 @@ LL | impl ArrayWindowsExample { LL | let mut N; | ^ cannot be named the same as a const parameter -error[E0412]: cannot find type `ArrayWindowsExample` in this scope +error[E0425]: cannot find type `ArrayWindowsExample` in this scope --> $DIR/issue-85348.rs:3:22 | LL | impl ArrayWindowsExample { @@ -26,5 +26,5 @@ LL | let mut N: /* Type */; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0282, E0412, E0530. +Some errors have detailed explanations: E0282, E0425, E0530. For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/resolve/issue-88472.rs b/tests/ui/resolve/issue-88472.rs index df20252b2b40..abc0bda790d6 100644 --- a/tests/ui/resolve/issue-88472.rs +++ b/tests/ui/resolve/issue-88472.rs @@ -15,7 +15,7 @@ mod b { use crate::a::*; //~^ WARNING: unused import type Bar = Foo; - //~^ ERROR: cannot find type `Foo` in this scope [E0412] + //~^ ERROR: cannot find type `Foo` in this scope [E0425] //~| NOTE: not found in this scope } @@ -32,7 +32,7 @@ enum Eee {} mod e { type Baz = Eee; - //~^ ERROR: cannot find type `Eee` in this scope [E0412] + //~^ ERROR: cannot find type `Eee` in this scope [E0425] //~| NOTE: not found in this scope } diff --git a/tests/ui/resolve/issue-88472.stderr b/tests/ui/resolve/issue-88472.stderr index cfcc0a95cc38..cca36f32f393 100644 --- a/tests/ui/resolve/issue-88472.stderr +++ b/tests/ui/resolve/issue-88472.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Foo` in this scope +error[E0425]: cannot find type `Foo` in this scope --> $DIR/issue-88472.rs:17:16 | LL | type Bar = Foo; @@ -10,7 +10,7 @@ note: struct `a::Foo` exists but is inaccessible LL | struct Foo; | ^^^^^^^^^^^ not accessible -error[E0412]: cannot find type `Eee` in this scope +error[E0425]: cannot find type `Eee` in this scope --> $DIR/issue-88472.rs:34:16 | LL | type Baz = Eee; @@ -39,4 +39,4 @@ LL | #![warn(unused_imports)] error: aborting due to 2 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/levenshtein.stderr b/tests/ui/resolve/levenshtein.stderr index 7fc5710c35ec..7a1abd134330 100644 --- a/tests/ui/resolve/levenshtein.stderr +++ b/tests/ui/resolve/levenshtein.stderr @@ -1,10 +1,10 @@ -error[E0412]: cannot find type `esize` in this scope +error[E0425]: cannot find type `esize` in this scope --> $DIR/levenshtein.rs:5:11 | LL | fn foo(c: esize) {} // Misspelled primitive type name. | ^^^^^ help: a builtin type with a similar name exists: `isize` -error[E0412]: cannot find type `Baz` in this scope +error[E0425]: cannot find type `Baz` in this scope --> $DIR/levenshtein.rs:10:10 | LL | enum Bar { } @@ -13,7 +13,7 @@ LL | LL | type A = Baz; // Misspelled type name. | ^^^ help: an enum with a similar name exists: `Bar` -error[E0412]: cannot find type `Opiton` in this scope +error[E0425]: cannot find type `Opiton` in this scope --> $DIR/levenshtein.rs:12:10 | LL | type B = Opiton; // Misspelled type name from the prelude. @@ -23,7 +23,7 @@ LL | type B = Opiton; // Misspelled type name from the prelude. | = note: similarly named enum `Option` defined here -error[E0412]: cannot find type `Baz` in this scope +error[E0425]: cannot find type `Baz` in this scope --> $DIR/levenshtein.rs:16:14 | LL | type A = Baz; // No suggestion here, Bar is not visible @@ -38,7 +38,7 @@ LL | const MAX_ITEM: usize = 10; LL | let v = [0u32; MAXITEM]; // Misspelled constant name. | ^^^^^^^ help: a constant with a similar name exists: `MAX_ITEM` -error[E0412]: cannot find type `first` in module `m` +error[E0425]: cannot find type `first` in module `m` --> $DIR/levenshtein.rs:28:15 | LL | pub struct First; @@ -67,5 +67,4 @@ LL | foobar(); // Misspelled function name. error: aborting due to 8 previous errors -Some errors have detailed explanations: E0412, E0425. -For more information about an error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/missing-type-in-scope-58712.stderr b/tests/ui/resolve/missing-type-in-scope-58712.stderr index d7e06eee856c..bd4078123068 100644 --- a/tests/ui/resolve/missing-type-in-scope-58712.stderr +++ b/tests/ui/resolve/missing-type-in-scope-58712.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `DeviceId` in this scope +error[E0425]: cannot find type `DeviceId` in this scope --> $DIR/missing-type-in-scope-58712.rs:7:20 | LL | impl AddrVec { @@ -9,7 +9,7 @@ help: you might be missing a type parameter LL | impl AddrVec { | ++++++++++ -error[E0412]: cannot find type `DeviceId` in this scope +error[E0425]: cannot find type `DeviceId` in this scope --> $DIR/missing-type-in-scope-58712.rs:9:29 | LL | pub fn device(&self) -> DeviceId { @@ -17,4 +17,4 @@ LL | pub fn device(&self) -> DeviceId { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr index 3082674941fd..81356c5040f8 100644 --- a/tests/ui/resolve/privacy-enum-ctor.stderr +++ b/tests/ui/resolve/privacy-enum-ctor.stderr @@ -142,7 +142,7 @@ LL + use std::f32::consts::E; LL + use std::f64::consts::E; | -error[E0412]: cannot find type `Z` in this scope +error[E0425]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:58:12 | LL | pub enum E { @@ -185,7 +185,7 @@ LL - let _: Z = m::n::Z; LL + let _: Z = (m::Z::Fn(/* fields */)); | -error[E0412]: cannot find type `Z` in this scope +error[E0425]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:62:12 | LL | pub enum E { @@ -200,7 +200,7 @@ note: enum `m::Z` exists but is inaccessible LL | pub(in crate::m) enum Z { | ^^^^^^^^^^^^^^^^^^^^^^^ not accessible -error[E0412]: cannot find type `Z` in this scope +error[E0425]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:65:12 | LL | pub enum E { @@ -215,7 +215,7 @@ note: enum `m::Z` exists but is inaccessible LL | pub(in crate::m) enum Z { | ^^^^^^^^^^^^^^^^^^^^^^^ not accessible -error[E0412]: cannot find type `Z` in this scope +error[E0425]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:69:12 | LL | pub enum E { @@ -433,5 +433,5 @@ LL | let _: Z = m::n::Z::Struct { s: /* value */ }; error: aborting due to 23 previous errors -Some errors have detailed explanations: E0308, E0412, E0423, E0533, E0603, E0618. +Some errors have detailed explanations: E0308, E0423, E0425, E0533, E0603, E0618. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/resolve/raw-ident-in-path.stderr b/tests/ui/resolve/raw-ident-in-path.stderr index 7d2aa6911363..e88465ab8952 100644 --- a/tests/ui/resolve/raw-ident-in-path.stderr +++ b/tests/ui/resolve/raw-ident-in-path.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `r#break` in the crate root +error[E0425]: cannot find type `r#break` in the crate root --> $DIR/raw-ident-in-path.rs:3:17 | LL | type A = crate::r#break; @@ -6,4 +6,4 @@ LL | type A = crate::r#break; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/resolve-assoc-suggestions.stderr b/tests/ui/resolve/resolve-assoc-suggestions.stderr index 3d9d4ffaa10c..ef519ac0d921 100644 --- a/tests/ui/resolve/resolve-assoc-suggestions.stderr +++ b/tests/ui/resolve/resolve-assoc-suggestions.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `field` in this scope +error[E0425]: cannot find type `field` in this scope --> $DIR/resolve-assoc-suggestions.rs:16:16 | LL | let _: field; @@ -21,7 +21,7 @@ help: you might have meant to use the available field LL | self.field; | +++++ -error[E0412]: cannot find type `Type` in this scope +error[E0425]: cannot find type `Type` in this scope --> $DIR/resolve-assoc-suggestions.rs:23:16 | LL | let _: Type; @@ -44,7 +44,7 @@ error[E0425]: cannot find value `Type` in this scope LL | Type; | ^^^^ not found in this scope -error[E0412]: cannot find type `method` in this scope +error[E0425]: cannot find type `method` in this scope --> $DIR/resolve-assoc-suggestions.rs:30:16 | LL | let _: method; @@ -69,5 +69,5 @@ LL | self.method; error: aborting due to 9 previous errors -Some errors have detailed explanations: E0412, E0425, E0531. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0531. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/resolve-primitive-fallback.stderr b/tests/ui/resolve/resolve-primitive-fallback.stderr index f9ab55913d14..17b8cf805de2 100644 --- a/tests/ui/resolve/resolve-primitive-fallback.stderr +++ b/tests/ui/resolve/resolve-primitive-fallback.stderr @@ -4,7 +4,7 @@ error[E0423]: expected value, found builtin type `u16` LL | std::mem::size_of(u16); | ^^^ not a value -error[E0412]: cannot find type `u8` in the crate root +error[E0425]: cannot find type `u8` in the crate root --> $DIR/resolve-primitive-fallback.rs:9:14 | LL | let _: ::u8; @@ -36,5 +36,5 @@ LL + std::mem::size_of(); error: aborting due to 3 previous errors -Some errors have detailed explanations: E0061, E0412, E0423. +Some errors have detailed explanations: E0061, E0423, E0425. For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr index 1ecbfee17bc7..039410f8795f 100644 --- a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr +++ b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr @@ -61,7 +61,7 @@ help: a constant with a similar name exists LL | BARR; | + -error[E0412]: cannot find type `Baz` in this scope +error[E0425]: cannot find type `Baz` in this scope --> $DIR/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs:37:18 | LL | let foo: Baz = "".to_string(); @@ -101,5 +101,4 @@ LL + ba(); error: aborting due to 7 previous errors -Some errors have detailed explanations: E0412, E0425. -For more information about an error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/use_suggestion.stderr b/tests/ui/resolve/use_suggestion.stderr index 1155f5caa173..9981c97b2c17 100644 --- a/tests/ui/resolve/use_suggestion.stderr +++ b/tests/ui/resolve/use_suggestion.stderr @@ -9,7 +9,7 @@ help: consider importing this struct LL + use std::collections::HashMap; | -error[E0412]: cannot find type `HashMap` in this scope +error[E0425]: cannot find type `HashMap` in this scope --> $DIR/use_suggestion.rs:5:13 | LL | let y1: HashMap; @@ -20,7 +20,7 @@ help: consider importing this struct LL + use std::collections::HashMap; | -error[E0412]: cannot find type `GooMap` in this scope +error[E0425]: cannot find type `GooMap` in this scope --> $DIR/use_suggestion.rs:6:13 | LL | let y2: GooMap; @@ -34,5 +34,5 @@ LL | let x2 = GooMap::new(); error: aborting due to 4 previous errors -Some errors have detailed explanations: E0412, E0433. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0433. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/use_suggestion_placement.stderr b/tests/ui/resolve/use_suggestion_placement.stderr index e92a230ad765..85ad25665768 100644 --- a/tests/ui/resolve/use_suggestion_placement.stderr +++ b/tests/ui/resolve/use_suggestion_placement.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Path` in this scope +error[E0425]: cannot find type `Path` in this scope --> $DIR/use_suggestion_placement.rs:19:16 | LL | type Bar = Path; @@ -20,7 +20,7 @@ help: consider importing this constant LL + use m::A; | -error[E0412]: cannot find type `HashMap` in this scope +error[E0425]: cannot find type `HashMap` in this scope --> $DIR/use_suggestion_placement.rs:29:23 | LL | type Dict = HashMap; @@ -33,5 +33,4 @@ LL + use std::collections::HashMap; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0412, E0425. -For more information about an error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/self/elision/nested-item.stderr b/tests/ui/self/elision/nested-item.stderr index 7bad26fa1330..0e6e36a30f9c 100644 --- a/tests/ui/self/elision/nested-item.stderr +++ b/tests/ui/self/elision/nested-item.stderr @@ -35,7 +35,7 @@ LL - fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &() { LL + fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> () { | -error[E0412]: cannot find type `Wrap` in this scope +error[E0425]: cannot find type `Wrap` in this scope --> $DIR/nested-item.rs:5:15 | LL | fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &() { @@ -43,5 +43,5 @@ LL | fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &() { error: aborting due to 4 previous errors -Some errors have detailed explanations: E0106, E0412. +Some errors have detailed explanations: E0106, E0425. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr index eec2f5b42fda..d253c7c065b9 100644 --- a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr +++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr @@ -6,7 +6,7 @@ LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes; | = note: arbitrary expressions are not allowed in patterns: -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:55 | LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes; @@ -47,5 +47,5 @@ LL | let str::<{fn str() { let str::T>>::as_bytes: /* Type */; }}, T>::as_by error: aborting due to 5 previous errors -Some errors have detailed explanations: E0109, E0282, E0412, E0533. +Some errors have detailed explanations: E0109, E0282, E0425, E0533. For more information about an error, try `rustc --explain E0109`. diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr index 00b9a81b27d9..b2380f4ba273 100644 --- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr +++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr @@ -7,7 +7,7 @@ LL | pub(crate) async fn new( = help: pass `--edition 2024` to `rustc` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0412]: cannot find type `Duration` in this scope +error[E0425]: cannot find type `Duration` in this scope --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:12:19 | LL | interval: Duration, @@ -20,5 +20,5 @@ LL + use std::time::Duration; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0412, E0670. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0670. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/specialization/issue-68830-spurious-diagnostics.stderr b/tests/ui/specialization/issue-68830-spurious-diagnostics.stderr index 0ecec03a023e..f668fda119c2 100644 --- a/tests/ui/specialization/issue-68830-spurious-diagnostics.stderr +++ b/tests/ui/specialization/issue-68830-spurious-diagnostics.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `MissingType` in this scope +error[E0425]: cannot find type `MissingType` in this scope --> $DIR/issue-68830-spurious-diagnostics.rs:8:10 | LL | err: MissingType @@ -6,4 +6,4 @@ LL | err: MissingType error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/specialization/min_specialization/impl-on-nonexisting.stderr b/tests/ui/specialization/min_specialization/impl-on-nonexisting.stderr index 85b492c0503b..a531d07d97c5 100644 --- a/tests/ui/specialization/min_specialization/impl-on-nonexisting.stderr +++ b/tests/ui/specialization/min_specialization/impl-on-nonexisting.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `NonExistent` in this scope +error[E0425]: cannot find type `NonExistent` in this scope --> $DIR/impl-on-nonexisting.rs:4:16 | LL | impl Trait for NonExistent {} @@ -6,4 +6,4 @@ LL | impl Trait for NonExistent {} error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/structs/ice-struct-tail-normalization-113272.stderr b/tests/ui/structs/ice-struct-tail-normalization-113272.stderr index 8c55dbca1871..9663f93c169b 100644 --- a/tests/ui/structs/ice-struct-tail-normalization-113272.stderr +++ b/tests/ui/structs/ice-struct-tail-normalization-113272.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/ice-struct-tail-normalization-113272.rs:5:25 | LL | impl Trait for () where Missing: Trait {} @@ -24,5 +24,5 @@ LL | std::mem::transmute::, Option<&Other>>(None); error: aborting due to 3 previous errors -Some errors have detailed explanations: E0046, E0412, E0512. +Some errors have detailed explanations: E0046, E0425, E0512. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/suggestions/assoc-type-in-method-return.stderr b/tests/ui/suggestions/assoc-type-in-method-return.stderr index f83da7909700..23a2fd5c504e 100644 --- a/tests/ui/suggestions/assoc-type-in-method-return.stderr +++ b/tests/ui/suggestions/assoc-type-in-method-return.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Bla` in this scope +error[E0425]: cannot find type `Bla` in this scope --> $DIR/assoc-type-in-method-return.rs:3:25 | LL | fn to_bla(&self) -> Bla; @@ -11,4 +11,4 @@ LL | fn to_bla(&self) -> Self::Bla; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs index e53932f79003..e7ce2b38b1b2 100644 --- a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs +++ b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs @@ -9,16 +9,16 @@ mod local { } pub fn test(_: Foo) {} -//~^ ERROR [E0412] +//~^ ERROR [E0425] pub fn test2(_: Bar) {} -//~^ ERROR [E0412] +//~^ ERROR [E0425] pub fn test3(_: Baz) {} -//~^ ERROR [E0412] +//~^ ERROR [E0425] pub fn test4(_: Quux) {} -//~^ ERROR [E0412] +//~^ ERROR [E0425] fn test5() {} diff --git a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr index 5ac336b0c3e2..623bc723eb6c 100644 --- a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr +++ b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Foo` in this scope +error[E0425]: cannot find type `Foo` in this scope --> $DIR/dont-suggest-foreign-doc-hidden.rs:11:16 | LL | pub fn test(_: Foo) {} @@ -9,13 +9,13 @@ help: consider importing this struct LL + use local::Foo; | -error[E0412]: cannot find type `Bar` in this scope +error[E0425]: cannot find type `Bar` in this scope --> $DIR/dont-suggest-foreign-doc-hidden.rs:14:17 | LL | pub fn test2(_: Bar) {} | ^^^ not found in this scope -error[E0412]: cannot find type `Baz` in this scope +error[E0425]: cannot find type `Baz` in this scope --> $DIR/dont-suggest-foreign-doc-hidden.rs:17:17 | LL | pub fn test3(_: Baz) {} @@ -26,7 +26,7 @@ help: consider importing this struct LL + use hidden_struct::Baz; | -error[E0412]: cannot find type `Quux` in this scope +error[E0425]: cannot find type `Quux` in this scope --> $DIR/dont-suggest-foreign-doc-hidden.rs:20:17 | LL | pub fn test4(_: Quux) {} @@ -83,5 +83,5 @@ LL | fn test6() {} error: aborting due to 6 previous errors -Some errors have detailed explanations: E0277, E0412. +Some errors have detailed explanations: E0277, E0425. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/suggestions/no-extern-crate-in-type.stderr b/tests/ui/suggestions/no-extern-crate-in-type.stderr index 384b17d1e2b4..6e71b351d1b5 100644 --- a/tests/ui/suggestions/no-extern-crate-in-type.stderr +++ b/tests/ui/suggestions/no-extern-crate-in-type.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Foo` in this scope +error[E0425]: cannot find type `Foo` in this scope --> $DIR/no-extern-crate-in-type.rs:5:22 | LL | type Output = Option; @@ -11,4 +11,4 @@ LL + use foo::Foo; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/suggestions/type-not-found-in-adt-field.stderr b/tests/ui/suggestions/type-not-found-in-adt-field.stderr index 934ba87bbaa8..7d8c6433eb5a 100644 --- a/tests/ui/suggestions/type-not-found-in-adt-field.stderr +++ b/tests/ui/suggestions/type-not-found-in-adt-field.stderr @@ -1,10 +1,10 @@ -error[E0412]: cannot find type `Someunknownname` in this scope +error[E0425]: cannot find type `Someunknownname` in this scope --> $DIR/type-not-found-in-adt-field.rs:2:12 | LL | m: Vec>, | ^^^^^^^^^^^^^^^ not found in this scope -error[E0412]: cannot find type `K` in this scope +error[E0425]: cannot find type `K` in this scope --> $DIR/type-not-found-in-adt-field.rs:6:8 | LL | m: K, @@ -17,4 +17,4 @@ LL | struct OtherStruct { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.stderr b/tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.stderr index 0be80e9479f0..c70d4cefe939 100644 --- a/tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.stderr +++ b/tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.stderr @@ -1,10 +1,10 @@ -error[E0412]: cannot find type `Idx` in this scope +error[E0425]: cannot find type `Idx` in this scope --> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:30 | LL | struct MySlice Idx>(bool, T); | ^^^ not found in this scope -error[E0412]: cannot find type `Idx` in this scope +error[E0425]: cannot find type `Idx` in this scope --> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:38 | LL | struct MySlice Idx>(bool, T); @@ -53,5 +53,5 @@ LL | struct MySlice Idx>(bool, T); error: aborting due to 4 previous errors -Some errors have detailed explanations: E0277, E0412. +Some errors have detailed explanations: E0277, E0425. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/trait-bounds/impl-bound-with-references-error.rs b/tests/ui/trait-bounds/impl-bound-with-references-error.rs index 5ba35da83839..6213f7432942 100644 --- a/tests/ui/trait-bounds/impl-bound-with-references-error.rs +++ b/tests/ui/trait-bounds/impl-bound-with-references-error.rs @@ -10,7 +10,7 @@ impl From for LabelText //~^ ERROR conflicting implementations of trait `From` for type `LabelText` [E0119] where T: Into>, - //~^ ERROR cannot find type `Cow` in this scope [E0412] + //~^ ERROR cannot find type `Cow` in this scope [E0425] { fn from(text: T) -> Self { LabelText::Plain(text.into()) //~ ERROR expected function, found `LabelText` diff --git a/tests/ui/trait-bounds/impl-bound-with-references-error.stderr b/tests/ui/trait-bounds/impl-bound-with-references-error.stderr index b3ac5544e38f..ca8a575e2caa 100644 --- a/tests/ui/trait-bounds/impl-bound-with-references-error.stderr +++ b/tests/ui/trait-bounds/impl-bound-with-references-error.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Cow` in this scope +error[E0425]: cannot find type `Cow` in this scope --> $DIR/impl-bound-with-references-error.rs:12:13 | LL | T: Into>, @@ -34,5 +34,5 @@ LL | LabelText::Plain(text.into()) error: aborting due to 3 previous errors -Some errors have detailed explanations: E0119, E0412, E0618. +Some errors have detailed explanations: E0119, E0425, E0618. For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/duplicate-generic-parameter-error-86756.stderr b/tests/ui/traits/duplicate-generic-parameter-error-86756.stderr index e761d15ff670..16043d868e07 100644 --- a/tests/ui/traits/duplicate-generic-parameter-error-86756.stderr +++ b/tests/ui/traits/duplicate-generic-parameter-error-86756.stderr @@ -6,7 +6,7 @@ LL | trait Foo {} | | | first use of `T` -error[E0412]: cannot find type `dyn` in this scope +error[E0425]: cannot find type `dyn` in this scope --> $DIR/duplicate-generic-parameter-error-86756.rs:7:10 | LL | eq:: @@ -44,5 +44,5 @@ LL | eq::> error: aborting due to 3 previous errors; 1 warning emitted -Some errors have detailed explanations: E0107, E0403, E0412. +Some errors have detailed explanations: E0107, E0403, E0425. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/error-reporting/apit-with-bad-path.stderr b/tests/ui/traits/error-reporting/apit-with-bad-path.stderr index 19bd5e78b47f..c4cc000d4753 100644 --- a/tests/ui/traits/error-reporting/apit-with-bad-path.stderr +++ b/tests/ui/traits/error-reporting/apit-with-bad-path.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Path` in this scope +error[E0425]: cannot find type `Path` in this scope --> $DIR/apit-with-bad-path.rs:3:29 | LL | fn foo(filename: impl AsRef) { @@ -11,4 +11,4 @@ LL + use std::path::Path; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/traits/error-reporting/where-clause-with-bad-path.stderr b/tests/ui/traits/error-reporting/where-clause-with-bad-path.stderr index 1137178f6114..763898277b8f 100644 --- a/tests/ui/traits/error-reporting/where-clause-with-bad-path.stderr +++ b/tests/ui/traits/error-reporting/where-clause-with-bad-path.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Path` in this scope +error[E0425]: cannot find type `Path` in this scope --> $DIR/where-clause-with-bad-path.rs:3:17 | LL | fn foo>(filename: T) { @@ -11,4 +11,4 @@ LL + use std::path::Path; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/traits/ignore-err-impls.stderr b/tests/ui/traits/ignore-err-impls.stderr index 955e2d780498..68077c435135 100644 --- a/tests/ui/traits/ignore-err-impls.stderr +++ b/tests/ui/traits/ignore-err-impls.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Type` in this scope +error[E0425]: cannot find type `Type` in this scope --> $DIR/ignore-err-impls.rs:6:14 | LL | impl Generic for S {} @@ -11,4 +11,4 @@ LL | impl Generic for S {} error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/traits/issue-50480.stderr b/tests/ui/traits/issue-50480.stderr index ed8c74e9bddc..32c8b2cf3ac1 100644 --- a/tests/ui/traits/issue-50480.stderr +++ b/tests/ui/traits/issue-50480.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `N` in this scope +error[E0425]: cannot find type `N` in this scope --> $DIR/issue-50480.rs:3:12 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); @@ -9,13 +9,13 @@ help: you might be missing a type parameter LL | struct Foo(N, NotDefined, ::Item, Vec, String); | +++ -error[E0412]: cannot find type `NotDefined` in this scope +error[E0425]: cannot find type `NotDefined` in this scope --> $DIR/issue-50480.rs:3:15 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | ^^^^^^^^^^ not found in this scope -error[E0412]: cannot find type `N` in this scope +error[E0425]: cannot find type `N` in this scope --> $DIR/issue-50480.rs:3:12 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); @@ -26,7 +26,7 @@ help: you might be missing a type parameter LL | struct Foo(N, NotDefined, ::Item, Vec, String); | +++ -error[E0412]: cannot find type `NotDefined` in this scope +error[E0425]: cannot find type `NotDefined` in this scope --> $DIR/issue-50480.rs:3:15 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); @@ -37,7 +37,7 @@ help: you might be missing a type parameter LL | struct Foo(N, NotDefined, ::Item, Vec, String); | ++++++++++++ -error[E0412]: cannot find type `N` in this scope +error[E0425]: cannot find type `N` in this scope --> $DIR/issue-50480.rs:14:18 | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); @@ -55,7 +55,7 @@ help: you might be missing a type parameter LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | +++ -error[E0412]: cannot find type `NotDefined` in this scope +error[E0425]: cannot find type `NotDefined` in this scope --> $DIR/issue-50480.rs:14:21 | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); @@ -128,5 +128,5 @@ LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); error: aborting due to 13 previous errors -Some errors have detailed explanations: E0204, E0277, E0412. +Some errors have detailed explanations: E0204, E0277, E0425. For more information about an error, try `rustc --explain E0204`. diff --git a/tests/ui/traits/issue-75627.stderr b/tests/ui/traits/issue-75627.stderr index 137985ee0464..0a3fc181aea2 100644 --- a/tests/ui/traits/issue-75627.stderr +++ b/tests/ui/traits/issue-75627.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/issue-75627.rs:3:26 | LL | unsafe impl Send for Foo {} @@ -11,4 +11,4 @@ LL | unsafe impl Send for Foo {} error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/traits/issue-78372.stderr b/tests/ui/traits/issue-78372.stderr index a1c772f58e1f..6744281dc34e 100644 --- a/tests/ui/traits/issue-78372.stderr +++ b/tests/ui/traits/issue-78372.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `PhantomData` in this scope +error[E0425]: cannot find type `PhantomData` in this scope --> $DIR/issue-78372.rs:2:23 | LL | struct Smaht(PhantomData); @@ -9,7 +9,7 @@ help: consider importing this struct LL + use std::marker::PhantomData; | -error[E0412]: cannot find type `U` in this scope +error[E0425]: cannot find type `U` in this scope --> $DIR/issue-78372.rs:3:31 | LL | impl DispatchFromDyn> for T {} @@ -27,7 +27,7 @@ help: you might be missing a type parameter LL | impl DispatchFromDyn> for T {} | +++ -error[E0412]: cannot find type `MISC` in this scope +error[E0425]: cannot find type `MISC` in this scope --> $DIR/issue-78372.rs:3:34 | LL | impl DispatchFromDyn> for T {} @@ -73,5 +73,5 @@ LL | fn foo(self: Smaht); error: aborting due to 7 previous errors -Some errors have detailed explanations: E0307, E0377, E0412, E0658. +Some errors have detailed explanations: E0307, E0377, E0425, E0658. For more information about an error, try `rustc --explain E0307`. diff --git a/tests/ui/traits/next-solver/dont-normalize-proj-with-error.stderr b/tests/ui/traits/next-solver/dont-normalize-proj-with-error.stderr index 576ede52aff2..67690a85d53c 100644 --- a/tests/ui/traits/next-solver/dont-normalize-proj-with-error.stderr +++ b/tests/ui/traits/next-solver/dont-normalize-proj-with-error.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `TypeError` in this scope +error[E0425]: cannot find type `TypeError` in this scope --> $DIR/dont-normalize-proj-with-error.rs:17:20 | LL | fn type_error() -> TypeError { todo!() } @@ -6,4 +6,4 @@ LL | fn type_error() -> TypeError { todo!() } error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index e934c5cdc749..74cbb5be02b3 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/issue-118950-root-region.rs:19:55 | LL | impl Overlap fn(Assoc<'a, T>)> for T where Missing: Overlap {} @@ -28,5 +28,5 @@ LL | trait ToUnit<'a> { WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a)), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. } error: aborting due to 2 previous errors; 1 warning emitted -Some errors have detailed explanations: E0277, E0412. +Some errors have detailed explanations: E0277, E0425. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr index d9e77dec794a..608e8136d2a8 100644 --- a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `V` in this scope +error[E0425]: cannot find type `V` in this scope --> $DIR/binder-defaults-112547.rs:10:4 | LL | }> V: IntoIterator @@ -37,4 +37,4 @@ LL | | }> V: IntoIterator error: aborting due to 3 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-118697.stderr b/tests/ui/traits/non_lifetime_binders/binder-defaults-118697.stderr index 6b93f52dbfca..9dea5b40159a 100644 --- a/tests/ui/traits/non_lifetime_binders/binder-defaults-118697.stderr +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-118697.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `A` in this scope +error[E0425]: cannot find type `A` in this scope --> $DIR/binder-defaults-118697.rs:4:22 | LL | type T = dyn for Fn(()); @@ -18,4 +18,4 @@ LL | type T = dyn for Fn(()); error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/traits/trait-selection-ice-84727.stderr b/tests/ui/traits/trait-selection-ice-84727.stderr index d4bc4163897c..c37c267c893e 100644 --- a/tests/ui/traits/trait-selection-ice-84727.stderr +++ b/tests/ui/traits/trait-selection-ice-84727.stderr @@ -1,22 +1,22 @@ -error[E0412]: cannot find type `Color` in this scope +error[E0425]: cannot find type `Color` in this scope --> $DIR/trait-selection-ice-84727.rs:5:17 | LL | foreground: Color, | ^^^^^ not found in this scope -error[E0412]: cannot find type `Color` in this scope +error[E0425]: cannot find type `Color` in this scope --> $DIR/trait-selection-ice-84727.rs:7:17 | LL | background: Color, | ^^^^^ not found in this scope -error[E0412]: cannot find type `Color` in this scope +error[E0425]: cannot find type `Color` in this scope --> $DIR/trait-selection-ice-84727.rs:18:16 | LL | Self: Over, Cell>, | ^^^^^ not found in this scope -error[E0412]: cannot find type `NewBg` in this scope +error[E0425]: cannot find type `NewBg` in this scope --> $DIR/trait-selection-ice-84727.rs:32:27 | LL | fn over(self) -> Cell { @@ -43,5 +43,5 @@ LL | self.over(); error: aborting due to 5 previous errors -Some errors have detailed explanations: E0308, E0412. +Some errors have detailed explanations: E0308, E0425. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/transmutability/issue-101739-1.stderr b/tests/ui/transmutability/issue-101739-1.stderr index 20bc8af47f8d..8ec3c8508fa9 100644 --- a/tests/ui/transmutability/issue-101739-1.stderr +++ b/tests/ui/transmutability/issue-101739-1.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Dst` in this scope +error[E0425]: cannot find type `Dst` in this scope --> $DIR/issue-101739-1.rs:8:9 | LL | Dst: TransmuteFrom, @@ -6,4 +6,4 @@ LL | Dst: TransmuteFrom, error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr index 9fa376bf4332..530cfc7e9b18 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Dst` in this scope +error[E0425]: cannot find type `Dst` in this scope --> $DIR/unknown_dst.rs:18:36 | LL | assert::is_transmutable::(); @@ -11,4 +11,4 @@ LL | fn should_gracefully_handle_unknown_dst() { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.stderr b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.stderr index 564aee687a5f..267f3b55619e 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.stderr +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.stderr @@ -1,10 +1,10 @@ -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/unknown_dst_field.rs:18:27 | LL | #[repr(C)] struct Dst(Missing); | ^^^^^^^ not found in this scope -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/unknown_dst_field.rs:24:36 | LL | #[repr(C)] struct Dst(&'static Missing); @@ -42,5 +42,5 @@ LL | Dst: TransmuteFrom error: aborting due to 4 previous errors -Some errors have detailed explanations: E0277, E0412. +Some errors have detailed explanations: E0277, E0425. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr index f2c7d9e1bcc1..0ee03efef9f8 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Src` in this scope +error[E0425]: cannot find type `Src` in this scope --> $DIR/unknown_src.rs:18:31 | LL | assert::is_transmutable::(); @@ -11,4 +11,4 @@ LL | fn should_gracefully_handle_unknown_src() { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr index 1156391c301c..e6bb45a34a1d 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr @@ -1,10 +1,10 @@ -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/unknown_src_field.rs:17:27 | LL | #[repr(C)] struct Src(Missing); | ^^^^^^^ not found in this scope -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/unknown_src_field.rs:23:36 | LL | #[repr(C)] struct Src(&'static Missing); @@ -42,5 +42,5 @@ LL | Dst: TransmuteFrom error: aborting due to 4 previous errors -Some errors have detailed explanations: E0277, E0412. +Some errors have detailed explanations: E0277, E0425. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/tuple/tuple-struct-fields/test.stderr b/tests/ui/tuple/tuple-struct-fields/test.stderr index bfa0b32fd458..61dcbde13b57 100644 --- a/tests/ui/tuple/tuple-struct-fields/test.stderr +++ b/tests/ui/tuple/tuple-struct-fields/test.stderr @@ -6,7 +6,7 @@ LL | struct S2(pub((foo)) ()); | | | help: missing `,` -error[E0412]: cannot find type `foo` in this scope +error[E0425]: cannot find type `foo` in this scope --> $DIR/test.rs:4:20 | LL | struct S2(pub((foo)) ()); @@ -14,4 +14,4 @@ LL | struct S2(pub((foo)) ()); error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/tuple/tuple-struct-fields/test2.stderr b/tests/ui/tuple/tuple-struct-fields/test2.stderr index 784411aba8f8..53706eb90bbb 100644 --- a/tests/ui/tuple/tuple-struct-fields/test2.stderr +++ b/tests/ui/tuple/tuple-struct-fields/test2.stderr @@ -11,13 +11,13 @@ LL | define_struct! { (foo) } | = note: this error originates in the macro `define_struct` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `foo` in this scope +error[E0425]: cannot find type `foo` in this scope --> $DIR/test2.rs:11:23 | LL | define_struct! { (foo) } | ^^^ not found in this scope -error[E0412]: cannot find type `foo` in this scope +error[E0425]: cannot find type `foo` in this scope --> $DIR/test2.rs:11:23 | LL | define_struct! { (foo) } @@ -27,4 +27,4 @@ LL | define_struct! { (foo) } error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/tuple/tuple-struct-fields/test3.stderr b/tests/ui/tuple/tuple-struct-fields/test3.stderr index 00b07c031529..6a30e4ba5da2 100644 --- a/tests/ui/tuple/tuple-struct-fields/test3.stderr +++ b/tests/ui/tuple/tuple-struct-fields/test3.stderr @@ -11,13 +11,13 @@ LL | define_struct! { foo } | = note: this error originates in the macro `define_struct` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `foo` in this scope +error[E0425]: cannot find type `foo` in this scope --> $DIR/test3.rs:11:22 | LL | define_struct! { foo } | ^^^ not found in this scope -error[E0412]: cannot find type `foo` in this scope +error[E0425]: cannot find type `foo` in this scope --> $DIR/test3.rs:11:22 | LL | define_struct! { foo } @@ -27,4 +27,4 @@ LL | define_struct! { foo } error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/type-alias-impl-trait/define_opaques_attr/invalid_path.stderr b/tests/ui/type-alias-impl-trait/define_opaques_attr/invalid_path.stderr index 6b4cd4eac512..c6c530b41aff 100644 --- a/tests/ui/type-alias-impl-trait/define_opaques_attr/invalid_path.stderr +++ b/tests/ui/type-alias-impl-trait/define_opaques_attr/invalid_path.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type alias or associated type with opaqaue types `Boom` in this scope +error[E0425]: cannot find type alias or associated type with opaqaue types `Boom` in this scope --> $DIR/invalid_path.rs:3:17 | LL | #[define_opaque(Boom)] @@ -6,4 +6,4 @@ LL | #[define_opaque(Boom)] error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.stderr b/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.stderr index 3a13ab7cb957..936bdd59cc9b 100644 --- a/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.stderr +++ b/tests/ui/type-alias-impl-trait/nested-impl-trait-in-tait.stderr @@ -14,7 +14,7 @@ help: consider introducing lifetime `'db` here LL | pub type Tait<'db> = impl Iterator; | +++++ -error[E0412]: cannot find type `LocalKey` in this scope +error[E0425]: cannot find type `LocalKey` in this scope --> $DIR/nested-impl-trait-in-tait.rs:3:44 | LL | pub type Tait = impl Iterator; @@ -43,5 +43,5 @@ LL | pub type Tait = impl Iterator; error: aborting due to 4 previous errors -Some errors have detailed explanations: E0261, E0412. +Some errors have detailed explanations: E0261, E0425. For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/type/cannot-find-wrapper-with-impl-trait.rs b/tests/ui/type/cannot-find-wrapper-with-impl-trait.rs index 48ff4c38f7db..0117f634c85e 100644 --- a/tests/ui/type/cannot-find-wrapper-with-impl-trait.rs +++ b/tests/ui/type/cannot-find-wrapper-with-impl-trait.rs @@ -6,7 +6,7 @@ pub trait A { } fn addition() -> Wrapper {} -//~^ ERROR cannot find type `Wrapper` in this scope [E0412] +//~^ ERROR cannot find type `Wrapper` in this scope [E0425] fn main() { let res = addition(); diff --git a/tests/ui/type/cannot-find-wrapper-with-impl-trait.stderr b/tests/ui/type/cannot-find-wrapper-with-impl-trait.stderr index ac7f2e5134a2..22fd8f99806b 100644 --- a/tests/ui/type/cannot-find-wrapper-with-impl-trait.stderr +++ b/tests/ui/type/cannot-find-wrapper-with-impl-trait.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Wrapper` in this scope +error[E0425]: cannot find type `Wrapper` in this scope --> $DIR/cannot-find-wrapper-with-impl-trait.rs:8:18 | LL | fn addition() -> Wrapper {} @@ -6,4 +6,4 @@ LL | fn addition() -> Wrapper {} error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/type/issue-7607-1.stderr b/tests/ui/type/issue-7607-1.stderr index 69b6d62e987a..ac6034da75f1 100644 --- a/tests/ui/type/issue-7607-1.stderr +++ b/tests/ui/type/issue-7607-1.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Fo` in this scope +error[E0425]: cannot find type `Fo` in this scope --> $DIR/issue-7607-1.rs:5:6 | LL | impl Fo { @@ -10,4 +10,4 @@ LL | impl Fo { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/type/type-path-err-node-types.stderr b/tests/ui/type/type-path-err-node-types.stderr index 8b12aa1a393b..a9e999f80b3a 100644 --- a/tests/ui/type/type-path-err-node-types.stderr +++ b/tests/ui/type/type-path-err-node-types.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Nonexistent` in this scope +error[E0425]: cannot find type `Nonexistent` in this scope --> $DIR/type-path-err-node-types.rs:7:12 | LL | let _: Nonexistent; @@ -35,5 +35,5 @@ LL | let _ = |a: /* Type */, b: _| -> _ { 0 }; error: aborting due to 5 previous errors -Some errors have detailed explanations: E0282, E0412, E0425, E0433, E0576. +Some errors have detailed explanations: E0282, E0425, E0433, E0576. For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/typeck/apit-with-error-type-in-sig.stderr b/tests/ui/typeck/apit-with-error-type-in-sig.stderr index 6ed9b1f9b8cb..21ae7554d2bb 100644 --- a/tests/ui/typeck/apit-with-error-type-in-sig.stderr +++ b/tests/ui/typeck/apit-with-error-type-in-sig.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Bar` in this scope +error[E0425]: cannot find type `Bar` in this scope --> $DIR/apit-with-error-type-in-sig.rs:1:12 | LL | type Foo = Bar; @@ -6,4 +6,4 @@ LL | type Foo = Bar; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/typeck/autoderef-with-param-env-error.stderr b/tests/ui/typeck/autoderef-with-param-env-error.stderr index e06be398aa07..dd4cfa761ce8 100644 --- a/tests/ui/typeck/autoderef-with-param-env-error.stderr +++ b/tests/ui/typeck/autoderef-with-param-env-error.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `T` in this scope +error[E0425]: cannot find type `T` in this scope --> $DIR/autoderef-with-param-env-error.rs:3:5 | LL | T: Send, @@ -11,4 +11,4 @@ LL | fn foo() error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/typeck/impl-for-nonexistent-type-error-8767.stderr b/tests/ui/typeck/impl-for-nonexistent-type-error-8767.stderr index 0e37391a00f7..354eb4019c65 100644 --- a/tests/ui/typeck/impl-for-nonexistent-type-error-8767.stderr +++ b/tests/ui/typeck/impl-for-nonexistent-type-error-8767.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `B` in this scope +error[E0425]: cannot find type `B` in this scope --> $DIR/impl-for-nonexistent-type-error-8767.rs:2:6 | LL | impl B { @@ -6,4 +6,4 @@ LL | impl B { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/typeck/issue-104510-ice.stderr b/tests/ui/typeck/issue-104510-ice.stderr index 143139b2c089..5f330a4e685c 100644 --- a/tests/ui/typeck/issue-104510-ice.stderr +++ b/tests/ui/typeck/issue-104510-ice.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Oops` in this scope +error[E0425]: cannot find type `Oops` in this scope --> $DIR/issue-104510-ice.rs:4:21 | LL | struct W(Oops); @@ -6,4 +6,4 @@ LL | struct W(Oops); error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/typeck/issue-83693.rs b/tests/ui/typeck/issue-83693.rs index 68a1416517a7..f78cf7da4a98 100644 --- a/tests/ui/typeck/issue-83693.rs +++ b/tests/ui/typeck/issue-83693.rs @@ -4,16 +4,16 @@ #![crate_type="lib"] impl F { -//~^ ERROR: cannot find type `F` in this scope [E0412] +//~^ ERROR: cannot find type `F` in this scope [E0425] fn call() { ::call - //~^ ERROR: cannot find type `TestResult` in this scope [E0412] + //~^ ERROR: cannot find type `TestResult` in this scope [E0425] //~| ERROR associated item constraints are not allowed here [E0229] } } fn call() { ::call - //~^ ERROR: cannot find type `x` in this scope [E0412] + //~^ ERROR: cannot find type `x` in this scope [E0425] //~| ERROR: associated item constraints are not allowed here [E0229] } diff --git a/tests/ui/typeck/issue-83693.stderr b/tests/ui/typeck/issue-83693.stderr index 0359b8af93a3..521288c43402 100644 --- a/tests/ui/typeck/issue-83693.stderr +++ b/tests/ui/typeck/issue-83693.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `F` in this scope +error[E0425]: cannot find type `F` in this scope --> $DIR/issue-83693.rs:6:6 | LL | impl F { @@ -8,13 +8,13 @@ LL | impl F { | = note: similarly named trait `Fn` defined here -error[E0412]: cannot find type `TestResult` in this scope +error[E0425]: cannot find type `TestResult` in this scope --> $DIR/issue-83693.rs:9:22 | LL | ::call | ^^^^^^^^^^ not found in this scope -error[E0412]: cannot find type `x` in this scope +error[E0425]: cannot find type `x` in this scope --> $DIR/issue-83693.rs:16:6 | LL | ::call @@ -34,5 +34,5 @@ LL | ::call error: aborting due to 5 previous errors -Some errors have detailed explanations: E0229, E0412. +Some errors have detailed explanations: E0229, E0425. For more information about an error, try `rustc --explain E0229`. diff --git a/tests/ui/typeck/issue-88844.rs b/tests/ui/typeck/issue-88844.rs index 116c75aabdbd..35d110b50262 100644 --- a/tests/ui/typeck/issue-88844.rs +++ b/tests/ui/typeck/issue-88844.rs @@ -4,7 +4,7 @@ struct Struct { value: i32 } //~^ NOTE: similarly named struct `Struct` defined here impl Stuct { -//~^ ERROR: cannot find type `Stuct` in this scope [E0412] +//~^ ERROR: cannot find type `Stuct` in this scope [E0425] //~| HELP: a struct with a similar name exists fn new() -> Self { Self { value: 42 } diff --git a/tests/ui/typeck/issue-88844.stderr b/tests/ui/typeck/issue-88844.stderr index 68473f65dcf5..a5f4310c34dd 100644 --- a/tests/ui/typeck/issue-88844.stderr +++ b/tests/ui/typeck/issue-88844.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Stuct` in this scope +error[E0425]: cannot find type `Stuct` in this scope --> $DIR/issue-88844.rs:6:6 | LL | struct Struct { value: i32 } @@ -9,4 +9,4 @@ LL | impl Stuct { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/typeck/issue-90319.rs b/tests/ui/typeck/issue-90319.rs index 57e6ac7cf34f..64b3a2715503 100644 --- a/tests/ui/typeck/issue-90319.rs +++ b/tests/ui/typeck/issue-90319.rs @@ -11,7 +11,7 @@ fn get() -> T { } fn main() { - let thing = get::();//~ERROR cannot find type `Thing` in this scope [E0412] + let thing = get::();//~ERROR cannot find type `Thing` in this scope [E0425] let wrapper = Wrapper(thing); Trait::method(&wrapper); } diff --git a/tests/ui/typeck/issue-90319.stderr b/tests/ui/typeck/issue-90319.stderr index fa18056e802d..4f427cbb3b00 100644 --- a/tests/ui/typeck/issue-90319.stderr +++ b/tests/ui/typeck/issue-90319.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Thing` in this scope +error[E0425]: cannot find type `Thing` in this scope --> $DIR/issue-90319.rs:14:23 | LL | let thing = get::(); @@ -6,4 +6,4 @@ LL | let thing = get::(); error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/typeck/issue-91267.rs b/tests/ui/typeck/issue-91267.rs index 1bffa09e6436..22198532b0c9 100644 --- a/tests/ui/typeck/issue-91267.rs +++ b/tests/ui/typeck/issue-91267.rs @@ -2,7 +2,7 @@ fn main() { type_ascribe!(0, u8=e>) - //~^ ERROR: cannot find type `e` in this scope [E0412] + //~^ ERROR: cannot find type `e` in this scope [E0425] //~| ERROR: associated item constraints are not allowed here [E0229] //~| ERROR: mismatched types [E0308] } diff --git a/tests/ui/typeck/issue-91267.stderr b/tests/ui/typeck/issue-91267.stderr index d16b1997e9f7..0c186f546df2 100644 --- a/tests/ui/typeck/issue-91267.stderr +++ b/tests/ui/typeck/issue-91267.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `e` in this scope +error[E0425]: cannot find type `e` in this scope --> $DIR/issue-91267.rs:4:30 | LL | type_ascribe!(0, u8=e>) @@ -22,5 +22,5 @@ LL | type_ascribe!(0, u8=e>) error: aborting due to 3 previous errors -Some errors have detailed explanations: E0229, E0308, E0412. +Some errors have detailed explanations: E0229, E0308, E0425. For more information about an error, try `rustc --explain E0229`. diff --git a/tests/ui/typeck/nonexistent-field-not-ambiguous.stderr b/tests/ui/typeck/nonexistent-field-not-ambiguous.stderr index 82207a731b96..3d876b022897 100644 --- a/tests/ui/typeck/nonexistent-field-not-ambiguous.stderr +++ b/tests/ui/typeck/nonexistent-field-not-ambiguous.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `MissingType` in this scope +error[E0425]: cannot find type `MissingType` in this scope --> $DIR/nonexistent-field-not-ambiguous.rs:2:10 | LL | val: MissingType, @@ -6,4 +6,4 @@ LL | val: MissingType, error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.rs b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.rs index 5aa2bd7fddeb..28aefdd8d3e4 100644 --- a/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.rs +++ b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.rs @@ -26,7 +26,7 @@ macro_rules! eq_local { pub fn foo(mut iter: I, value: &I::Item) where - Item: Eq + Debug, //~ ERROR cannot find type `Item` in this scope [E0412] + Item: Eq + Debug, //~ ERROR cannot find type `Item` in this scope [E0425] { ext::eq!(assert iter.next(), Some(value)); //~ ERROR mismatched types [E0308] eq_local!(assert iter.next(), Some(value)); diff --git a/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.stderr b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.stderr index 96a3bc65dfdc..d74372c665a4 100644 --- a/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.stderr +++ b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Item` in this scope +error[E0425]: cannot find type `Item` in this scope --> $DIR/sugg-swap-equality-in-macro-issue-139050.rs:29:5 | LL | Item: Eq + Debug, @@ -35,5 +35,5 @@ LL + if !(*right_val == *left_val) { error: aborting due to 3 previous errors -Some errors have detailed explanations: E0308, E0412. +Some errors have detailed explanations: E0308, E0425. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/union/unresolved-field-isnt-copy.stderr b/tests/ui/union/unresolved-field-isnt-copy.stderr index ee5d1e37b141..5ac9e0e9162a 100644 --- a/tests/ui/union/unresolved-field-isnt-copy.stderr +++ b/tests/ui/union/unresolved-field-isnt-copy.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/unresolved-field-isnt-copy.rs:4:15 | LL | x: *const Missing, @@ -6,4 +6,4 @@ LL | x: *const Missing, error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/variance/type-resolve-error-two-structs-deep.stderr b/tests/ui/variance/type-resolve-error-two-structs-deep.stderr index 3458d924bb15..2b4f3b5b1115 100644 --- a/tests/ui/variance/type-resolve-error-two-structs-deep.stderr +++ b/tests/ui/variance/type-resolve-error-two-structs-deep.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/type-resolve-error-two-structs-deep.rs:5:14 | LL | missing: Missing<'a>, @@ -6,4 +6,4 @@ LL | missing: Missing<'a>, error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/wf/issue-110157.stderr b/tests/ui/wf/issue-110157.stderr index e750ea47d515..eb496628c5e0 100644 --- a/tests/ui/wf/issue-110157.stderr +++ b/tests/ui/wf/issue-110157.stderr @@ -1,10 +1,10 @@ -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/issue-110157.rs:6:12 | LL | F: Fn(&Missing) -> Result, | ^^^^^^^ not found in this scope -error[E0412]: cannot find type `Missing` in this scope +error[E0425]: cannot find type `Missing` in this scope --> $DIR/issue-110157.rs:8:24 | LL | I: Iterator, @@ -26,5 +26,5 @@ LL | | I: Iterator, error: aborting due to 3 previous errors -Some errors have detailed explanations: E0046, E0412. +Some errors have detailed explanations: E0046, E0425. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/where-clauses/ignore-err-clauses.stderr b/tests/ui/where-clauses/ignore-err-clauses.stderr index 9c76c1c6a048..222b162cd482 100644 --- a/tests/ui/where-clauses/ignore-err-clauses.stderr +++ b/tests/ui/where-clauses/ignore-err-clauses.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `UUU` in this scope +error[E0425]: cannot find type `UUU` in this scope --> $DIR/ignore-err-clauses.rs:6:5 | LL | UUU: Copy, @@ -29,5 +29,5 @@ note: calling this operator moves the left-hand side error: aborting due to 2 previous errors -Some errors have detailed explanations: E0382, E0412. +Some errors have detailed explanations: E0382, E0425. For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/where-clauses/normalization-of-unknown-type.stderr b/tests/ui/where-clauses/normalization-of-unknown-type.stderr index 11b83224352b..100d28ed2deb 100644 --- a/tests/ui/where-clauses/normalization-of-unknown-type.stderr +++ b/tests/ui/where-clauses/normalization-of-unknown-type.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `Foo` in this scope +error[E0425]: cannot find type `Foo` in this scope --> $DIR/normalization-of-unknown-type.rs:24:5 | LL | Foo: Filter, @@ -6,4 +6,4 @@ LL | Foo: Filter, error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0425`. From 9c0cbe98ea1890eb261e63ef1cde58f89ee7df38 Mon Sep 17 00:00:00 2001 From: xonx4l Date: Sat, 8 Nov 2025 00:11:35 +0530 Subject: [PATCH 223/585] Merge E0412 into E0425 --- tests/ui/crashes/ice-6252.stderr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/crashes/ice-6252.stderr b/tests/ui/crashes/ice-6252.stderr index 201a897b2319..b6a2597a44d5 100644 --- a/tests/ui/crashes/ice-6252.stderr +++ b/tests/ui/crashes/ice-6252.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `PhantomData` in this scope +error[E0425]: cannot find type `PhantomData` in this scope --> tests/ui/crashes/ice-6252.rs:9:9 | LL | _n: PhantomData, @@ -9,7 +9,7 @@ help: consider importing this struct LL + use std::marker::PhantomData; | -error[E0412]: cannot find type `VAL` in this scope +error[E0425]: cannot find type `VAL` in this scope --> tests/ui/crashes/ice-6252.rs:12:63 | LL | impl TypeVal for Multiply where N: TypeVal {} @@ -31,5 +31,5 @@ LL | impl TypeVal for Multiply where N: TypeVal {} error: aborting due to 3 previous errors -Some errors have detailed explanations: E0046, E0412. +Some errors have detailed explanations: E0046, E0425. For more information about an error, try `rustc --explain E0046`. From f8ca41755924f992aa760a4dcb7bf79baea9028b Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 2 Dec 2025 00:38:13 +0000 Subject: [PATCH 224/585] reword error for invalid range patterns For half-open ranges, specifies that the upper bound cannot be the minimum. Also specify that this only applies to range patterns and not also expressions. --- compiler/rustc_mir_build/messages.ftl | 6 ++-- compiler/rustc_mir_build/src/errors.rs | 7 +++++ .../rustc_mir_build/src/thir/pattern/mod.rs | 3 ++ tests/ui/error-codes/E0030-teach.rs | 2 +- tests/ui/error-codes/E0030-teach.stderr | 2 +- tests/ui/error-codes/E0030.rs | 2 +- tests/ui/error-codes/E0030.stderr | 2 +- .../half-open-range-pats-thir-lower-empty.rs | 30 +++++++++---------- ...lf-open-range-pats-thir-lower-empty.stderr | 30 +++++++++---------- tests/ui/loop-match/invalid.rs | 2 +- tests/ui/loop-match/invalid.stderr | 2 +- tests/ui/match/match-range-fail-2.rs | 6 ++-- tests/ui/match/match-range-fail-2.stderr | 6 ++-- tests/ui/match/validate-range-endpoints.rs | 2 +- .../ui/match/validate-range-endpoints.stderr | 2 +- 15 files changed, 58 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index f65b99d5f99f..8b0c38dd3b53 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -250,11 +250,11 @@ mir_build_loop_match_unsupported_type = .note = only integers, floats, bool, char, and enums without fields are supported mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper = - lower range bound must be less than or equal to upper + lower bound for range pattern must be less than or equal to upper bound .label = lower bound larger than upper bound .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. -mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper +mir_build_lower_range_bound_must_be_less_than_upper = lower bound for range pattern must be less than upper bound mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html @@ -506,6 +506,8 @@ mir_build_unused_unsafe = unnecessary `unsafe` block mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block +mir_build_upper_range_bound_cannot_be_min = exclusive upper bound for a range bound cannot be the minimum + mir_build_variant_defined_here = not covered mir_build_wrap_suggestion = consider wrapping the function body in an unsafe block diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 3d9753d72da5..64e2bb3207c8 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -776,6 +776,13 @@ pub(crate) struct LowerRangeBoundMustBeLessThanUpper { pub(crate) span: Span, } +#[derive(Diagnostic)] +#[diag(mir_build_upper_range_bound_cannot_be_min, code = E0579)] +pub(crate) struct UpperRangeBoundCannotBeMin { + #[primary_span] + pub(crate) span: Span, +} + #[derive(LintDiagnostic)] #[diag(mir_build_leading_irrefutable_let_patterns)] #[note] diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8531c5f39f84..02e6f8d6ce71 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -273,6 +273,9 @@ fn lower_pattern_range( teach: self.tcx.sess.teach(E0030), }) } + RangeEnd::Excluded if lo_expr.is_none() => { + self.tcx.dcx().emit_err(UpperRangeBoundCannotBeMin { span }) + } RangeEnd::Excluded => { self.tcx.dcx().emit_err(LowerRangeBoundMustBeLessThanUpper { span }) } diff --git a/tests/ui/error-codes/E0030-teach.rs b/tests/ui/error-codes/E0030-teach.rs index e1f887139e3d..56736e69f1b0 100644 --- a/tests/ui/error-codes/E0030-teach.rs +++ b/tests/ui/error-codes/E0030-teach.rs @@ -3,6 +3,6 @@ fn main() { match 5u32 { 1000 ..= 5 => {} - //~^ ERROR lower range bound must be less than or equal to upper + //~^ ERROR lower bound for range pattern must be less than or equal to upper bound } } diff --git a/tests/ui/error-codes/E0030-teach.stderr b/tests/ui/error-codes/E0030-teach.stderr index 36200d2b86af..50c7d1eee1f4 100644 --- a/tests/ui/error-codes/E0030-teach.stderr +++ b/tests/ui/error-codes/E0030-teach.stderr @@ -1,4 +1,4 @@ -error[E0030]: lower range bound must be less than or equal to upper +error[E0030]: lower bound for range pattern must be less than or equal to upper bound --> $DIR/E0030-teach.rs:5:9 | LL | 1000 ..= 5 => {} diff --git a/tests/ui/error-codes/E0030.rs b/tests/ui/error-codes/E0030.rs index 58d856b7c9d2..d861360532b5 100644 --- a/tests/ui/error-codes/E0030.rs +++ b/tests/ui/error-codes/E0030.rs @@ -1,6 +1,6 @@ fn main() { match 5u32 { 1000 ..= 5 => {} - //~^ ERROR lower range bound must be less than or equal to upper + //~^ ERROR lower bound for range pattern must be less than or equal to upper bound } } diff --git a/tests/ui/error-codes/E0030.stderr b/tests/ui/error-codes/E0030.stderr index 4e9378dfe1dc..f5190f5330d7 100644 --- a/tests/ui/error-codes/E0030.stderr +++ b/tests/ui/error-codes/E0030.stderr @@ -1,4 +1,4 @@ -error[E0030]: lower range bound must be less than or equal to upper +error[E0030]: lower bound for range pattern must be less than or equal to upper bound --> $DIR/E0030.rs:3:9 | LL | 1000 ..= 5 => {} diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs index 6a0115de0160..6b7306e86573 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs @@ -9,36 +9,36 @@ macro_rules! m { fn main() { m!(0, ..u8::MIN); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!(0, ..u16::MIN); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!(0, ..u32::MIN); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!(0, ..u64::MIN); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!(0, ..u128::MIN); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!(0, ..i8::MIN); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!(0, ..i16::MIN); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!(0, ..i32::MIN); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!(0, ..i64::MIN); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!(0, ..i128::MIN); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!(0f16, ..f16::NEG_INFINITY); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!(0f32, ..f32::NEG_INFINITY); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!(0f64, ..f64::NEG_INFINITY); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!(0f128, ..f128::NEG_INFINITY); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum m!('a', ..'\u{0}'); - //~^ ERROR lower range bound must be less than upper + //~^ ERROR exclusive upper bound for a range bound cannot be the minimum } diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr index f414a6bfd183..8be3c81876de 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr @@ -1,88 +1,88 @@ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:11:11 | LL | m!(0, ..u8::MIN); | ^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:13:11 | LL | m!(0, ..u16::MIN); | ^^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:15:11 | LL | m!(0, ..u32::MIN); | ^^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:17:11 | LL | m!(0, ..u64::MIN); | ^^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:19:11 | LL | m!(0, ..u128::MIN); | ^^^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:22:11 | LL | m!(0, ..i8::MIN); | ^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:24:11 | LL | m!(0, ..i16::MIN); | ^^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:26:11 | LL | m!(0, ..i32::MIN); | ^^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:28:11 | LL | m!(0, ..i64::MIN); | ^^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:11 | LL | m!(0, ..i128::MIN); | ^^^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:14 | LL | m!(0f16, ..f16::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:35:14 | LL | m!(0f32, ..f32::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:37:14 | LL | m!(0f64, ..f64::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:39:15 | LL | m!(0f128, ..f128::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^^ -error[E0579]: lower range bound must be less than upper +error[E0579]: exclusive upper bound for a range bound cannot be the minimum --> $DIR/half-open-range-pats-thir-lower-empty.rs:42:13 | LL | m!('a', ..'\u{0}'); diff --git a/tests/ui/loop-match/invalid.rs b/tests/ui/loop-match/invalid.rs index 08eaf832f56d..31712485040f 100644 --- a/tests/ui/loop-match/invalid.rs +++ b/tests/ui/loop-match/invalid.rs @@ -202,7 +202,7 @@ fn invalid_range_pattern(state: f32) { break 'blk 2.5; } 4.0..3.0 => { - //~^ ERROR lower range bound must be less than upper + //~^ ERROR lower bound for range pattern must be less than upper bound todo!() } } diff --git a/tests/ui/loop-match/invalid.stderr b/tests/ui/loop-match/invalid.stderr index 9e9796a2ea79..82539ed17430 100644 --- a/tests/ui/loop-match/invalid.stderr +++ b/tests/ui/loop-match/invalid.stderr @@ -121,7 +121,7 @@ LL ~ State::A => State::B, LL ~ State::B | State::C => todo!(), | -error[E0579]: lower range bound must be less than upper +error[E0579]: lower bound for range pattern must be less than upper bound --> $DIR/invalid.rs:204:17 | LL | 4.0..3.0 => { diff --git a/tests/ui/match/match-range-fail-2.rs b/tests/ui/match/match-range-fail-2.rs index 524e84323e7c..7b65ef049e4e 100644 --- a/tests/ui/match/match-range-fail-2.rs +++ b/tests/ui/match/match-range-fail-2.rs @@ -1,19 +1,19 @@ fn main() { match 5 { 6 ..= 1 => { } - //~^ ERROR lower range bound must be less than or equal to upper + //~^ ERROR lower bound for range pattern must be less than or equal to upper bound _ => { } }; match 5 { 0 .. 0 => { } - //~^ ERROR lower range bound must be less than upper + //~^ ERROR lower bound for range pattern must be less than upper bound _ => { } }; match 5u64 { 0xFFFF_FFFF_FFFF_FFFF ..= 1 => { } - //~^ ERROR lower range bound must be less than or equal to upper + //~^ ERROR lower bound for range pattern must be less than or equal to upper bound _ => { } }; } diff --git a/tests/ui/match/match-range-fail-2.stderr b/tests/ui/match/match-range-fail-2.stderr index 8bad2e6e1470..41bb85da9505 100644 --- a/tests/ui/match/match-range-fail-2.stderr +++ b/tests/ui/match/match-range-fail-2.stderr @@ -1,16 +1,16 @@ -error[E0030]: lower range bound must be less than or equal to upper +error[E0030]: lower bound for range pattern must be less than or equal to upper bound --> $DIR/match-range-fail-2.rs:3:9 | LL | 6 ..= 1 => { } | ^^^^^^^ lower bound larger than upper bound -error[E0579]: lower range bound must be less than upper +error[E0579]: lower bound for range pattern must be less than upper bound --> $DIR/match-range-fail-2.rs:9:9 | LL | 0 .. 0 => { } | ^^^^^^ -error[E0030]: lower range bound must be less than or equal to upper +error[E0030]: lower bound for range pattern must be less than or equal to upper bound --> $DIR/match-range-fail-2.rs:15:9 | LL | 0xFFFF_FFFF_FFFF_FFFF ..= 1 => { } diff --git a/tests/ui/match/validate-range-endpoints.rs b/tests/ui/match/validate-range-endpoints.rs index 678cedf016b9..71a54eb374fc 100644 --- a/tests/ui/match/validate-range-endpoints.rs +++ b/tests/ui/match/validate-range-endpoints.rs @@ -15,7 +15,7 @@ fn main() { // There isn't really a way to detect these 1..=TOO_BIG => {} - //~^ ERROR lower range bound must be less than or equal to upper + //~^ ERROR lower bound for range pattern must be less than or equal to upper bound _ => {} } diff --git a/tests/ui/match/validate-range-endpoints.stderr b/tests/ui/match/validate-range-endpoints.stderr index 6a8a81a1cc64..345629ee41a5 100644 --- a/tests/ui/match/validate-range-endpoints.stderr +++ b/tests/ui/match/validate-range-endpoints.stderr @@ -10,7 +10,7 @@ error: literal out of range for `u8` LL | 1..=256 => {} | ^^^ this value does not fit into the type `u8` whose range is `0..=255` -error[E0030]: lower range bound must be less than or equal to upper +error[E0030]: lower bound for range pattern must be less than or equal to upper bound --> $DIR/validate-range-endpoints.rs:17:9 | LL | 1..=TOO_BIG => {} From e778ec5311487f5d6f05dad831d1021d4ad56fc4 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 2 Dec 2025 14:31:07 -0500 Subject: [PATCH 225/585] Update cargo submodule --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 2a7c49606779..bd979347d814 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 2a7c4960677971f88458b0f8b461a866836dff59 +Subproject commit bd979347d814dfe03bba124165dbce9554d0b4d8 From f2af204d17aad5264372218c58dd7d87a6769307 Mon Sep 17 00:00:00 2001 From: yanglsh Date: Fri, 10 Oct 2025 00:16:12 +0800 Subject: [PATCH 226/585] fix: `zero_repeat_side_effects` misses curlies --- clippy_lints/src/zero_repeat_side_effects.rs | 72 ++++++++++++++++---- tests/ui/zero_repeat_side_effects.fixed | 32 ++++++++- tests/ui/zero_repeat_side_effects.rs | 26 ++++++- tests/ui/zero_repeat_side_effects.stderr | 52 ++++++++++---- 4 files changed, 151 insertions(+), 31 deletions(-) diff --git a/clippy_lints/src/zero_repeat_side_effects.rs b/clippy_lints/src/zero_repeat_side_effects.rs index a8351690068d..95085161c09c 100644 --- a/clippy_lints/src/zero_repeat_side_effects.rs +++ b/clippy_lints/src/zero_repeat_side_effects.rs @@ -4,10 +4,11 @@ use rustc_ast::LitKind; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; -use rustc_hir::{ConstArgKind, ExprKind, Node}; +use rustc_hir::{ConstArgKind, Expr, ExprKind, LetStmt, LocalSource, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::IsSuggestable; +use rustc_middle::ty::{IsSuggestable, Ty}; use rustc_session::declare_lint_pass; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -44,7 +45,7 @@ declare_lint_pass!(ZeroRepeatSideEffects => [ZERO_REPEAT_SIDE_EFFECTS]); impl LateLintPass<'_> for ZeroRepeatSideEffects { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &rustc_hir::Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let Some(args) = VecArgs::hir(cx, expr) && let VecArgs::Repeat(inner_expr, len) = args && let ExprKind::Lit(l) = len.kind @@ -69,7 +70,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &rustc_hir::Expr<'_>) { } } -fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr: &'_ rustc_hir::Expr<'_>, is_vec: bool) { +fn inner_check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, inner_expr: &'_ Expr<'_>, is_vec: bool) { // check if expr is a call or has a call inside it if inner_expr.can_have_side_effects() { let parent_hir_node = cx.tcx.parent_hir_node(expr.hir_id); @@ -81,19 +82,22 @@ fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr: let vec = if is_vec { "vec!" } else { "" }; let (span, sugg) = match parent_hir_node { - Node::LetStmt(l) => ( - l.span, - format!( - "{inner_expr};\n{indent}let {var_name}: {return_type} = {vec}[];", - var_name = snippet(cx, l.pat.span.source_callsite(), "..") - ), - ), + Node::LetStmt(l) + if matches!(l.source, LocalSource::AssignDesugar) + && let mut parent_iter = cx.tcx.hir_parent_iter(l.hir_id) + && let Some((_, Node::Stmt(_))) = parent_iter.next() + && let Some((_, Node::Block(_))) = parent_iter.next() + && let Some((_, Node::Expr(x))) = parent_iter.next() => + { + ( + x.span, + assign_expr_suggestion(cx, x, l.pat.span, &inner_expr, return_type, vec), + ) + }, + Node::LetStmt(l) => (l.span, let_stmt_suggestion(cx, l, &inner_expr, return_type, vec)), Node::Expr(x) if let ExprKind::Assign(l, _, _) = x.kind => ( x.span, - format!( - "{inner_expr};\n{indent}{var_name} = {vec}[] as {return_type}", - var_name = snippet(cx, l.span.source_callsite(), "..") - ), + assign_expr_suggestion(cx, x, l.span, &inner_expr, return_type, vec), ), // NOTE: don't use the stmt span to avoid touching the trailing semicolon Node::Stmt(_) => (expr.span, format!("{inner_expr};\n{indent}{vec}[] as {return_type}")), @@ -131,3 +135,41 @@ fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr: ); } } + +fn let_stmt_suggestion( + cx: &LateContext<'_>, + let_stmt: &LetStmt<'_>, + inner_expr: &str, + return_type: Ty<'_>, + vec_str: &str, +) -> String { + let indent = snippet_indent(cx, let_stmt.span).unwrap_or_default(); + format!( + "{inner_expr};\n{}let {var_name}: {return_type} = {vec_str}[];", + indent, + var_name = snippet(cx, let_stmt.pat.span.source_callsite(), "..") + ) +} + +fn assign_expr_suggestion( + cx: &LateContext<'_>, + outer_expr: &Expr<'_>, + assign_expr_span: Span, + inner_expr: &str, + return_type: Ty<'_>, + vec_str: &str, +) -> String { + let mut parent_hir_node = cx.tcx.parent_hir_node(outer_expr.hir_id); + if let Node::Stmt(stmt) = parent_hir_node { + parent_hir_node = cx.tcx.parent_hir_node(stmt.hir_id); + } + let needs_curly = !matches!(parent_hir_node, Node::Block(_)); + + let indent = snippet_indent(cx, outer_expr.span).unwrap_or_default(); + let var_name = snippet(cx, assign_expr_span.source_callsite(), ".."); + if needs_curly { + format!("{{\n {indent}{inner_expr};\n {indent}{var_name} = {vec_str}[] as {return_type}\n{indent}}}",) + } else { + format!("{inner_expr};\n{indent}{var_name} = {vec_str}[] as {return_type}") + } +} diff --git a/tests/ui/zero_repeat_side_effects.fixed b/tests/ui/zero_repeat_side_effects.fixed index b5fca36f3f08..4bdff6fd0f6c 100644 --- a/tests/ui/zero_repeat_side_effects.fixed +++ b/tests/ui/zero_repeat_side_effects.fixed @@ -1,6 +1,11 @@ #![warn(clippy::zero_repeat_side_effects)] -#![expect(clippy::unnecessary_operation, clippy::useless_vec, clippy::needless_late_init)] -#![allow(clippy::no_effect)] // only fires _after_ the fix +#![allow( + clippy::unnecessary_operation, + clippy::useless_vec, + clippy::needless_late_init, + clippy::single_match, + clippy::no_effect // only fires _after_ the fix +)] fn f() -> i32 { println!("side effect"); @@ -119,3 +124,26 @@ fn issue_14681() { }); //~^ zero_repeat_side_effects } + +fn issue_15824() { + fn f() {} + + match 0 { + 0 => { + f(); + _ = [] as [(); 0] + }, + //~^ zero_repeat_side_effects + _ => {}, + } + + let mut a = [(); 0]; + match 0 { + 0 => { + f(); + a = [] as [(); 0] + }, + //~^ zero_repeat_side_effects + _ => {}, + } +} diff --git a/tests/ui/zero_repeat_side_effects.rs b/tests/ui/zero_repeat_side_effects.rs index ea043d21638c..a1454d724c87 100644 --- a/tests/ui/zero_repeat_side_effects.rs +++ b/tests/ui/zero_repeat_side_effects.rs @@ -1,6 +1,11 @@ #![warn(clippy::zero_repeat_side_effects)] -#![expect(clippy::unnecessary_operation, clippy::useless_vec, clippy::needless_late_init)] -#![allow(clippy::no_effect)] // only fires _after_ the fix +#![allow( + clippy::unnecessary_operation, + clippy::useless_vec, + clippy::needless_late_init, + clippy::single_match, + clippy::no_effect // only fires _after_ the fix +)] fn f() -> i32 { println!("side effect"); @@ -102,3 +107,20 @@ fn foo(_s: &[Option]) {} foo(&[Some(Some(S::new())); 0]); //~^ zero_repeat_side_effects } + +fn issue_15824() { + fn f() {} + + match 0 { + 0 => _ = [f(); 0], + //~^ zero_repeat_side_effects + _ => {}, + } + + let mut a = [(); 0]; + match 0 { + 0 => a = [f(); 0], + //~^ zero_repeat_side_effects + _ => {}, + } +} diff --git a/tests/ui/zero_repeat_side_effects.stderr b/tests/ui/zero_repeat_side_effects.stderr index 49e850d03534..f376a1501b00 100644 --- a/tests/ui/zero_repeat_side_effects.stderr +++ b/tests/ui/zero_repeat_side_effects.stderr @@ -1,5 +1,5 @@ error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:17:5 + --> tests/ui/zero_repeat_side_effects.rs:22:5 | LL | let a = [f(); 0]; | ^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + let a: [i32; 0] = []; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:20:5 + --> tests/ui/zero_repeat_side_effects.rs:25:5 | LL | b = [f(); 0]; | ^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL ~ b = [] as [i32; 0]; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:25:5 + --> tests/ui/zero_repeat_side_effects.rs:30:5 | LL | let c = vec![f(); 0]; | ^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + let c: std::vec::Vec = vec![]; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:28:5 + --> tests/ui/zero_repeat_side_effects.rs:33:5 | LL | d = vec![f(); 0]; | ^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL ~ d = vec![] as std::vec::Vec; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:32:5 + --> tests/ui/zero_repeat_side_effects.rs:37:5 | LL | let e = [println!("side effect"); 0]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + let e: [(); 0] = []; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:36:5 + --> tests/ui/zero_repeat_side_effects.rs:41:5 | LL | let g = [{ f() }; 0]; | ^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + let g: [i32; 0] = []; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:40:10 + --> tests/ui/zero_repeat_side_effects.rs:45:10 | LL | drop(vec![f(); 0]); | ^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL ~ }); | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:44:5 + --> tests/ui/zero_repeat_side_effects.rs:49:5 | LL | vec![f(); 0]; | ^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL ~ vec![] as std::vec::Vec; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:46:5 + --> tests/ui/zero_repeat_side_effects.rs:51:5 | LL | [f(); 0]; | ^^^^^^^^ @@ -111,7 +111,7 @@ LL ~ [] as [i32; 0]; | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:100:10 + --> tests/ui/zero_repeat_side_effects.rs:105:10 | LL | foo(&[Some(f()); 0]); | ^^^^^^^^^^^^^^ @@ -125,7 +125,7 @@ LL ~ }); | error: expression with side effects as the initial value in a zero-sized array initializer - --> tests/ui/zero_repeat_side_effects.rs:102:10 + --> tests/ui/zero_repeat_side_effects.rs:107:10 | LL | foo(&[Some(Some(S::new())); 0]); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,5 +138,33 @@ LL + [] as [std::option::Option>; 0] LL ~ }); | -error: aborting due to 11 previous errors +error: expression with side effects as the initial value in a zero-sized array initializer + --> tests/ui/zero_repeat_side_effects.rs:115:14 + | +LL | 0 => _ = [f(); 0], + | ^^^^^^^^^^^^ + | +help: consider performing the side effect separately + | +LL ~ 0 => { +LL + f(); +LL + _ = [] as [(); 0] +LL ~ }, + | + +error: expression with side effects as the initial value in a zero-sized array initializer + --> tests/ui/zero_repeat_side_effects.rs:122:14 + | +LL | 0 => a = [f(); 0], + | ^^^^^^^^^^^^ + | +help: consider performing the side effect separately + | +LL ~ 0 => { +LL + f(); +LL + a = [] as [(); 0] +LL ~ }, + | + +error: aborting due to 13 previous errors From bb239c290c1283d576fde8d87b2e514cf2dec9b9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 1 Dec 2025 21:51:44 -0500 Subject: [PATCH 227/585] library: Rename `IterRange*` to `Range*Iter` There is a weak convention in the ecosystem that `IterFoos` is an iterator yielding items of type `Foo` (e.g. `bitflags` `IterNames`, `hashbrown` `IterBuckets`), while `FooIter` is an iterator over `Foo` from an `.iter()` or `.into_iter()` method (e.g. `memchr` `OneIter`, `regex` `SetMatchesIter`). Rename `IterRange`, `IterRangeInclusive`, and `IterRangeFrom` to `RangeIter`, `RangeInclusiveIter`, and `RangeInclusiveIter` to match this. Tracking issue: RUST-125687 (`new_range_api`) --- library/core/src/range.rs | 8 +-- library/core/src/range/iter.rs | 54 +++++++++---------- ...ks.rs => fromrangeiter-overflow-checks.rs} | 4 +- .../{iterrangefrom.rs => fromrangeiter.rs} | 0 tests/ui/new-range/enabled.rs | 6 +-- 5 files changed, 36 insertions(+), 36 deletions(-) rename tests/codegen-llvm/{iterrangefrom-overflow-checks.rs => fromrangeiter-overflow-checks.rs} (90%) rename tests/ui/iterators/{iterrangefrom.rs => fromrangeiter.rs} (100%) diff --git a/library/core/src/range.rs b/library/core/src/range.rs index 2df520d35b39..4b87d426bda7 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -26,7 +26,7 @@ use Bound::{Excluded, Included, Unbounded}; #[doc(inline)] -pub use iter::{IterRange, IterRangeFrom, IterRangeInclusive}; +pub use iter::{RangeFromIter, RangeInclusiveIter, RangeIter}; #[doc(inline)] pub use crate::iter::Step; @@ -89,7 +89,7 @@ impl Range { /// ``` #[unstable(feature = "new_range_api", issue = "125687")] #[inline] - pub fn iter(&self) -> IterRange { + pub fn iter(&self) -> RangeIter { self.clone().into_iter() } } @@ -340,7 +340,7 @@ impl RangeInclusive { /// ``` #[unstable(feature = "new_range_api", issue = "125687")] #[inline] - pub fn iter(&self) -> IterRangeInclusive { + pub fn iter(&self) -> RangeInclusiveIter { self.clone().into_iter() } } @@ -477,7 +477,7 @@ impl RangeFrom { /// ``` #[unstable(feature = "new_range_api", issue = "125687")] #[inline] - pub fn iter(&self) -> IterRangeFrom { + pub fn iter(&self) -> RangeFromIter { self.clone().into_iter() } } diff --git a/library/core/src/range/iter.rs b/library/core/src/range/iter.rs index 9a8824baefe4..6fe5d9b34361 100644 --- a/library/core/src/range/iter.rs +++ b/library/core/src/range/iter.rs @@ -8,9 +8,9 @@ /// By-value [`Range`] iterator. #[unstable(feature = "new_range_api", issue = "125687")] #[derive(Debug, Clone)] -pub struct IterRange(legacy::Range); +pub struct RangeIter(legacy::Range); -impl IterRange { +impl RangeIter { /// Returns the remainder of the range being iterated over. pub fn remainder(self) -> Range { Range { start: self.0.start, end: self.0.end } @@ -23,11 +23,11 @@ macro_rules! unsafe_range_trusted_random_access_impl { ($($t:ty)*) => ($( #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] - unsafe impl TrustedRandomAccess for IterRange<$t> {} + unsafe impl TrustedRandomAccess for RangeIter<$t> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] - unsafe impl TrustedRandomAccessNoCoerce for IterRange<$t> { + unsafe impl TrustedRandomAccessNoCoerce for RangeIter<$t> { const MAY_HAVE_SIDE_EFFECT: bool = false; } )*) @@ -50,7 +50,7 @@ unsafe impl TrustedRandomAccessNoCoerce for IterRange<$t> { } #[unstable(feature = "new_range_api", issue = "125687")] -impl Iterator for IterRange { +impl Iterator for RangeIter { type Item = A; #[inline] @@ -118,7 +118,7 @@ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item } #[unstable(feature = "new_range_api", issue = "125687")] -impl DoubleEndedIterator for IterRange { +impl DoubleEndedIterator for RangeIter { #[inline] fn next_back(&mut self) -> Option { self.0.next_back() @@ -136,27 +136,27 @@ fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { } #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for IterRange {} +unsafe impl TrustedLen for RangeIter {} #[unstable(feature = "new_range_api", issue = "125687")] -impl FusedIterator for IterRange {} +impl FusedIterator for RangeIter {} #[unstable(feature = "new_range_api", issue = "125687")] impl IntoIterator for Range { type Item = A; - type IntoIter = IterRange; + type IntoIter = RangeIter; fn into_iter(self) -> Self::IntoIter { - IterRange(self.into()) + RangeIter(self.into()) } } /// By-value [`RangeInclusive`] iterator. #[unstable(feature = "new_range_api", issue = "125687")] #[derive(Debug, Clone)] -pub struct IterRangeInclusive(legacy::RangeInclusive); +pub struct RangeInclusiveIter(legacy::RangeInclusive); -impl IterRangeInclusive { +impl RangeInclusiveIter { /// Returns the remainder of the range being iterated over. /// /// If the iterator is exhausted or empty, returns `None`. @@ -170,7 +170,7 @@ pub fn remainder(self) -> Option> { } #[unstable(feature = "new_range_api", issue = "125687")] -impl Iterator for IterRangeInclusive { +impl Iterator for RangeInclusiveIter { type Item = A; #[inline] @@ -226,7 +226,7 @@ fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { } #[unstable(feature = "new_range_api", issue = "125687")] -impl DoubleEndedIterator for IterRangeInclusive { +impl DoubleEndedIterator for RangeInclusiveIter { #[inline] fn next_back(&mut self) -> Option { self.0.next_back() @@ -244,18 +244,18 @@ fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { } #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for IterRangeInclusive {} +unsafe impl TrustedLen for RangeInclusiveIter {} #[unstable(feature = "new_range_api", issue = "125687")] -impl FusedIterator for IterRangeInclusive {} +impl FusedIterator for RangeInclusiveIter {} #[unstable(feature = "new_range_api", issue = "125687")] impl IntoIterator for RangeInclusive { type Item = A; - type IntoIter = IterRangeInclusive; + type IntoIter = RangeInclusiveIter; fn into_iter(self) -> Self::IntoIter { - IterRangeInclusive(self.into()) + RangeInclusiveIter(self.into()) } } @@ -270,14 +270,14 @@ fn into_iter(self) -> Self::IntoIter { macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[unstable(feature = "new_range_api", issue = "125687")] - impl ExactSizeIterator for IterRange<$t> { } + impl ExactSizeIterator for RangeIter<$t> { } )*) } macro_rules! range_incl_exact_iter_impl { ($($t:ty)*) => ($( #[unstable(feature = "new_range_api", issue = "125687")] - impl ExactSizeIterator for IterRangeInclusive<$t> { } + impl ExactSizeIterator for RangeInclusiveIter<$t> { } )*) } @@ -294,14 +294,14 @@ impl ExactSizeIterator for IterRangeInclusive<$t> { } /// By-value [`RangeFrom`] iterator. #[unstable(feature = "new_range_api", issue = "125687")] #[derive(Debug, Clone)] -pub struct IterRangeFrom { +pub struct RangeFromIter { start: A, /// Whether the first element of the iterator has yielded. /// Only used when overflow checks are enabled. first: bool, } -impl IterRangeFrom { +impl RangeFromIter { /// Returns the remainder of the range being iterated over. #[inline] #[rustc_inherit_overflow_checks] @@ -317,7 +317,7 @@ pub fn remainder(self) -> RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -impl Iterator for IterRangeFrom { +impl Iterator for RangeFromIter { type Item = A; #[inline] @@ -366,17 +366,17 @@ fn nth(&mut self, n: usize) -> Option { } #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for IterRangeFrom {} +unsafe impl TrustedLen for RangeFromIter {} #[unstable(feature = "new_range_api", issue = "125687")] -impl FusedIterator for IterRangeFrom {} +impl FusedIterator for RangeFromIter {} #[unstable(feature = "new_range_api", issue = "125687")] impl IntoIterator for RangeFrom { type Item = A; - type IntoIter = IterRangeFrom; + type IntoIter = RangeFromIter; fn into_iter(self) -> Self::IntoIter { - IterRangeFrom { start: self.start, first: true } + RangeFromIter { start: self.start, first: true } } } diff --git a/tests/codegen-llvm/iterrangefrom-overflow-checks.rs b/tests/codegen-llvm/fromrangeiter-overflow-checks.rs similarity index 90% rename from tests/codegen-llvm/iterrangefrom-overflow-checks.rs rename to tests/codegen-llvm/fromrangeiter-overflow-checks.rs index 88ff5a8508c8..4d27f118ddd3 100644 --- a/tests/codegen-llvm/iterrangefrom-overflow-checks.rs +++ b/tests/codegen-llvm/fromrangeiter-overflow-checks.rs @@ -11,11 +11,11 @@ #![crate_type = "lib"] #![feature(new_range_api)] -use std::range::{IterRangeFrom, RangeFrom}; +use std::range::{RangeFrom, RangeFromIter}; // CHECK-LABEL: @iterrangefrom_remainder( #[no_mangle] -pub unsafe fn iterrangefrom_remainder(x: IterRangeFrom) -> RangeFrom { +pub unsafe fn iterrangefrom_remainder(x: RangeFromIter) -> RangeFrom { // DEBUG: i32 noundef %x // NOCHECKS: i32 noundef returned %x // DEBUG: br i1 diff --git a/tests/ui/iterators/iterrangefrom.rs b/tests/ui/iterators/fromrangeiter.rs similarity index 100% rename from tests/ui/iterators/iterrangefrom.rs rename to tests/ui/iterators/fromrangeiter.rs diff --git a/tests/ui/new-range/enabled.rs b/tests/ui/new-range/enabled.rs index 5ddbba492e76..140e3b648709 100644 --- a/tests/ui/new-range/enabled.rs +++ b/tests/ui/new-range/enabled.rs @@ -17,8 +17,8 @@ fn main() { let c: core::range::RangeInclusive = 4..=5; let d: core::range::RangeToInclusive = ..=3; - let _: core::range::IterRangeFrom = a.into_iter(); - let _: core::range::IterRange = b.into_iter(); - let _: core::range::IterRangeInclusive = c.into_iter(); + let _: core::range::RangeFromIter = a.into_iter(); + let _: core::range::RangeIter = b.into_iter(); + let _: core::range::RangeInclusiveIter = c.into_iter(); // RangeToInclusive has no Iterator implementation } From e7734099d058ebf5ce89f8b5faeba65faf9942cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Nov 2025 11:59:43 +0100 Subject: [PATCH 228/585] float::maximum/minimum: make docs more streamlined --- library/core/src/num/f128.rs | 36 ++++++++++++++++++------------------ library/core/src/num/f16.rs | 36 ++++++++++++++++++------------------ library/core/src/num/f32.rs | 36 ++++++++++++++++++------------------ library/core/src/num/f64.rs | 36 ++++++++++++++++++------------------ 4 files changed, 72 insertions(+), 72 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index bfe3a501f453..3832d7bb2c39 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -750,8 +750,15 @@ pub const fn min(self, other: f128) -> f128 { /// Returns the maximum of the two numbers, propagating NaN. /// - /// This returns NaN when *either* argument is NaN, as opposed to - /// [`f128::max`] which only returns NaN when *both* arguments are NaN. + /// If at least one of the arguments is NaN, the return value is NaN, with the bit pattern + /// picked using the usual [rules for arithmetic operations](f32#nan-bit-patterns). Furthermore, + /// `-0.0` is considered to be less than `+0.0`, making this function fully deterministic for + /// non-NaN inputs. + /// + /// This is in contrast to [`f128::max`] which only returns NaN when *both* arguments are NaN, + /// and which does not reliably order `-0.0` and `+0.0`. + /// + /// This follows the IEEE 754-2019 semantics for `maximum`. /// /// ``` /// #![feature(f128)] @@ -766,13 +773,6 @@ pub const fn min(self, other: f128) -> f128 { /// assert!(x.maximum(f128::NAN).is_nan()); /// # } /// ``` - /// - /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater - /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. - /// Note that this follows the IEEE 754-2019 semantics for `maximum`. - /// - /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN - /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info. #[inline] #[unstable(feature = "f128", issue = "116909")] // #[unstable(feature = "float_minimum_maximum", issue = "91079")] @@ -783,8 +783,15 @@ pub const fn maximum(self, other: f128) -> f128 { /// Returns the minimum of the two numbers, propagating NaN. /// - /// This returns NaN when *either* argument is NaN, as opposed to - /// [`f128::min`] which only returns NaN when *both* arguments are NaN. + /// If at least one of the arguments is NaN, the return value is NaN, with the bit pattern + /// picked using the usual [rules for arithmetic operations](f32#nan-bit-patterns). Furthermore, + /// `-0.0` is considered to be less than `+0.0`, making this function fully deterministic for + /// non-NaN inputs. + /// + /// This is in contrast to [`f128::min`] which only returns NaN when *both* arguments are NaN, + /// and which does not reliably order `-0.0` and `+0.0`. + /// + /// This follows the IEEE 754-2019 semantics for `minimum`. /// /// ``` /// #![feature(f128)] @@ -799,13 +806,6 @@ pub const fn maximum(self, other: f128) -> f128 { /// assert!(x.minimum(f128::NAN).is_nan()); /// # } /// ``` - /// - /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser - /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. - /// Note that this follows the IEEE 754-2019 semantics for `minimum`. - /// - /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN - /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info. #[inline] #[unstable(feature = "f128", issue = "116909")] // #[unstable(feature = "float_minimum_maximum", issue = "91079")] diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index d3a12e94c800..a1b284620cbc 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -741,8 +741,15 @@ pub const fn min(self, other: f16) -> f16 { /// Returns the maximum of the two numbers, propagating NaN. /// - /// This returns NaN when *either* argument is NaN, as opposed to - /// [`f16::max`] which only returns NaN when *both* arguments are NaN. + /// If at least one of the arguments is NaN, the return value is NaN, with the bit pattern + /// picked using the usual [rules for arithmetic operations](f32#nan-bit-patterns). Furthermore, + /// `-0.0` is considered to be less than `+0.0`, making this function fully deterministic for + /// non-NaN inputs. + /// + /// This is in contrast to [`f16::max`] which only returns NaN when *both* arguments are NaN, + /// and which does not reliably order `-0.0` and `+0.0`. + /// + /// This follows the IEEE 754-2019 semantics for `maximum`. /// /// ``` /// #![feature(f16)] @@ -756,13 +763,6 @@ pub const fn min(self, other: f16) -> f16 { /// assert!(x.maximum(f16::NAN).is_nan()); /// # } /// ``` - /// - /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater - /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. - /// Note that this follows the IEEE 754-2019 semantics for `maximum`. - /// - /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN - /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info. #[inline] #[unstable(feature = "f16", issue = "116909")] // #[unstable(feature = "float_minimum_maximum", issue = "91079")] @@ -773,8 +773,15 @@ pub const fn maximum(self, other: f16) -> f16 { /// Returns the minimum of the two numbers, propagating NaN. /// - /// This returns NaN when *either* argument is NaN, as opposed to - /// [`f16::min`] which only returns NaN when *both* arguments are NaN. + /// If at least one of the arguments is NaN, the return value is NaN, with the bit pattern + /// picked using the usual [rules for arithmetic operations](f32#nan-bit-patterns). Furthermore, + /// `-0.0` is considered to be less than `+0.0`, making this function fully deterministic for + /// non-NaN inputs. + /// + /// This is in contrast to [`f16::min`] which only returns NaN when *both* arguments are NaN, + /// and which does not reliably order `-0.0` and `+0.0`. + /// + /// This follows the IEEE 754-2019 semantics for `minimum`. /// /// ``` /// #![feature(f16)] @@ -788,13 +795,6 @@ pub const fn maximum(self, other: f16) -> f16 { /// assert!(x.minimum(f16::NAN).is_nan()); /// # } /// ``` - /// - /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser - /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. - /// Note that this follows the IEEE 754-2019 semantics for `minimum`. - /// - /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN - /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info. #[inline] #[unstable(feature = "f16", issue = "116909")] // #[unstable(feature = "float_minimum_maximum", issue = "91079")] diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 7e6a757e5e29..b6ec99436956 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -943,8 +943,15 @@ pub const fn min(self, other: f32) -> f32 { /// Returns the maximum of the two numbers, propagating NaN. /// - /// This returns NaN when *either* argument is NaN, as opposed to - /// [`f32::max`] which only returns NaN when *both* arguments are NaN. + /// If at least one of the arguments is NaN, the return value is NaN, with the bit pattern + /// picked using the usual [rules for arithmetic operations](f32#nan-bit-patterns). Furthermore, + /// `-0.0` is considered to be less than `+0.0`, making this function fully deterministic for + /// non-NaN inputs. + /// + /// This is in contrast to [`f32::max`] which only returns NaN when *both* arguments are NaN, + /// and which does not reliably order `-0.0` and `+0.0`. + /// + /// This follows the IEEE 754-2019 semantics for `maximum`. /// /// ``` /// #![feature(float_minimum_maximum)] @@ -954,13 +961,6 @@ pub const fn min(self, other: f32) -> f32 { /// assert_eq!(x.maximum(y), y); /// assert!(x.maximum(f32::NAN).is_nan()); /// ``` - /// - /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater - /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. - /// Note that this follows the IEEE 754-2019 semantics for `maximum`. - /// - /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN - /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info. #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] @@ -970,8 +970,15 @@ pub const fn maximum(self, other: f32) -> f32 { /// Returns the minimum of the two numbers, propagating NaN. /// - /// This returns NaN when *either* argument is NaN, as opposed to - /// [`f32::min`] which only returns NaN when *both* arguments are NaN. + /// If at least one of the arguments is NaN, the return value is NaN, with the bit pattern + /// picked using the usual [rules for arithmetic operations](f32#nan-bit-patterns). Furthermore, + /// `-0.0` is considered to be less than `+0.0`, making this function fully deterministic for + /// non-NaN inputs. + /// + /// This is in contrast to [`f32::min`] which only returns NaN when *both* arguments are NaN, + /// and which does not reliably order `-0.0` and `+0.0`. + /// + /// This follows the IEEE 754-2019 semantics for `minimum`. /// /// ``` /// #![feature(float_minimum_maximum)] @@ -981,13 +988,6 @@ pub const fn maximum(self, other: f32) -> f32 { /// assert_eq!(x.minimum(y), x); /// assert!(x.minimum(f32::NAN).is_nan()); /// ``` - /// - /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser - /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. - /// Note that this follows the IEEE 754-2019 semantics for `minimum`. - /// - /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN - /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info. #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 854bdcf39d09..42726fa57dc5 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -961,8 +961,15 @@ pub const fn min(self, other: f64) -> f64 { /// Returns the maximum of the two numbers, propagating NaN. /// - /// This returns NaN when *either* argument is NaN, as opposed to - /// [`f64::max`] which only returns NaN when *both* arguments are NaN. + /// If at least one of the arguments is NaN, the return value is NaN, with the bit pattern + /// picked using the usual [rules for arithmetic operations](f32#nan-bit-patterns). Furthermore, + /// `-0.0` is considered to be less than `+0.0`, making this function fully deterministic for + /// non-NaN inputs. + /// + /// This is in contrast to [`f64::max`] which only returns NaN when *both* arguments are NaN, + /// and which does not reliably order `-0.0` and `+0.0`. + /// + /// This follows the IEEE 754-2019 semantics for `maximum`. /// /// ``` /// #![feature(float_minimum_maximum)] @@ -972,13 +979,6 @@ pub const fn min(self, other: f64) -> f64 { /// assert_eq!(x.maximum(y), y); /// assert!(x.maximum(f64::NAN).is_nan()); /// ``` - /// - /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater - /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. - /// Note that this follows the IEEE 754-2019 semantics for `maximum`. - /// - /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN - /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info. #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] @@ -988,8 +988,15 @@ pub const fn maximum(self, other: f64) -> f64 { /// Returns the minimum of the two numbers, propagating NaN. /// - /// This returns NaN when *either* argument is NaN, as opposed to - /// [`f64::min`] which only returns NaN when *both* arguments are NaN. + /// If at least one of the arguments is NaN, the return value is NaN, with the bit pattern + /// picked using the usual [rules for arithmetic operations](f32#nan-bit-patterns). Furthermore, + /// `-0.0` is considered to be less than `+0.0`, making this function fully deterministic for + /// non-NaN inputs. + /// + /// This is in contrast to [`f64::min`] which only returns NaN when *both* arguments are NaN, + /// and which does not reliably order `-0.0` and `+0.0`. + /// + /// This follows the IEEE 754-2019 semantics for `minimum`. /// /// ``` /// #![feature(float_minimum_maximum)] @@ -999,13 +1006,6 @@ pub const fn maximum(self, other: f64) -> f64 { /// assert_eq!(x.minimum(y), x); /// assert!(x.minimum(f64::NAN).is_nan()); /// ``` - /// - /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser - /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. - /// Note that this follows the IEEE 754-2019 semantics for `minimum`. - /// - /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN - /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info. #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] From 8c03477d574ca552b97c8b60e2ce0278fc7c717e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 2 Dec 2025 23:48:44 +0100 Subject: [PATCH 229/585] rename cortex-ar references to unified aarch32 --- .../rustc/src/platform-support/armebv7r-none-eabi.md | 8 ++++---- .../rustc/src/platform-support/armv7a-none-eabi.md | 12 ++++++------ .../rustc/src/platform-support/armv7r-none-eabi.md | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md index d5c676ea9a4c..853f717cf63f 100644 --- a/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md @@ -46,10 +46,10 @@ disabled as needed with `-C target-feature=(+/-)`. ## Start-up and Low-Level Code -The [Rust Embedded Devices Working Group Arm Team] maintain the [`cortex-ar`] -and [`cortex-r-rt`] crates, which may be useful for writing bare-metal code +The [Rust Embedded Devices Working Group Arm Team] maintain the [`aarch32-cpu`] +and [`aarch32-rt`] crates, which may be useful for writing bare-metal code using this target. Those crates include several examples which run in QEMU and build using these targets. -[`cortex-ar`]: https://docs.rs/cortex-ar -[`cortex-r-rt`]: https://docs.rs/cortex-r-rt +[`aarch32-cpu`]: https://docs.rs/aarch32-cpu +[`aarch32-rt`]: https://docs.rs/aarch32-rt diff --git a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md index ef9b7f4e9450..05afb4f4321b 100644 --- a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md @@ -63,10 +63,10 @@ and disable them via `.cargo/config.toml` file. ## Start-up and Low-Level Code -The [Rust Embedded Devices Working Group Arm Team] maintain the [`cortex-ar`] -and [`cortex-a-rt`] crates, which may be useful for writing bare-metal code -using this target. The [`cortex-ar` repository](https://github.com/rust-embedded/cortex-ar) -includes several examples which run in QEMU and build using these targets. +The [Rust Embedded Devices Working Group Arm Team] maintain the [`aarch32-cpu`] +and [`aarch32-rt`] crates, which may be useful for writing bare-metal code +using this target. Those crates include several examples which run in QEMU and +build using these targets. -[`cortex-ar`]: https://docs.rs/cortex-ar -[`cortex-a-rt`]: https://docs.rs/cortex-a-rt +[`aarch32-cpu`]: https://docs.rs/aarch32-cpu +[`aarch32-rt`]: https://docs.rs/aarch32-rt diff --git a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md index 9429eb6ab8ae..7f22a29f2ee6 100644 --- a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md @@ -41,10 +41,10 @@ disabled as needed with `-C target-feature=(+/-)`. ## Start-up and Low-Level Code -The [Rust Embedded Devices Working Group Arm Team] maintain the [`cortex-ar`] -and [`cortex-r-rt`] crates, which may be useful for writing bare-metal code +The [Rust Embedded Devices Working Group Arm Team] maintain the [`aarch32-cpu`] +and [`aarch32-rt`] crates, which may be useful for writing bare-metal code using this target. Those crates include several examples which run in QEMU and build using these targets. -[`cortex-ar`]: https://docs.rs/cortex-ar -[`cortex-r-rt`]: https://docs.rs/cortex-r-rt +[`aarch32-cpu`]: https://docs.rs/aarch32-cpu +[`aarch32-rt`]: https://docs.rs/aarch32-rt From f113df337548ae54d83657fdb54ba887fbfd5c31 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 2 Dec 2025 16:44:15 -0800 Subject: [PATCH 230/585] Remove pagetoc This has been subsumed by the update to mdbook 0.5. I just forgot to remove this in https://github.com/rust-lang/rustc-dev-guide/pull/2652. --- src/doc/rustc-dev-guide/README.md | 5 -- src/doc/rustc-dev-guide/book.toml | 2 - src/doc/rustc-dev-guide/pagetoc.css | 84 ---------------------- src/doc/rustc-dev-guide/pagetoc.js | 104 ---------------------------- 4 files changed, 195 deletions(-) delete mode 100644 src/doc/rustc-dev-guide/pagetoc.css delete mode 100644 src/doc/rustc-dev-guide/pagetoc.js diff --git a/src/doc/rustc-dev-guide/README.md b/src/doc/rustc-dev-guide/README.md index 1ad895aeda2e..fee7cf042e1f 100644 --- a/src/doc/rustc-dev-guide/README.md +++ b/src/doc/rustc-dev-guide/README.md @@ -65,11 +65,6 @@ following example. ENABLE_LINKCHECK=1 mdbook serve ``` -### Table of Contents - -Each page has a TOC that is automatically generated by `pagetoc.js`. -There is an associated `pagetoc.css`, for styling. - ## Synchronizing josh subtree with rustc This repository is linked to `rust-lang/rust` as a [josh](https://josh-project.github.io/josh/intro.html) subtree. You can use the [rustc-josh-sync](https://github.com/rust-lang/josh-sync) tool to perform synchronization. diff --git a/src/doc/rustc-dev-guide/book.toml b/src/doc/rustc-dev-guide/book.toml index efb13101c8de..15a597e5addb 100644 --- a/src/doc/rustc-dev-guide/book.toml +++ b/src/doc/rustc-dev-guide/book.toml @@ -15,9 +15,7 @@ edit-url-template = "https://github.com/rust-lang/rustc-dev-guide/edit/main/{pat additional-js = [ "mermaid.min.js", "mermaid-init.js", - "pagetoc.js", ] -additional-css = ["pagetoc.css"] [output.html.search] use-boolean-and = true diff --git a/src/doc/rustc-dev-guide/pagetoc.css b/src/doc/rustc-dev-guide/pagetoc.css deleted file mode 100644 index fa709194f375..000000000000 --- a/src/doc/rustc-dev-guide/pagetoc.css +++ /dev/null @@ -1,84 +0,0 @@ -/* Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) */ - -:root { - --toc-width: 270px; - --center-content-toc-shift: calc(-1 * var(--toc-width) / 2); -} - -.nav-chapters { - /* adjust width of buttons that bring to the previous or the next page */ - min-width: 50px; -} - -@media only screen { - @media (max-width: 1179px) { - .sidebar-hidden #sidetoc { - display: none; - } - } - - @media (max-width: 1439px) { - .sidebar-visible #sidetoc { - display: none; - } - } - - @media (1180px <= width <= 1439px) { - .sidebar-hidden main { - position: relative; - left: var(--center-content-toc-shift); - } - } - - @media (1440px <= width <= 1700px) { - .sidebar-visible main { - position: relative; - left: var(--center-content-toc-shift); - } - } - - #sidetoc { - margin-left: calc(100% + 20px); - } - #pagetoc { - position: fixed; - /* adjust TOC width */ - width: var(--toc-width); - height: calc(100vh - var(--menu-bar-height) - 0.67em * 4); - overflow: auto; - } - #pagetoc a { - border-left: 1px solid var(--sidebar-bg); - color: var(--fg); - display: block; - padding-bottom: 5px; - padding-top: 5px; - padding-left: 10px; - text-align: left; - text-decoration: none; - } - #pagetoc a:hover, - #pagetoc a.active { - background: var(--sidebar-bg); - color: var(--sidebar-active) !important; - } - #pagetoc .active { - background: var(--sidebar-bg); - color: var(--sidebar-active); - } - #pagetoc .pagetoc-H2 { - padding-left: 20px; - } - #pagetoc .pagetoc-H3 { - padding-left: 40px; - } - #pagetoc .pagetoc-H4 { - padding-left: 60px; - } -} - -@media print { - #sidetoc { - display: none; - } -} diff --git a/src/doc/rustc-dev-guide/pagetoc.js b/src/doc/rustc-dev-guide/pagetoc.js deleted file mode 100644 index 927a5b10749b..000000000000 --- a/src/doc/rustc-dev-guide/pagetoc.js +++ /dev/null @@ -1,104 +0,0 @@ -// Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) - -let activeHref = location.href; -function updatePageToc(elem = undefined) { - let selectedPageTocElem = elem; - const pagetoc = document.getElementById("pagetoc"); - - function getRect(element) { - return element.getBoundingClientRect(); - } - - function overflowTop(container, element) { - return getRect(container).top - getRect(element).top; - } - - function overflowBottom(container, element) { - return getRect(container).bottom - getRect(element).bottom; - } - - // We've not selected a heading to highlight, and the URL needs updating - // so we need to find a heading based on the URL - if (selectedPageTocElem === undefined && location.href !== activeHref) { - activeHref = location.href; - for (const pageTocElement of pagetoc.children) { - if (pageTocElement.href === activeHref) { - selectedPageTocElem = pageTocElement; - } - } - } - - // We still don't have a selected heading, let's try and find the most - // suitable heading based on the scroll position - if (selectedPageTocElem === undefined) { - const margin = window.innerHeight / 3; - - const headers = document.getElementsByClassName("header"); - for (let i = 0; i < headers.length; i++) { - const header = headers[i]; - if (selectedPageTocElem === undefined && getRect(header).top >= 0) { - if (getRect(header).top < margin) { - selectedPageTocElem = header; - } else { - selectedPageTocElem = headers[Math.max(0, i - 1)]; - } - } - // a very long last section's heading is over the screen - if (selectedPageTocElem === undefined && i === headers.length - 1) { - selectedPageTocElem = header; - } - } - } - - // Remove the active flag from all pagetoc elements - for (const pageTocElement of pagetoc.children) { - pageTocElement.classList.remove("active"); - } - - // If we have a selected heading, set it to active and scroll to it - if (selectedPageTocElem !== undefined) { - for (const pageTocElement of pagetoc.children) { - if (selectedPageTocElem.href.localeCompare(pageTocElement.href) === 0) { - pageTocElement.classList.add("active"); - if (overflowTop(pagetoc, pageTocElement) > 0) { - pagetoc.scrollTop = pageTocElement.offsetTop; - } - if (overflowBottom(pagetoc, pageTocElement) < 0) { - pagetoc.scrollTop -= overflowBottom(pagetoc, pageTocElement); - } - } - } - } -} - -if (document.getElementById("sidetoc") === null && - document.getElementsByClassName("header").length > 0) { - // The sidetoc element doesn't exist yet, let's create it - - // Create the empty sidetoc and pagetoc elements - const sidetoc = document.createElement("div"); - const pagetoc = document.createElement("div"); - sidetoc.id = "sidetoc"; - pagetoc.id = "pagetoc"; - sidetoc.appendChild(pagetoc); - - // And append them to the current DOM - const main = document.querySelector('main'); - main.insertBefore(sidetoc, main.firstChild); - - // Populate sidebar on load - window.addEventListener("load", () => { - for (const header of document.getElementsByClassName("header")) { - const link = document.createElement("a"); - link.innerHTML = header.innerHTML; - link.href = header.hash; - link.classList.add("pagetoc-" + header.parentElement.tagName); - document.getElementById("pagetoc").appendChild(link); - link.onclick = () => updatePageToc(link); - } - updatePageToc(); - }); - - // Update page table of contents selected heading on scroll - window.addEventListener("scroll", () => updatePageToc()); -} From 880a77999918ebdbe96fd733693c78997995b206 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 2 Dec 2025 19:27:15 -0800 Subject: [PATCH 231/585] Update reference Pulls in https://github.com/rust-lang/reference/pull/2080 to fix the tests. --- src/doc/reference | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/reference b/src/doc/reference index f2ac173df990..b14b4e40f53c 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit f2ac173df9906de5c03b0ee50653321ef1c4ebe8 +Subproject commit b14b4e40f53ca468beaf2f5d0dfb4f4c4ba6bc7b From 8949b816eee486f7308b89bd0b04d3a7e412a29c Mon Sep 17 00:00:00 2001 From: lapla Date: Wed, 3 Dec 2025 12:54:44 +0900 Subject: [PATCH 232/585] rustdoc: Fix broken link to `Itertools::format` --- src/librustdoc/display.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/display.rs b/src/librustdoc/display.rs index 550be1ae8958..adb761ed9faa 100644 --- a/src/librustdoc/display.rs +++ b/src/librustdoc/display.rs @@ -5,11 +5,13 @@ pub(crate) trait Joined: IntoIterator { /// Takes an iterator over elements that implement [`Display`], and format them into `f`, separated by `sep`. /// - /// This is similar to [`Itertools::format`](itertools::Itertools::format), but instead of returning an implementation of `Display`, + /// This is similar to [`Itertools::format`], but instead of returning an implementation of `Display`, /// it formats directly into a [`Formatter`]. /// /// The performance of `joined` is slightly better than `format`, since it doesn't need to use a `Cell` to keep track of whether [`fmt`](Display::fmt) /// was already called (`joined`'s API doesn't allow it be called more than once). + /// + /// [`Itertools::format`]: https://docs.rs/itertools/latest/itertools/trait.Itertools.html#method.format fn joined(&mut self, sep: impl Display, f: &mut Formatter<'_>) -> fmt::Result; } From 537a8d79624959551fbb6ea81457a2bc0e6c1e3d Mon Sep 17 00:00:00 2001 From: "U. Lasiotus" Date: Wed, 3 Dec 2025 04:48:26 +0000 Subject: [PATCH 233/585] Motor OS: fix compile error [PR 148765](https://github.com/rust-lang/rust/pull/148765) changed the expected signature of Thread::new(), which broke Motor OS target. Also set thread name. --- library/std/src/sys/thread/motor.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/library/std/src/sys/thread/motor.rs b/library/std/src/sys/thread/motor.rs index 0457d8818f32..4c6d3ccb84ec 100644 --- a/library/std/src/sys/thread/motor.rs +++ b/library/std/src/sys/thread/motor.rs @@ -2,6 +2,7 @@ use crate::io; use crate::num::NonZeroUsize; use crate::sys::map_motor_error; +use crate::thread::ThreadInit; use crate::time::Duration; pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 256; @@ -14,21 +15,21 @@ unsafe impl Send for Thread {} unsafe impl Sync for Thread {} impl Thread { - pub unsafe fn new( - stack: usize, - _name: Option<&str>, - p: Box, - ) -> io::Result { + pub unsafe fn new(stack: usize, init: Box) -> io::Result { extern "C" fn __moto_rt_thread_fn(thread_arg: u64) { unsafe { - Box::from_raw( - core::ptr::with_exposed_provenance::>(thread_arg as usize) - .cast_mut(), - )(); + let init = Box::from_raw(core::ptr::with_exposed_provenance_mut::( + thread_arg as usize, + )); + let rust_start = init.init(); + if let Some(name) = crate::thread::current().name() { + let _ = moto_rt::thread::set_name(name); + } + rust_start(); } } - let thread_arg = Box::into_raw(Box::new(p)).expose_provenance() as u64; + let thread_arg = Box::into_raw(init).expose_provenance() as u64; let sys_thread = moto_rt::thread::spawn(__moto_rt_thread_fn, stack, thread_arg) .map_err(map_motor_error)?; Ok(Self { sys_thread }) From f49eaecca9e231ffe0f290f31314be06ef5f8db2 Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Wed, 3 Dec 2025 10:08:29 +0200 Subject: [PATCH 234/585] reorganize test contents and adjust generated inputs to reduce iterations --- library/coretests/tests/num/uint_macros.rs | 28 ++++++++++------------ 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs index 6e746a6a2278..72d500e575fa 100644 --- a/library/coretests/tests/num/uint_macros.rs +++ b/library/coretests/tests/num/uint_macros.rs @@ -407,10 +407,10 @@ fn test_lots_of_gather_scatter() { assert_eq!(&xs, &[0xff, 0x00, 0x0f, 0xf0, 0x33, 0xcc, 0x55, 0xaa]); } - // `256 * BITS` masks + // `256 * (BITS / 5)` masks let sparse_masks = (i8::MIN..=i8::MAX) .map(|i| (i as i128 as $T).rotate_right(4)) - .flat_map(|x| (0..$T::BITS).map(move |s| ((1 as $T) << s) ^ x)); + .flat_map(|x| (0..$T::BITS).step_by(5).map(move |r| x.rotate_right(r))); for sparse in sparse_masks { // Collect the set bits to sequential low bits @@ -419,21 +419,19 @@ fn test_lots_of_gather_scatter() { assert_eq!(count, dense.count_ones()); assert_eq!(count, dense.trailing_ones()); + // Check that each bit is individually mapped correctly let mut t = sparse; - for k in 0..$T::BITS { - let x = ((1 as $T) << k).scatter_bits(sparse); - let y = t.isolate_lowest_one(); - assert_eq!(x, y); - t ^= y; - } - - let mut t = sparse; - for k in 0..count { - let y = t.isolate_lowest_one(); - let x = y.gather_bits(sparse); - assert_eq!(x, (1 as $T) << k); - t ^= y; + let mut bit = 1 as $T; + for _ in 0..count { + let lowest_one = t.isolate_lowest_one(); + assert_eq!(lowest_one, bit.scatter_bits(sparse)); + assert_eq!(bit, lowest_one.gather_bits(sparse)); + t ^= lowest_one; + bit <<= 1; } + // Other bits are ignored + assert_eq!(0, bit.wrapping_neg().scatter_bits(sparse)); + assert_eq!(0, (!sparse).gather_bits(sparse)); for &x in &xs { // Gather bits from `x & sparse` to `dense` From fc017dd1760fec2b02b2f3db0375bda58fbb608a Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 3 Dec 2025 01:36:20 +0100 Subject: [PATCH 235/585] c-variadic: bpf and spirv do not support c-variadic definitions --- compiler/rustc_ast_passes/messages.ftl | 2 ++ .../rustc_ast_passes/src/ast_validation.rs | 8 ++++++++ compiler/rustc_ast_passes/src/errors.rs | 8 ++++++++ compiler/rustc_target/src/spec/mod.rs | 18 ++++++++++++++++++ 4 files changed, 36 insertions(+) diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index f03c7dd5b9d5..f1f734b855c1 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -80,6 +80,8 @@ ast_passes_c_variadic_must_be_unsafe = ast_passes_c_variadic_no_extern = `...` is not supported for non-extern functions .help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list +ast_passes_c_variadic_not_supported = the `{$target}` target does not support c-variadic functions + ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic .const = `const` because of this .variadic = C-variadic because of this diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index e57f8da26769..42461bd5eb10 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -710,6 +710,14 @@ fn check_c_variadic_type(&self, fk: FnKind<'a>, attrs: &'a AttrVec) { match fn_ctxt { FnCtxt::Foreign => return, FnCtxt::Free | FnCtxt::Assoc(_) => { + if !self.sess.target.arch.supports_c_variadic_definitions() { + self.dcx().emit_err(errors::CVariadicNotSupported { + variadic_span: variadic_param.span, + target: &*self.sess.target.llvm_target, + }); + return; + } + match sig.header.ext { Extern::Implicit(_) => { if !matches!(sig.header.safety, Safety::Unsafe(_)) { diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index c700ae517140..bf9309614fe2 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -733,6 +733,14 @@ pub(crate) struct CoroutineAndCVariadic { pub variadic_span: Span, } +#[derive(Diagnostic)] +#[diag(ast_passes_c_variadic_not_supported)] +pub(crate) struct CVariadicNotSupported<'a> { + #[primary_span] + pub variadic_span: Span, + pub target: &'a str, +} + #[derive(Diagnostic)] #[diag(ast_passes_pattern_in_foreign, code = E0130)] // FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 2b1c7174fb15..424026bdceab 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1925,6 +1925,24 @@ pub fn desc_symbol(&self) -> Symbol { Self::Other(name) => rustc_span::Symbol::intern(name), } } + + pub fn supports_c_variadic_definitions(&self) -> bool { + use Arch::*; + + match self { + // These targets just do not support c-variadic definitions. + Bpf | SpirV => false, + + // We don't know if the target supports c-variadic definitions, but we don't want + // to needlessly restrict custom target.json configurations. + Other(_) => true, + + AArch64 | AmdGpu | Arm | Arm64EC | Avr | CSky | Hexagon | LoongArch32 | LoongArch64 + | M68k | Mips | Mips32r6 | Mips64 | Mips64r6 | Msp430 | Nvptx64 | PowerPC + | PowerPC64 | PowerPC64LE | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 + | Wasm64 | X86 | X86_64 | Xtensa => true, + } + } } crate::target_spec_enum! { From 388c42e72a832aae836f8e9b885137a73646f718 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Dec 2025 14:10:54 +0300 Subject: [PATCH 236/585] linker: Remove special case for `rust-lld` in `detect_self_contained_mingw` `rust-lld` is supposed to live in sysroot, so it doesn't change the behavior of the function, only removes a potential micro-optimization. --- compiler/rustc_codegen_ssa/src/back/link.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 878b333580e1..d35c3b6bb189 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1763,10 +1763,6 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { // Returns true if linker is located within sysroot fn detect_self_contained_mingw(sess: &Session, linker: &Path) -> bool { - // Assume `-C linker=rust-lld` as self-contained mode - if linker == Path::new("rust-lld") { - return true; - } let linker_with_extension = if cfg!(windows) && linker.extension().is_none() { linker.with_extension("exe") } else { From ae93635f5df3680448b2550bd7e6d43d3904cc14 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 3 Dec 2025 09:05:21 +0800 Subject: [PATCH 237/585] compiletest: rename `compile_lib_path` -> `host_compile_lib_path` --- src/tools/compiletest/src/common.rs | 7 ++----- src/tools/compiletest/src/directives/needs.rs | 2 +- src/tools/compiletest/src/lib.rs | 2 +- src/tools/compiletest/src/runtest.rs | 9 +++++---- src/tools/compiletest/src/runtest/run_make.rs | 2 +- src/tools/compiletest/src/rustdoc_gui_test.rs | 2 +- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 6d020f3f245e..3ee66591c43a 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -252,10 +252,7 @@ pub struct Config { /// /// For example: /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/stage1/bin/lib` - /// - /// FIXME: maybe rename this to reflect (1) which target platform (host, not target), and (2) - /// which `rustc` (the `rustc`-under-test, not the stage 0 `rustc` unless forced). - pub compile_lib_path: Utf8PathBuf, + pub host_compile_lib_path: Utf8PathBuf, /// Path to libraries needed to run the compiled executable for the **target** platform. This /// corresponds to the **target** sysroot libraries, including the **target** standard library. @@ -1093,7 +1090,7 @@ fn query_rustc_output(config: &Config, args: &[&str], envs: HashMap Self { // // However, `rust-lld` is only located under the lib path, so we look for it there. rust_lld: config - .compile_lib_path + .host_compile_lib_path .parent() .expect("couldn't traverse to the parent of the specified --compile-lib-path") .join("lib") diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 4dcf3ef28cde..aef15cc69b3c 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -375,7 +375,7 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { fail_fast: matches.opt_present("fail-fast") || env::var_os("RUSTC_TEST_FAIL_FAST").is_some(), - compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), + host_compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), rustc_path: opt_path(matches, "rustc-path"), cargo_path: matches.opt_str("cargo-path").map(Utf8PathBuf::from), diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ddcda91c13d0..c2fc0e55c220 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -458,7 +458,7 @@ fn print_source(&self, read_from: ReadFrom, pretty_type: &str) -> ProcRes { self.compose_and_run( rustc, - self.config.compile_lib_path.as_path(), + self.config.host_compile_lib_path.as_path(), Some(aux_dir.as_path()), src, ) @@ -1321,7 +1321,7 @@ fn compose_and_run_compiler(&self, mut rustc: Command, input: Option) -> self.props.unset_rustc_env.iter().fold(&mut rustc, Command::env_remove); self.compose_and_run( rustc, - self.config.compile_lib_path.as_path(), + self.config.host_compile_lib_path.as_path(), Some(aux_dir.as_path()), input, ) @@ -1344,7 +1344,8 @@ fn build_minicore(&self) -> Utf8PathBuf { rustc.arg("-Cpanic=abort"); rustc.args(self.props.minicore_compile_flags.clone()); - let res = self.compose_and_run(rustc, self.config.compile_lib_path.as_path(), None, None); + let res = + self.compose_and_run(rustc, self.config.host_compile_lib_path.as_path(), None, None); if !res.status.success() { self.fatal_proc_rec( &format!("auxiliary build of {} failed to compile: ", self.config.minicore_path), @@ -1458,7 +1459,7 @@ fn build_auxiliary( let auxres = aux_cx.compose_and_run( aux_rustc, - aux_cx.config.compile_lib_path.as_path(), + aux_cx.config.host_compile_lib_path.as_path(), Some(aux_dir.as_path()), None, ); diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index b201710e32fd..b29752f330d6 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -172,7 +172,7 @@ pub(super) fn run_rmake_test(&self) { .env(dylib_env_var(), &env::join_paths(recipe_dylib_search_paths).unwrap()) // Provide the directory to libraries that are needed to run the *compiler* invoked // by the recipe. - .env("HOST_RUSTC_DYLIB_PATH", &self.config.compile_lib_path) + .env("HOST_RUSTC_DYLIB_PATH", &self.config.host_compile_lib_path) // Provide the directory to libraries that might be needed to run binaries created // by a compiler invoked by the recipe. .env("TARGET_EXE_DYLIB_PATH", &self.config.run_lib_path) diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index db66d7a8febc..19bc3e0e4e7b 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -58,7 +58,7 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { edition: Default::default(), bless: Default::default(), fail_fast: Default::default(), - compile_lib_path: Utf8PathBuf::default(), + host_compile_lib_path: Utf8PathBuf::default(), run_lib_path: Utf8PathBuf::default(), rustc_path: Utf8PathBuf::default(), cargo_path: Default::default(), From 0654444d7fa280dc7a033d408c771beab5e09823 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 3 Dec 2025 09:06:29 +0800 Subject: [PATCH 238/585] compiletest: rename `run_lib_path` -> `target_run_lib_path` --- src/tools/compiletest/src/common.rs | 5 +---- src/tools/compiletest/src/lib.rs | 4 ++-- src/tools/compiletest/src/runtest.rs | 8 ++++---- src/tools/compiletest/src/runtest/debuginfo.rs | 4 ++-- src/tools/compiletest/src/runtest/run_make.rs | 2 +- src/tools/compiletest/src/rustdoc_gui_test.rs | 2 +- 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 3ee66591c43a..2ccbd83be38e 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -260,13 +260,10 @@ pub struct Config { /// For example: /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/i686-unknown-linux-gnu/lib` /// - /// FIXME: maybe rename this to reflect (1) which target platform (target, not host), and (2) - /// what "run libraries" are against. - /// /// FIXME: this is very under-documented in conjunction with the `remote-test-client` scheme and /// `RUNNER` scheme to actually run the target executable under the target platform environment, /// cf. [`Self::remote_test_client`] and [`Self::runner`]. - pub run_lib_path: Utf8PathBuf, + pub target_run_lib_path: Utf8PathBuf, /// Path to the *staged* `rustc`-under-test. Unless forced, this `rustc` is *staged*, and must /// not be confused with [`Self::stage0_rustc_path`]. diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index aef15cc69b3c..7ff729b1667a 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -376,7 +376,7 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { || env::var_os("RUSTC_TEST_FAIL_FAST").is_some(), host_compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), - run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), + target_run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), rustc_path: opt_path(matches, "rustc-path"), cargo_path: matches.opt_str("cargo-path").map(Utf8PathBuf::from), stage0_rustc_path: matches.opt_str("stage0-rustc-path").map(Utf8PathBuf::from), @@ -688,7 +688,7 @@ fn common_inputs_stamp(config: &Config) -> Stamp { stamp.add_dir(&src_root.join("src/etc/natvis")); - stamp.add_dir(&config.run_lib_path); + stamp.add_dir(&config.target_run_lib_path); if let Some(ref rustdoc_path) = config.rustdoc_path { stamp.add_path(&rustdoc_path); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index c2fc0e55c220..54d6e0190ddc 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1060,7 +1060,7 @@ fn document_inner( rustdoc.current_dir(current_dir); rustdoc .arg("-L") - .arg(self.config.run_lib_path.as_path()) + .arg(self.config.target_run_lib_path.as_path()) .arg("-L") .arg(aux_dir) .arg("-o") @@ -1151,7 +1151,7 @@ fn exec_compiled_test_general( self.compose_and_run( test_client, - self.config.run_lib_path.as_path(), + self.config.target_run_lib_path.as_path(), Some(aux_dir.as_path()), None, ) @@ -1166,7 +1166,7 @@ fn exec_compiled_test_general( self.compose_and_run( wr_run, - self.config.run_lib_path.as_path(), + self.config.target_run_lib_path.as_path(), Some(aux_dir.as_path()), None, ) @@ -1181,7 +1181,7 @@ fn exec_compiled_test_general( self.compose_and_run( program, - self.config.run_lib_path.as_path(), + self.config.target_run_lib_path.as_path(), Some(aux_dir.as_path()), None, ) diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 15e37cda7d96..5ef4366b68be 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -90,7 +90,7 @@ fn run_debuginfo_cdb_test(&self) { let debugger_run_result = self.compose_and_run( cdb, - self.config.run_lib_path.as_path(), + self.config.target_run_lib_path.as_path(), None, // aux_path None, // input ); @@ -313,7 +313,7 @@ fn run_debuginfo_gdb_test(&self) { gdb.args(debugger_opts).env("PYTHONPATH", pythonpath); debugger_run_result = - self.compose_and_run(gdb, self.config.run_lib_path.as_path(), None, None); + self.compose_and_run(gdb, self.config.target_run_lib_path.as_path(), None, None); } if !debugger_run_result.status.success() { diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index b29752f330d6..68574eb4bfd6 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -175,7 +175,7 @@ pub(super) fn run_rmake_test(&self) { .env("HOST_RUSTC_DYLIB_PATH", &self.config.host_compile_lib_path) // Provide the directory to libraries that might be needed to run binaries created // by a compiler invoked by the recipe. - .env("TARGET_EXE_DYLIB_PATH", &self.config.run_lib_path) + .env("TARGET_EXE_DYLIB_PATH", &self.config.target_run_lib_path) // Provide the target. .env("TARGET", &self.config.target) // Some tests unfortunately still need Python, so provide path to a Python interpreter. diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index 19bc3e0e4e7b..704f1806f8b7 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -59,7 +59,7 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { bless: Default::default(), fail_fast: Default::default(), host_compile_lib_path: Utf8PathBuf::default(), - run_lib_path: Utf8PathBuf::default(), + target_run_lib_path: Utf8PathBuf::default(), rustc_path: Utf8PathBuf::default(), cargo_path: Default::default(), stage0_rustc_path: Default::default(), From 6a00f0d4fff69ef7cb8b37a89ac187b55ac8ae04 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 3 Dec 2025 09:13:31 +0800 Subject: [PATCH 239/585] compiletest: fixup comment for `rustc_path` --- src/tools/compiletest/src/common.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 2ccbd83be38e..9a941e2a9c9b 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -265,13 +265,23 @@ pub struct Config { /// cf. [`Self::remote_test_client`] and [`Self::runner`]. pub target_run_lib_path: Utf8PathBuf, - /// Path to the *staged* `rustc`-under-test. Unless forced, this `rustc` is *staged*, and must - /// not be confused with [`Self::stage0_rustc_path`]. + /// Path to the `rustc`-under-test. + /// + /// For `ui-fulldeps` test suite specifically: + /// + /// - This is the **stage 0** compiler when testing `ui-fulldeps` under `--stage=1`. + /// - This is the **stage 2** compiler when testing `ui-fulldeps` under `--stage=2`. + /// + /// See [`Self::query_rustc_path`] for the `--stage=1` `ui-fulldeps` scenario where a separate + /// in-tree `rustc` is used for querying target information. /// /// For example: /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc` /// - /// FIXME: maybe rename this to reflect that this is the `rustc`-under-test. + /// # Note on forced stage0 + /// + /// It is possible for this `rustc` to be a stage 0 `rustc` if explicitly configured with the + /// bootstrap option `build.compiletest-allow-stage0=true` and specifying `--stage=0`. pub rustc_path: Utf8PathBuf, /// Path to a *staged* **host** platform cargo executable (unless stage 0 is forced). This From 57f9580f10e5613d035d8b727c46de8d07ed2386 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 3 Dec 2025 09:20:59 +0800 Subject: [PATCH 240/585] compiletest: change some `String`s to `Utf8PathBuf` --- src/tools/compiletest/src/common.rs | 14 +++++++------- src/tools/compiletest/src/debuggers.rs | 6 +++--- src/tools/compiletest/src/lib.rs | 14 ++++++++------ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 9a941e2a9c9b..f3bd707c7891 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -321,10 +321,10 @@ pub struct Config { pub python: String, /// Path to the `src/tools/jsondocck/` bootstrap tool executable. - pub jsondocck_path: Option, + pub jsondocck_path: Option, /// Path to the `src/tools/jsondoclint/` bootstrap tool executable. - pub jsondoclint_path: Option, + pub jsondoclint_path: Option, /// Path to a host LLVM `FileCheck` executable. pub llvm_filecheck: Option, @@ -337,7 +337,7 @@ pub struct Config { /// The path to the **target** `clang` executable to run `clang`-based tests with. If `None`, /// then these tests will be ignored. - pub run_clang_based_tests_with: Option, + pub run_clang_based_tests_with: Option, /// Path to the directory containing the sources. This corresponds to the root folder of a /// `rust-lang/rust` checkout. @@ -530,7 +530,7 @@ pub struct Config { /// /// FIXME: we are propagating a python from `PYTHONPATH`, not from an explicit config for gdb /// debugger script. - pub gdb: Option, + pub gdb: Option, /// Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch /// @@ -575,7 +575,7 @@ pub struct Config { /// /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for /// `arm-linux-androideabi` target. - pub adb_path: String, + pub adb_path: Utf8PathBuf, /// Extra parameter to run test suite on `arm-linux-androideabi`. /// @@ -584,7 +584,7 @@ pub struct Config { /// /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for /// `arm-linux-androideabi` target. - pub adb_test_dir: String, + pub adb_test_dir: Utf8PathBuf, /// Status whether android device available or not. When unavailable, this will cause tests to /// panic when the test binary is attempted to be run. @@ -660,7 +660,7 @@ pub struct Config { pub llvm_components: String, /// Path to a NodeJS executable. Used for JS doctests, emscripten and WASM tests. - pub nodejs: Option, + pub nodejs: Option, /// Whether to rerun tests even if the inputs are unchanged. pub force_rerun: bool, diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs index b26c45240b9f..791c5f03c21a 100644 --- a/src/tools/compiletest/src/debuggers.rs +++ b/src/tools/compiletest/src/debuggers.rs @@ -133,7 +133,7 @@ pub(crate) fn discover_gdb( gdb: Option, target: &str, android_cross_path: &Utf8Path, -) -> Option { +) -> Option { #[cfg(not(windows))] const GDB_FALLBACK: &str = "gdb"; #[cfg(windows)] @@ -155,10 +155,10 @@ pub(crate) fn discover_gdb( Some(ref s) => s.to_owned(), }; - Some(gdb) + Some(Utf8PathBuf::from(gdb)) } -pub(crate) fn query_gdb_version(gdb: &str) -> Option { +pub(crate) fn query_gdb_version(gdb: &Utf8Path) -> Option { let mut version_line = None; if let Ok(output) = Command::new(&gdb).arg("--version").output() { if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 7ff729b1667a..8b64339c156f 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -384,9 +384,11 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { rustdoc_path: matches.opt_str("rustdoc-path").map(Utf8PathBuf::from), coverage_dump_path: matches.opt_str("coverage-dump-path").map(Utf8PathBuf::from), python: matches.opt_str("python").unwrap(), - jsondocck_path: matches.opt_str("jsondocck-path"), - jsondoclint_path: matches.opt_str("jsondoclint-path"), - run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), + jsondocck_path: matches.opt_str("jsondocck-path").map(Utf8PathBuf::from), + jsondoclint_path: matches.opt_str("jsondoclint-path").map(Utf8PathBuf::from), + run_clang_based_tests_with: matches + .opt_str("run-clang-based-tests-with") + .map(Utf8PathBuf::from), llvm_filecheck: matches.opt_str("llvm-filecheck").map(Utf8PathBuf::from), llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(Utf8PathBuf::from), @@ -441,8 +443,8 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { llvm_version, system_llvm: matches.opt_present("system-llvm"), android_cross_path, - adb_path: opt_str2(matches.opt_str("adb-path")), - adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")), + adb_path: Utf8PathBuf::from(opt_str2(matches.opt_str("adb-path"))), + adb_test_dir: Utf8PathBuf::from(opt_str2(matches.opt_str("adb-test-dir"))), adb_device_status: opt_str2(matches.opt_str("target")).contains("android") && "(none)" != opt_str2(matches.opt_str("adb-test-dir")) && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(), @@ -466,7 +468,7 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { target_linker: matches.opt_str("target-linker"), host_linker: matches.opt_str("host-linker"), llvm_components: matches.opt_str("llvm-components").unwrap(), - nodejs: matches.opt_str("nodejs"), + nodejs: matches.opt_str("nodejs").map(Utf8PathBuf::from), force_rerun: matches.opt_present("force-rerun"), From c18cd270b4afd9e9657cdd8382f475a19be54c1f Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 3 Dec 2025 09:23:52 +0800 Subject: [PATCH 241/585] compiletest: flip `nocapture` to `capture` --- src/tools/compiletest/src/common.rs | 9 ++++++--- src/tools/compiletest/src/executor.rs | 6 +++--- src/tools/compiletest/src/lib.rs | 2 +- src/tools/compiletest/src/rustdoc_gui_test.rs | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index f3bd707c7891..eb1fc55a2624 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -687,9 +687,12 @@ pub struct Config { pub builtin_cfg_names: OnceLock>, pub supported_crate_types: OnceLock>, - /// FIXME: rename this to the more canonical `no_capture`, or better, invert this to `capture` - /// to avoid `!nocapture` double-negatives. - pub nocapture: bool, + /// Should we capture console output that would be printed by test runners via their `stdout` + /// and `stderr` trait objects, or via the custom panic hook. + /// + /// The default is `true`. This can be disabled via the compiletest cli flag `--no-capture` + /// (which mirrors the libtest `--no-capture` flag). + pub capture: bool, /// Needed both to construct [`build_helper::git::GitConfig`]. pub nightly_branch: String, diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index 5a2136c55b05..4dd4b1f85aaa 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -196,10 +196,10 @@ enum CaptureKind { impl CaptureKind { fn for_config(config: &Config) -> Self { - if config.nocapture { - Self::None - } else { + if config.capture { Self::Capture { buf: output_capture::CaptureBuf::new() } + } else { + Self::None } } diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 8b64339c156f..acd0d70d081f 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -476,7 +476,7 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { builtin_cfg_names: OnceLock::new(), supported_crate_types: OnceLock::new(), - nocapture: matches.opt_present("no-capture"), + capture: !matches.opt_present("no-capture"), nightly_branch: matches.opt_str("nightly-branch").unwrap(), git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(), diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index 704f1806f8b7..f6d026ab9cfd 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -130,7 +130,7 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { target_cfgs: Default::default(), builtin_cfg_names: Default::default(), supported_crate_types: Default::default(), - nocapture: Default::default(), + capture: Default::default(), nightly_branch: Default::default(), git_merge_commit_email: Default::default(), profiler_runtime: Default::default(), From 743d27794fb96620c0473183bc847c3c9f6f47f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Dec 2025 13:31:50 +0100 Subject: [PATCH 242/585] powf, powi: point out SNaN non-determinism --- library/core/src/num/f128.rs | 5 +++++ library/core/src/num/f16.rs | 5 +++++ library/std/src/num/f128.rs | 5 +++++ library/std/src/num/f16.rs | 5 +++++ library/std/src/num/f32.rs | 10 ++++++++++ library/std/src/num/f64.rs | 10 ++++++++++ 6 files changed, 40 insertions(+) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 9b9cc80a606c..20353c65d491 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1800,6 +1800,11 @@ pub fn rem_euclid(self, rhs: f128) -> f128 { /// It might have a different sequence of rounding operations than `powf`, /// so the results are not guaranteed to agree. /// + /// Note that this function is special in that it can return non-NaN results for NaN inputs. For + /// example, `f128::powi(f128::NAN, 0)` returns `1.0`. However, if an input is a *signaling* + /// NaN, then the result is non-deterministically either a NaN or the result that the + /// corresponding quiet NaN would produce. + /// /// # Unspecified precision /// /// The precision of this function is non-deterministic. This means it varies by platform, diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index ab765ebcb7fa..823bd4917b3d 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1775,6 +1775,11 @@ pub fn rem_euclid(self, rhs: f16) -> f16 { /// It might have a different sequence of rounding operations than `powf`, /// so the results are not guaranteed to agree. /// + /// Note that this function is special in that it can return non-NaN results for NaN inputs. For + /// example, `f16::powi(f16::NAN, 0)` returns `1.0`. However, if an input is a *signaling* + /// NaN, then the result is non-deterministically either a NaN or the result that the + /// corresponding quiet NaN would produce. + /// /// # Unspecified precision /// /// The precision of this function is non-deterministic. This means it varies by platform, diff --git a/library/std/src/num/f128.rs b/library/std/src/num/f128.rs index 3b787713afa2..6f1fd2975b71 100644 --- a/library/std/src/num/f128.rs +++ b/library/std/src/num/f128.rs @@ -19,6 +19,11 @@ impl f128 { /// Raises a number to a floating point power. /// + /// Note that this function is special in that it can return non-NaN results for NaN inputs. For + /// example, `f128::powf(f128::NAN, 0.0)` returns `1.0`. However, if an input is a *signaling* + /// NaN, then the result is non-deterministically either a NaN or the result that the + /// corresponding quiet NaN would produce. + /// /// # Unspecified precision /// /// The precision of this function is non-deterministic. This means it varies by platform, diff --git a/library/std/src/num/f16.rs b/library/std/src/num/f16.rs index 4af21c95c9ba..20d0b4e1e552 100644 --- a/library/std/src/num/f16.rs +++ b/library/std/src/num/f16.rs @@ -19,6 +19,11 @@ impl f16 { /// Raises a number to a floating point power. /// + /// Note that this function is special in that it can return non-NaN results for NaN inputs. For + /// example, `f16::powf(f16::NAN, 0.0)` returns `1.0`. However, if an input is a *signaling* + /// NaN, then the result is non-deterministically either a NaN or the result that the + /// corresponding quiet NaN would produce. + /// /// # Unspecified precision /// /// The precision of this function is non-deterministic. This means it varies by platform, diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index 09ced388a339..97ae334e1994 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -295,6 +295,11 @@ pub fn rem_euclid(self, rhs: f32) -> f32 { /// It might have a different sequence of rounding operations than `powf`, /// so the results are not guaranteed to agree. /// + /// Note that this function is special in that it can return non-NaN results for NaN inputs. For + /// example, `f32::powi(f32::NAN, 0)` returns `1.0`. However, if an input is a *signaling* + /// NaN, then the result is non-deterministically either a NaN or the result that the + /// corresponding quiet NaN would produce. + /// /// # Unspecified precision /// /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and @@ -320,6 +325,11 @@ pub fn powi(self, n: i32) -> f32 { /// Raises a number to a floating point power. /// + /// Note that this function is special in that it can return non-NaN results for NaN inputs. For + /// example, `f32::powf(f32::NAN, 0.0)` returns `1.0`. However, if an input is a *signaling* + /// NaN, then the result is non-deterministically either a NaN or the result that the + /// corresponding quiet NaN would produce. + /// /// # Unspecified precision /// /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 79adf076e4b1..aaeaa86ca77e 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -295,6 +295,11 @@ pub fn rem_euclid(self, rhs: f64) -> f64 { /// It might have a different sequence of rounding operations than `powf`, /// so the results are not guaranteed to agree. /// + /// Note that this function is special in that it can return non-NaN results for NaN inputs. For + /// example, `f64::powi(f64::NAN, 0)` returns `1.0`. However, if an input is a *signaling* + /// NaN, then the result is non-deterministically either a NaN or the result that the + /// corresponding quiet NaN would produce. + /// /// # Unspecified precision /// /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and @@ -320,6 +325,11 @@ pub fn powi(self, n: i32) -> f64 { /// Raises a number to a floating point power. /// + /// Note that this function is special in that it can return non-NaN results for NaN inputs. For + /// example, `f64::powf(f64::NAN, 0.0)` returns `1.0`. However, if an input is a *signaling* + /// NaN, then the result is non-deterministically either a NaN or the result that the + /// corresponding quiet NaN would produce. + /// /// # Unspecified precision /// /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and From 0ab78c152300499d0c17344e4e12d299313910e7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 3 Dec 2025 12:21:03 +0000 Subject: [PATCH 243/585] `is_const_default_method` is completely handled by the `constness` query --- compiler/rustc_const_eval/src/check_consts/mod.rs | 6 ++++-- compiler/rustc_metadata/src/rmeta/encoder.rs | 3 +-- compiler/rustc_middle/src/hir/map.rs | 1 - compiler/rustc_middle/src/ty/mod.rs | 5 ----- compiler/rustc_mir_transform/src/lib.rs | 3 +-- 5 files changed, 6 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 4a88d039ef3c..e9824400ab7a 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -95,8 +95,10 @@ pub fn rustc_allow_const_fn_unstable( /// unstable features, not even recursively), and those that are not. pub fn is_fn_or_trait_safe_to_expose_on_stable(tcx: TyCtxt<'_>, def_id: DefId) -> bool { // A default body in a `const trait` is const-stable when the trait is const-stable. - if tcx.is_const_default_method(def_id) { - return is_fn_or_trait_safe_to_expose_on_stable(tcx, tcx.parent(def_id)); + if let Some(trait_id) = tcx.trait_of_assoc(def_id) + && tcx.is_const_trait(trait_id) + { + return is_fn_or_trait_safe_to_expose_on_stable(tcx, trait_id); } match tcx.lookup_const_stability(def_id) { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 9fac68039f52..4085fd5e70f1 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1132,8 +1132,7 @@ fn should_encode_mir( && (generics.requires_monomorphization(tcx) || tcx.cross_crate_inlinable(def_id))); // The function has a `const` modifier or is in a `const trait`. - let is_const_fn = tcx.is_const_fn(def_id.to_def_id()) - || tcx.is_const_default_method(def_id.to_def_id()); + let is_const_fn = tcx.is_const_fn(def_id.to_def_id()); (is_const_fn, opt) } // The others don't have MIR. diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 430cd329408f..bf3192d9df17 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -321,7 +321,6 @@ pub fn hir_body_const_context(self, def_id: LocalDefId) -> Option BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.is_const_fn(def_id) => { ConstContext::ConstFn } - BodyOwnerKind::Fn if self.is_const_default_method(def_id) => ConstContext::ConstFn, BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None, }; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 61b3059ab425..d3e0fbb955c4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2224,11 +2224,6 @@ pub fn is_const_trait(self, def_id: DefId) -> bool { self.trait_def(def_id).constness == hir::Constness::Const } - #[inline] - pub fn is_const_default_method(self, def_id: DefId) -> bool { - matches!(self.trait_of_assoc(def_id), Some(trait_id) if self.is_const_trait(trait_id)) - } - pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool { if self.def_kind(def_id) != DefKind::AssocFn { return false; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 18b798c01faa..9a964d5e01bb 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -429,8 +429,7 @@ fn mir_promoted( let const_qualifs = match tcx.def_kind(def) { DefKind::Fn | DefKind::AssocFn | DefKind::Closure - if tcx.constness(def) == hir::Constness::Const - || tcx.is_const_default_method(def.to_def_id()) => + if tcx.constness(def) == hir::Constness::Const => { tcx.mir_const_qualif(def) } From bf0970f0fa717eeebb62b9592fbadafcace0efa0 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Tue, 2 Dec 2025 13:21:33 +0100 Subject: [PATCH 244/585] add one more test for type ascription of never --- tests/ui/reachable/type_ascribe_never_field.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/ui/reachable/type_ascribe_never_field.rs diff --git a/tests/ui/reachable/type_ascribe_never_field.rs b/tests/ui/reachable/type_ascribe_never_field.rs new file mode 100644 index 000000000000..2788d30414e6 --- /dev/null +++ b/tests/ui/reachable/type_ascribe_never_field.rs @@ -0,0 +1,17 @@ +// Regression test for +// +// Checks that type ascription of a field place with type never is correctly +// checked for if it constitutes a read of type never. (it doesn't) +// +//@ check-pass + +#![feature(never_type)] +#![feature(type_ascription)] +#![deny(unreachable_code)] + +fn main() { + let x: (!,); + let _ = type_ascribe!(x.0, _); + + (); // reachable +} From 5e802dd1a1723b21ffcff3af7b7fb9169f18ab42 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 3 Dec 2025 23:18:11 +0900 Subject: [PATCH 245/585] moved and deleted test tests/ui/issues/issue-4935 is duplicated of tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs --- tests/ui/issues/issue-4935.rs | 7 ------- tests/ui/issues/issue-4935.stderr | 20 ------------------- .../assignment-mismatch-various-types.rs} | 0 .../assignment-mismatch-various-types.stderr} | 0 .../debug-print-basic-tuple.rs} | 0 .../ambiguous-num-type-method-call.rs} | 0 .../ambiguous-num-type-method-call.stderr} | 0 .../type-inference-unconstrained-none-2.rs} | 0 ...ype-inference-unconstrained-none-2.stderr} | 0 9 files changed, 27 deletions(-) delete mode 100644 tests/ui/issues/issue-4935.rs delete mode 100644 tests/ui/issues/issue-4935.stderr rename tests/ui/{issues/issue-3477.rs => mismatched_types/assignment-mismatch-various-types.rs} (100%) rename tests/ui/{issues/issue-3477.stderr => mismatched_types/assignment-mismatch-various-types.stderr} (100%) rename tests/ui/{issues/issue-3109.rs => str/debug-print-basic-tuple.rs} (100%) rename tests/ui/{issues/issue-51874.rs => type-inference/ambiguous-num-type-method-call.rs} (100%) rename tests/ui/{issues/issue-51874.stderr => type-inference/ambiguous-num-type-method-call.stderr} (100%) rename tests/ui/{issues/issue-5062.rs => type-inference/type-inference-unconstrained-none-2.rs} (100%) rename tests/ui/{issues/issue-5062.stderr => type-inference/type-inference-unconstrained-none-2.stderr} (100%) diff --git a/tests/ui/issues/issue-4935.rs b/tests/ui/issues/issue-4935.rs deleted file mode 100644 index ef8a3eb32abb..000000000000 --- a/tests/ui/issues/issue-4935.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Regression test for issue #4935 - -fn foo(a: usize) {} -//~^ NOTE defined here -fn main() { foo(5, 6) } -//~^ ERROR function takes 1 argument but 2 arguments were supplied -//~| NOTE unexpected argument #2 of type `{integer}` diff --git a/tests/ui/issues/issue-4935.stderr b/tests/ui/issues/issue-4935.stderr deleted file mode 100644 index 918f74256c03..000000000000 --- a/tests/ui/issues/issue-4935.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0061]: this function takes 1 argument but 2 arguments were supplied - --> $DIR/issue-4935.rs:5:13 - | -LL | fn main() { foo(5, 6) } - | ^^^ - unexpected argument #2 of type `{integer}` - | -note: function defined here - --> $DIR/issue-4935.rs:3:4 - | -LL | fn foo(a: usize) {} - | ^^^ -help: remove the extra argument - | -LL - fn main() { foo(5, 6) } -LL + fn main() { foo(5) } - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0061`. diff --git a/tests/ui/issues/issue-3477.rs b/tests/ui/mismatched_types/assignment-mismatch-various-types.rs similarity index 100% rename from tests/ui/issues/issue-3477.rs rename to tests/ui/mismatched_types/assignment-mismatch-various-types.rs diff --git a/tests/ui/issues/issue-3477.stderr b/tests/ui/mismatched_types/assignment-mismatch-various-types.stderr similarity index 100% rename from tests/ui/issues/issue-3477.stderr rename to tests/ui/mismatched_types/assignment-mismatch-various-types.stderr diff --git a/tests/ui/issues/issue-3109.rs b/tests/ui/str/debug-print-basic-tuple.rs similarity index 100% rename from tests/ui/issues/issue-3109.rs rename to tests/ui/str/debug-print-basic-tuple.rs diff --git a/tests/ui/issues/issue-51874.rs b/tests/ui/type-inference/ambiguous-num-type-method-call.rs similarity index 100% rename from tests/ui/issues/issue-51874.rs rename to tests/ui/type-inference/ambiguous-num-type-method-call.rs diff --git a/tests/ui/issues/issue-51874.stderr b/tests/ui/type-inference/ambiguous-num-type-method-call.stderr similarity index 100% rename from tests/ui/issues/issue-51874.stderr rename to tests/ui/type-inference/ambiguous-num-type-method-call.stderr diff --git a/tests/ui/issues/issue-5062.rs b/tests/ui/type-inference/type-inference-unconstrained-none-2.rs similarity index 100% rename from tests/ui/issues/issue-5062.rs rename to tests/ui/type-inference/type-inference-unconstrained-none-2.rs diff --git a/tests/ui/issues/issue-5062.stderr b/tests/ui/type-inference/type-inference-unconstrained-none-2.stderr similarity index 100% rename from tests/ui/issues/issue-5062.stderr rename to tests/ui/type-inference/type-inference-unconstrained-none-2.stderr From 07b1dadf86041aa058a798e52d012ab2bbb85e39 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 3 Dec 2025 23:24:39 +0900 Subject: [PATCH 246/585] Added comment to `tests/ui/type-inference/ambiguous-num-type-method-call.rs` --- tests/ui/type-inference/ambiguous-num-type-method-call.rs | 2 ++ tests/ui/type-inference/ambiguous-num-type-method-call.stderr | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/ui/type-inference/ambiguous-num-type-method-call.rs b/tests/ui/type-inference/ambiguous-num-type-method-call.rs index d9d7e36b50e9..ee3c95ba0843 100644 --- a/tests/ui/type-inference/ambiguous-num-type-method-call.rs +++ b/tests/ui/type-inference/ambiguous-num-type-method-call.rs @@ -1,3 +1,5 @@ +//! regression test for + fn main() { let a = (1.0).pow(1.0); //~ ERROR can't call method `pow` on ambiguous numeric type } diff --git a/tests/ui/type-inference/ambiguous-num-type-method-call.stderr b/tests/ui/type-inference/ambiguous-num-type-method-call.stderr index 5c9331b4e1e1..3a808c06aef1 100644 --- a/tests/ui/type-inference/ambiguous-num-type-method-call.stderr +++ b/tests/ui/type-inference/ambiguous-num-type-method-call.stderr @@ -1,5 +1,5 @@ error[E0689]: can't call method `pow` on ambiguous numeric type `{float}` - --> $DIR/issue-51874.rs:2:19 + --> $DIR/ambiguous-num-type-method-call.rs:4:19 | LL | let a = (1.0).pow(1.0); | ^^^ From 245096b6aeb99929ebf2c8da8b7f8d83f74cc97d Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 3 Dec 2025 23:38:42 +0900 Subject: [PATCH 247/585] Added comment to `tests/ui/mismatched_types/assignment-mismatch-various-types.rs` merge `tests/ui/mismatched_types/main.rs` --- .../assignment-mismatch-various-types.rs | 7 +++++-- .../assignment-mismatch-various-types.stderr | 12 ++++++++++-- tests/ui/mismatched_types/main.rs | 4 ---- tests/ui/mismatched_types/main.stderr | 13 ------------- 4 files changed, 15 insertions(+), 21 deletions(-) delete mode 100644 tests/ui/mismatched_types/main.rs delete mode 100644 tests/ui/mismatched_types/main.stderr diff --git a/tests/ui/mismatched_types/assignment-mismatch-various-types.rs b/tests/ui/mismatched_types/assignment-mismatch-various-types.rs index eb94294d5a87..903bfd9756f0 100644 --- a/tests/ui/mismatched_types/assignment-mismatch-various-types.rs +++ b/tests/ui/mismatched_types/assignment-mismatch-various-types.rs @@ -1,6 +1,9 @@ +//! regression test for + fn main() { + let x: u32 = (); + //~^ ERROR mismatched types + let _p: char = 100; //~^ ERROR mismatched types - //~| NOTE expected `char`, found `u8` - //~| NOTE expected due to this } diff --git a/tests/ui/mismatched_types/assignment-mismatch-various-types.stderr b/tests/ui/mismatched_types/assignment-mismatch-various-types.stderr index 2a4d6d2449ed..14356fe16d3d 100644 --- a/tests/ui/mismatched_types/assignment-mismatch-various-types.stderr +++ b/tests/ui/mismatched_types/assignment-mismatch-various-types.stderr @@ -1,11 +1,19 @@ error[E0308]: mismatched types - --> $DIR/issue-3477.rs:2:20 + --> $DIR/assignment-mismatch-various-types.rs:4:18 + | +LL | let x: u32 = (); + | --- ^^ expected `u32`, found `()` + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/assignment-mismatch-various-types.rs:7:20 | LL | let _p: char = 100; | ---- ^^^ expected `char`, found `u8` | | | expected due to this -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/main.rs b/tests/ui/mismatched_types/main.rs deleted file mode 100644 index e2d09dc21992..000000000000 --- a/tests/ui/mismatched_types/main.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let x: u32 = ( //~ ERROR mismatched types - ); -} diff --git a/tests/ui/mismatched_types/main.stderr b/tests/ui/mismatched_types/main.stderr deleted file mode 100644 index 38146cef3475..000000000000 --- a/tests/ui/mismatched_types/main.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/main.rs:2:18 - | -LL | let x: u32 = ( - | ____________---___^ - | | | - | | expected due to this -LL | | ); - | |_____^ expected `u32`, found `()` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. From cc230fb7636306e92c55c9c9b2ec9086cd2ebc5c Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 3 Dec 2025 23:40:06 +0900 Subject: [PATCH 248/585] Added comment to `tests\ui\str\debug-print-basic-tuple.rs` --- tests/ui/str/debug-print-basic-tuple.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/str/debug-print-basic-tuple.rs b/tests/ui/str/debug-print-basic-tuple.rs index 89beaa222273..7e2b86f56293 100644 --- a/tests/ui/str/debug-print-basic-tuple.rs +++ b/tests/ui/str/debug-print-basic-tuple.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass pub fn main() { println!("{:?}", ("hi there!", "you")); From d1bc6e3459bee4c318371b282d5e0a284e57d279 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 3 Dec 2025 23:43:21 +0900 Subject: [PATCH 249/585] Merged `tests\ui\type-inference\type-inference-unconstrained-none.rs` --- .../type-inference-unconstrained-none-2.rs | 2 -- .../type-inference-unconstrained-none-2.stderr | 14 -------------- .../type-inference-unconstrained-none.rs | 4 ++++ .../type-inference-unconstrained-none.stderr | 15 +++++++++++++-- 4 files changed, 17 insertions(+), 18 deletions(-) delete mode 100644 tests/ui/type-inference/type-inference-unconstrained-none-2.rs delete mode 100644 tests/ui/type-inference/type-inference-unconstrained-none-2.stderr diff --git a/tests/ui/type-inference/type-inference-unconstrained-none-2.rs b/tests/ui/type-inference/type-inference-unconstrained-none-2.rs deleted file mode 100644 index 2db0a8e25b46..000000000000 --- a/tests/ui/type-inference/type-inference-unconstrained-none-2.rs +++ /dev/null @@ -1,2 +0,0 @@ -fn main() { format!("{:?}", None); } - //~^ ERROR type annotations needed [E0282] diff --git a/tests/ui/type-inference/type-inference-unconstrained-none-2.stderr b/tests/ui/type-inference/type-inference-unconstrained-none-2.stderr deleted file mode 100644 index 0839ece79aaf..000000000000 --- a/tests/ui/type-inference/type-inference-unconstrained-none-2.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/issue-5062.rs:1:29 - | -LL | fn main() { format!("{:?}", None); } - | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option` - | -help: consider specifying the generic argument - | -LL | fn main() { format!("{:?}", None::); } - | +++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/type-inference/type-inference-unconstrained-none.rs b/tests/ui/type-inference/type-inference-unconstrained-none.rs index 38a506763c76..5b24e866b521 100644 --- a/tests/ui/type-inference/type-inference-unconstrained-none.rs +++ b/tests/ui/type-inference/type-inference-unconstrained-none.rs @@ -1,5 +1,9 @@ //! Regression test for . +fn foo() { + format!("{:?}", None); //~ ERROR type annotations needed [E0282] +} + fn main() { None; //~ ERROR type annotations needed [E0282] } diff --git a/tests/ui/type-inference/type-inference-unconstrained-none.stderr b/tests/ui/type-inference/type-inference-unconstrained-none.stderr index 80572b845e84..54260c03b76a 100644 --- a/tests/ui/type-inference/type-inference-unconstrained-none.stderr +++ b/tests/ui/type-inference/type-inference-unconstrained-none.stderr @@ -1,5 +1,16 @@ error[E0282]: type annotations needed - --> $DIR/type-inference-unconstrained-none.rs:4:5 + --> $DIR/type-inference-unconstrained-none.rs:4:21 + | +LL | format!("{:?}", None); + | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option` + | +help: consider specifying the generic argument + | +LL | format!("{:?}", None::); + | +++++ + +error[E0282]: type annotations needed + --> $DIR/type-inference-unconstrained-none.rs:8:5 | LL | None; | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option` @@ -9,6 +20,6 @@ help: consider specifying the generic argument LL | None::; | +++++ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0282`. From b3bf3158ec32b1a2a957228bae36f1b7cfc3fa2a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 2 Dec 2025 16:33:47 +0000 Subject: [PATCH 250/585] Disable native-lib for x check miri This reduces check times for miri from 2m15s to 20s. And reduces check times for miri with --compile-time-deps from 1m50s to 7s. This makes rust-analyzer start a lot faster after switching branches. --- src/bootstrap/src/core/build_steps/check.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index aebdc2a6a92a..df82b7baa9f9 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -662,6 +662,7 @@ macro_rules! tool_check_step { $(, allow_features: $allow_features:expr )? // Features that should be enabled when checking $(, enable_features: [$($enable_features:expr),*] )? + $(, default_features: $default_features:expr )? $(, default: $default:literal )? $( , )? } @@ -708,8 +709,13 @@ fn run(self, builder: &Builder<'_>) { _value }; let extra_features: &[&str] = &[$($($enable_features),*)?]; + let default_features = { + let mut _value = true; + $( _value = $default_features; )? + _value + }; let mode: Mode = $mode; - run_tool_check_step(builder, compiler, target, $path, mode, allow_features, extra_features); + run_tool_check_step(builder, compiler, target, $path, mode, allow_features, extra_features, default_features); } fn metadata(&self) -> Option { @@ -720,6 +726,7 @@ fn metadata(&self) -> Option { } /// Used by the implementation of `Step::run` in `tool_check_step!`. +#[allow(clippy::too_many_arguments)] fn run_tool_check_step( builder: &Builder<'_>, compiler: CompilerForCheck, @@ -728,6 +735,7 @@ fn run_tool_check_step( mode: Mode, allow_features: &str, extra_features: &[&str], + default_features: bool, ) { let display_name = path.rsplit('/').next().unwrap(); @@ -761,6 +769,10 @@ fn run_tool_check_step( cargo.arg("--all-targets"); } + if !default_features { + cargo.arg("--no-default-features"); + } + let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, mode, target)) .with_prefix(&format!("{display_name}-check")); @@ -778,7 +790,12 @@ fn run_tool_check_step( // behavior, treat it as in-tree so that any new warnings in clippy will be // rejected. tool_check_step!(Clippy { path: "src/tools/clippy", mode: Mode::ToolRustcPrivate }); -tool_check_step!(Miri { path: "src/tools/miri", mode: Mode::ToolRustcPrivate }); +tool_check_step!(Miri { + path: "src/tools/miri", + mode: Mode::ToolRustcPrivate, + enable_features: ["stack-cache"], + default_features: false, +}); tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: Mode::ToolRustcPrivate }); tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: Mode::ToolRustcPrivate }); tool_check_step!(RustAnalyzer { From 6f632ef2430f34523a19b90f574e288646225e9b Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 8 Oct 2025 03:25:43 +0100 Subject: [PATCH 251/585] non-behaviour changing cleanups --- compiler/rustc_hir_typeck/src/coercion.rs | 241 +++++++----------- ...structural_identity_dependent_reborrows.rs | 24 ++ ...ctural_identity_dependent_reborrows.stderr | 25 ++ 3 files changed, 140 insertions(+), 150 deletions(-) create mode 100644 tests/ui/coercion/structural_identity_dependent_reborrows.rs create mode 100644 tests/ui/coercion/structural_identity_dependent_reborrows.stderr diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 009caad51eac..bcff4eeb71b3 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -179,7 +179,7 @@ fn unify_and( }) } - #[instrument(skip(self))] + #[instrument(skip(self), ret)] fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { // First, remove any resolved type variables (at the top level, at least): let a = self.shallow_resolve(a); @@ -223,21 +223,20 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { } } - // Examine the supertype and consider type-specific coercions, such - // as auto-borrowing, coercing pointer mutability, a `dyn*` coercion, - // or pin-ergonomics. + // Examine the target type and consider type-specific coercions, such + // as auto-borrowing, coercing pointer mutability, or pin-ergonomics. match *b.kind() { ty::RawPtr(_, b_mutbl) => { - return self.coerce_raw_ptr(a, b, b_mutbl); + return self.coerce_to_raw_ptr(a, b, b_mutbl); } ty::Ref(r_b, _, mutbl_b) => { - return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b); + return self.coerce_to_ref(a, b, mutbl_b, r_b); } ty::Adt(pin, _) if self.tcx.features().pin_ergonomics() && self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => { - let pin_coerce = self.commit_if_ok(|_| self.coerce_pin_ref(a, b)); + let pin_coerce = self.commit_if_ok(|_| self.coerce_to_pin_ref(a, b)); if pin_coerce.is_ok() { return pin_coerce; } @@ -281,22 +280,21 @@ fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResu debug_assert!(self.shallow_resolve(b) == b); if b.is_ty_var() { - // Two unresolved type variables: create a `Coerce` predicate. - let target_ty = if self.use_lub { self.next_ty_var(self.cause.span) } else { b }; - let mut obligations = PredicateObligations::with_capacity(2); - for &source_ty in &[a, b] { - if source_ty != target_ty { - obligations.push(Obligation::new( - self.tcx(), - self.cause.clone(), - self.param_env, - ty::Binder::dummy(ty::PredicateKind::Coerce(ty::CoercePredicate { - a: source_ty, - b: target_ty, - })), - )); - } + let mut push_coerce_obligation = |a, b| { + obligations.push(Obligation::new( + self.tcx(), + self.cause.clone(), + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Coerce(ty::CoercePredicate { a, b })), + )); + }; + + let target_ty = self.use_lub.then(|| self.next_ty_var(self.cause.span)).unwrap_or(b); + + push_coerce_obligation(a, target_ty); + if self.use_lub { + push_coerce_obligation(b, target_ty); } debug!( @@ -311,159 +309,99 @@ fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResu } } - /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. - /// To match `A` with `B`, autoderef will be performed, - /// calling `deref`/`deref_mut` where necessary. - fn coerce_borrowed_pointer( + /// Handles coercing some arbitrary type `a` to some reference (`b`). This + /// handles a few cases: + /// - Introducing reborrows to give more flexible lifetimes + /// - Deref coercions to allow `&T` to coerce to `&T::Target` + /// - Coercing mutable references to immutable references + /// These coercions can be freely intermixed, for example we are able to + /// coerce `&mut T` to `&mut T::Target`. + fn coerce_to_ref( &self, a: Ty<'tcx>, b: Ty<'tcx>, - r_b: ty::Region<'tcx>, mutbl_b: hir::Mutability, + r_b: ty::Region<'tcx>, ) -> CoerceResult<'tcx> { - debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); + debug!("coerce_to_ref(a={:?}, b={:?})", a, b); debug_assert!(self.shallow_resolve(a) == a); debug_assert!(self.shallow_resolve(b) == b); - // If we have a parameter of type `&M T_a` and the value - // provided is `expr`, we will be adding an implicit borrow, - // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore, - // to type check, we will construct the type that `&M*expr` would - // yield. - let (r_a, mt_a) = match *a.kind() { ty::Ref(r_a, ty, mutbl) => { - let mt_a = ty::TypeAndMut { ty, mutbl }; - coerce_mutbls(mt_a.mutbl, mutbl_b)?; - (r_a, mt_a) + coerce_mutbls(mutbl, mutbl_b)?; + (r_a, ty::TypeAndMut { ty, mutbl }) } _ => return self.unify(a, b), }; - let span = self.cause.span; - + // Look at each step in the `Deref` chain and check if + // any of the autoref'd `Target` types unify with the + // coercion target. + // + // For example when coercing from `&mut Vec` to `&M [T]` we + // have three deref steps: + // 1. `&mut Vec`, skip autoref + // 2. `Vec`, autoref'd ty: `&M Vec` + // - `&M Vec` does not unify with `&M [T]` + // 3. `[T]`, autoref'd ty: `&M [T]` + // - `&M [T]` does unify with `&M [T]` let mut first_error = None; let mut r_borrow_var = None; - let mut autoderef = self.autoderef(span, a); - let mut found = None; - - for (referent_ty, autoderefs) in autoderef.by_ref() { + let mut autoderef = self.autoderef(self.cause.span, a); + let found = autoderef.by_ref().find_map(|(deref_ty, autoderefs)| { if autoderefs == 0 { - // Don't let this pass, otherwise it would cause - // &T to autoref to &&T. - continue; + // Don't autoref the first step as otherwise we'd allow + // coercing `&T` to `&&T`. + return None; } - // At this point, we have deref'd `a` to `referent_ty`. So - // imagine we are coercing from `&'a mut Vec` to `&'b mut [T]`. - // In the autoderef loop for `&'a mut Vec`, we would get - // three callbacks: + // The logic here really shouldn't exist. We don't care about free + // lifetimes during HIR typeck. Unfortunately later parts of this + // function rely on structural identity of the autoref'd deref'd ty. // - // - `&'a mut Vec` -- 0 derefs, just ignore it - // - `Vec` -- 1 deref - // - `[T]` -- 2 deref - // - // At each point after the first callback, we want to - // check to see whether this would match out target type - // (`&'b mut [T]`) if we autoref'd it. We can't just - // compare the referent types, though, because we still - // have to consider the mutability. E.g., in the case - // we've been considering, we have an `&mut` reference, so - // the `T` in `[T]` needs to be unified with equality. - // - // Therefore, we construct reference types reflecting what - // the types will be after we do the final auto-ref and - // compare those. Note that this means we use the target - // mutability [1], since it may be that we are coercing - // from `&mut T` to `&U`. - // - // One fine point concerns the region that we use. We - // choose the region such that the region of the final - // type that results from `unify` will be the region we - // want for the autoref: - // - // - if in sub mode, that means we want to use `'b` (the - // region from the target reference) for both - // pointers [2]. This is because sub mode (somewhat - // arbitrarily) returns the subtype region. In the case - // where we are coercing to a target type, we know we - // want to use that target type region (`'b`) because -- - // for the program to type-check -- it must be the - // smaller of the two. - // - One fine point. It may be surprising that we can - // use `'b` without relating `'a` and `'b`. The reason - // that this is ok is that what we produce is - // effectively a `&'b *x` expression (if you could - // annotate the region of a borrow), and regionck has - // code that adds edges from the region of a borrow - // (`'b`, here) into the regions in the borrowed - // expression (`*x`, here). (Search for "link".) - // - if in lub mode, things can get fairly complicated. The - // easiest thing is just to make a fresh - // region variable [4], which effectively means we defer - // the decision to region inference (and regionck, which will add - // some more edges to this variable). However, this can wind up - // creating a crippling number of variables in some cases -- - // e.g., #32278 -- so we optimize one particular case [3]. - // Let me try to explain with some examples: - // - The "running example" above represents the simple case, - // where we have one `&` reference at the outer level and - // ownership all the rest of the way down. In this case, - // we want `LUB('a, 'b)` as the resulting region. - // - However, if there are nested borrows, that region is - // too strong. Consider a coercion from `&'a &'x Rc` to - // `&'b T`. In this case, `'a` is actually irrelevant. - // The pointer we want is `LUB('x, 'b`). If we choose `LUB('a,'b)` - // we get spurious errors (`ui/regions-lub-ref-ref-rc.rs`). - // (The errors actually show up in borrowck, typically, because - // this extra edge causes the region `'a` to be inferred to something - // too big, which then results in borrowck errors.) - // - We could track the innermost shared reference, but there is already - // code in regionck that has the job of creating links between - // the region of a borrow and the regions in the thing being - // borrowed (here, `'a` and `'x`), and it knows how to handle - // all the various cases. So instead we just make a region variable - // and let regionck figure it out. + // This means that what region we use here actually impacts whether + // we emit a reborrow coercion or not which can affect diagnostics + // and capture analysis (which in turn affects borrowck). let r = if !self.use_lub { - r_b // [2] above + r_b } else if autoderefs == 1 { - r_a // [3] above + r_a } else { if r_borrow_var.is_none() { // create var lazily, at most once - let coercion = RegionVariableOrigin::Coercion(span); + let coercion = RegionVariableOrigin::Coercion(self.cause.span); let r = self.next_region_var(coercion); - r_borrow_var = Some(r); // [4] above + r_borrow_var = Some(r); } r_borrow_var.unwrap() }; - let derefd_ty_a = Ty::new_ref( - self.tcx, - r, - referent_ty, - mutbl_b, // [1] above - ); - match self.unify_raw(derefd_ty_a, b) { - Ok(ok) => { - found = Some(ok); - break; - } + + let autorefd_deref_ty = Ty::new_ref(self.tcx, r, deref_ty, mutbl_b); + + // Note that we unify the autoref'd `Target` type with `b` rather than + // the `Target` type with the pointee of `b`. This is necessary + // to properly account for the differing variances of the pointees + // of `&` vs `&mut` references. + match self.unify_raw(autorefd_deref_ty, b) { + Ok(ok) => Some(ok), Err(err) => { if first_error.is_none() { first_error = Some(err); } + None } } - } + }); // Extract type or return an error. We return the first error // we got, which should be from relating the "base" type // (e.g., in example above, the failure from relating `Vec` // to the target type), since that should be the least // confusing. - let Some(InferOk { value: ty, mut obligations }) = found else { + let Some(InferOk { value: coerced_a, mut obligations }) = found else { if let Some(first_error) = first_error { - debug!("coerce_borrowed_pointer: failed with err = {:?}", first_error); + debug!("coerce_to_ref: failed with err = {:?}", first_error); return Err(first_error); } else { // This may happen in the new trait solver since autoderef requires @@ -475,11 +413,15 @@ fn coerce_borrowed_pointer( } }; - if ty == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 { + if coerced_a == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 { // As a special case, if we would produce `&'a *x`, that's // a total no-op. We end up with the type `&'a T` just as - // we started with. In that case, just skip it - // altogether. This is just an optimization. + // we started with. In that case, just skip it altogether. + // + // Unfortunately, this can actually effect capture analysis + // which in turn means this effects borrow checking. This can + // also effect diagnostics. + // FIXME(BoxyUwU): we should always emit reborrow coercions // // Note that for `&mut`, we DO want to reborrow -- // otherwise, this would be a move, which might be an @@ -488,7 +430,7 @@ fn coerce_borrowed_pointer( // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, // which is a borrow. assert!(mutbl_b.is_not()); // can only coerce &T -> &U - return success(vec![], ty, obligations); + return success(vec![], coerced_a, obligations); } let InferOk { value: mut adjustments, obligations: o } = @@ -496,17 +438,17 @@ fn coerce_borrowed_pointer( obligations.extend(o); obligations.extend(autoderef.into_obligations()); - // Now apply the autoref. We have to extract the region out of - // the final ref type we got. - let ty::Ref(..) = ty.kind() else { - span_bug!(span, "expected a ref type, got {:?}", ty); + // Now apply the autoref + let ty::Ref(..) = coerced_a.kind() else { + span_bug!(self.cause.span, "expected a ref type, got {:?}", coerced_a); }; let mutbl = AutoBorrowMutability::new(mutbl_b, self.allow_two_phase); - adjustments.push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)), target: ty }); + adjustments + .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)), target: coerced_a }); - debug!("coerce_borrowed_pointer: succeeded ty={:?} adjustments={:?}", ty, adjustments); + debug!("coerce_to_ref: succeeded coerced_a={:?} adjustments={:?}", coerced_a, adjustments); - success(adjustments, ty, obligations) + success(adjustments, coerced_a, obligations) } /// Performs [unsized coercion] by emulating a fulfillment loop on a @@ -569,9 +511,8 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc | ty::Tuple(_) => return Err(TypeError::Mismatch), _ => {} } - // Additionally, we ignore `&str -> &str` coercions, which happen very - // commonly since strings are one of the most used argument types in Rust, - // we do coercions when type checking call expressions. + // `&str: CoerceUnsized<&str>` does not hold but is encountered frequently + // so we fast path bail out here if let ty::Ref(_, source_pointee, ty::Mutability::Not) = *source.kind() && source_pointee.is_str() && let ty::Ref(_, target_pointee, ty::Mutability::Not) = *target.kind() @@ -810,7 +751,7 @@ fn coerce_unsized_old_solver( /// - `Pin>` as `Pin<&T>` /// - `Pin>` as `Pin<&mut T>` #[instrument(skip(self), level = "trace")] - fn coerce_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + fn coerce_to_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { debug_assert!(self.shallow_resolve(a) == a); debug_assert!(self.shallow_resolve(b) == b); @@ -1013,13 +954,13 @@ fn coerce_closure_to_fn( } } - fn coerce_raw_ptr( + fn coerce_to_raw_ptr( &self, a: Ty<'tcx>, b: Ty<'tcx>, mutbl_b: hir::Mutability, ) -> CoerceResult<'tcx> { - debug!("coerce_raw_ptr(a={:?}, b={:?})", a, b); + debug!("coerce_to_raw_ptr(a={:?}, b={:?})", a, b); debug_assert!(self.shallow_resolve(a) == a); debug_assert!(self.shallow_resolve(b) == b); diff --git a/tests/ui/coercion/structural_identity_dependent_reborrows.rs b/tests/ui/coercion/structural_identity_dependent_reborrows.rs new file mode 100644 index 000000000000..60cf28aaf303 --- /dev/null +++ b/tests/ui/coercion/structural_identity_dependent_reborrows.rs @@ -0,0 +1,24 @@ +//@ edition: 2024 + +// We avoid emitting reborrow coercions if it seems like it would +// not result in a different lifetime on the borrow. This can effect +// capture analysis resulting in borrow checking errors. + +fn foo<'a>(b: &'a ()) -> impl Fn() { + || { + expected::<&()>(b); + } +} + +// No reborrow of `b` is emitted which means our closure captures +// `b` by ref resulting in an upvar of `&&'a ()` +fn bar<'a>(b: &'a ()) -> impl Fn() { + || { + //~^ ERROR: closure may outlive the current function + expected::<&'a ()>(b); + } +} + +fn expected(_: T) {} + +fn main() {} diff --git a/tests/ui/coercion/structural_identity_dependent_reborrows.stderr b/tests/ui/coercion/structural_identity_dependent_reborrows.stderr new file mode 100644 index 000000000000..d598a4fa7633 --- /dev/null +++ b/tests/ui/coercion/structural_identity_dependent_reborrows.stderr @@ -0,0 +1,25 @@ +error[E0373]: closure may outlive the current function, but it borrows `b`, which is owned by the current function + --> $DIR/structural_identity_dependent_reborrows.rs:16:5 + | +LL | || { + | ^^ may outlive borrowed value `b` +LL | +LL | expected::<&'a ()>(b); + | - `b` is borrowed here + | +note: closure is returned here + --> $DIR/structural_identity_dependent_reborrows.rs:16:5 + | +LL | / || { +LL | | +LL | | expected::<&'a ()>(b); +LL | | } + | |_____^ +help: to force the closure to take ownership of `b` (and any other referenced variables), use the `move` keyword + | +LL | move || { + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0373`. From 9a1b2e8846fbdcc36f2b435cb6d3e0e661046108 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Fri, 10 Oct 2025 18:03:53 +0100 Subject: [PATCH 252/585] remove normalize call --- compiler/rustc_hir_typeck/src/coercion.rs | 12 ++--- tests/crashes/132765.rs | 12 ----- .../hr_alias_normalization_leaking_vars.rs | 36 +++++++++++++++ ...hr_alias_normalization_leaking_vars.stderr | 46 +++++++++++++++++++ 4 files changed, 87 insertions(+), 19 deletions(-) delete mode 100644 tests/crashes/132765.rs create mode 100644 tests/ui/coercion/hr_alias_normalization_leaking_vars.rs create mode 100644 tests/ui/coercion/hr_alias_normalization_leaking_vars.stderr diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index bcff4eeb71b3..32104a5c0cf7 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -856,9 +856,6 @@ fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { debug_assert!(self.shallow_resolve(a) == a); debug_assert!(self.shallow_resolve(b) == b); - let InferOk { value: b, mut obligations } = - self.at(&self.cause, self.param_env).normalize(b); - match b.kind() { ty::FnPtr(_, b_hdr) => { let mut a_sig = a.fn_sig(self.tcx); @@ -890,9 +887,10 @@ fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { } } - let InferOk { value: a_sig, obligations: o1 } = + // FIXME: we shouldn't be normalizing here as coercion is inside of + // a probe. This can probably cause ICEs. + let InferOk { value: a_sig, mut obligations } = self.at(&self.cause, self.param_env).normalize(a_sig); - obligations.extend(o1); let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn( a_sig, @@ -907,8 +905,8 @@ fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { } } - /// Attempts to coerce from the type of a non-capturing closure - /// into a function pointer. + /// Attempts to coerce from a closure to a function pointer. Fails + /// if the closure has any upvars. fn coerce_closure_to_fn( &self, a: Ty<'tcx>, diff --git a/tests/crashes/132765.rs b/tests/crashes/132765.rs deleted file mode 100644 index 01e8fdaacff7..000000000000 --- a/tests/crashes/132765.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #132765 - -trait LendingIterator { - type Item<'q>; - fn for_each(&self, _f: Box)>) {} -} - -fn f(_: ()) {} - -fn main() { - LendingIterator::for_each(&(), f); -} diff --git a/tests/ui/coercion/hr_alias_normalization_leaking_vars.rs b/tests/ui/coercion/hr_alias_normalization_leaking_vars.rs new file mode 100644 index 000000000000..43678fd876fb --- /dev/null +++ b/tests/ui/coercion/hr_alias_normalization_leaking_vars.rs @@ -0,0 +1,36 @@ +// We have two function parameters with types: +// - `&?0` +// - `Box fn(>::Item)>` +// +// As the alias in the second parameter has a `?0` it is an ambig +// alias, and as it references bound vars it can't be normalized to +// an infer var. +// +// When checking function arguments we try to coerce both: +// - `&()` to `&?0` +// - `FnDef(f)` to `Box fn(>::Item)>` +// +// The first coercion infers `?0=()`. Previously when handling +// the second coercion we wound *re-normalize* the alias, which +// now that `?0` has been inferred allowed us to determine this +// alias is not wellformed and normalize it to some infer var `?1`. +// +// We would then see that `FnDef(f)` can't be coerced to `Box` +// and return a `TypeError` referencing this new variable `?1`. This +// then caused ICEs as diagnostics would encounter inferences variables +// from the result of normalization inside of the probe used be coercion. + + +trait LendingIterator { + type Item<'q>; + fn for_each(&self, _f: Box)>) {} +} + +fn f(_: ()) {} + +fn main() { + LendingIterator::for_each(&(), f); + //~^ ERROR: the trait bound `(): LendingIterator` is not satisfied + //~| ERROR: the trait bound `(): LendingIterator` is not satisfied + //~| ERROR: mismatched types +} diff --git a/tests/ui/coercion/hr_alias_normalization_leaking_vars.stderr b/tests/ui/coercion/hr_alias_normalization_leaking_vars.stderr new file mode 100644 index 000000000000..143cc6b29735 --- /dev/null +++ b/tests/ui/coercion/hr_alias_normalization_leaking_vars.stderr @@ -0,0 +1,46 @@ +error[E0277]: the trait bound `(): LendingIterator` is not satisfied + --> $DIR/hr_alias_normalization_leaking_vars.rs:32:31 + | +LL | LendingIterator::for_each(&(), f); + | ------------------------- ^^^ the trait `LendingIterator` is not implemented for `()` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/hr_alias_normalization_leaking_vars.rs:24:1 + | +LL | trait LendingIterator { + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/hr_alias_normalization_leaking_vars.rs:32:36 + | +LL | LendingIterator::for_each(&(), f); + | ------------------------- ^ expected `Box`, found fn item + | | + | arguments to this function are incorrect + | + = note: expected struct `Box fn(<() as LendingIterator>::Item<'a>)>` + found fn item `fn(()) {f}` +note: method defined here + --> $DIR/hr_alias_normalization_leaking_vars.rs:26:8 + | +LL | fn for_each(&self, _f: Box)>) {} + | ^^^^^^^^ --------------------------- + +error[E0277]: the trait bound `(): LendingIterator` is not satisfied + --> $DIR/hr_alias_normalization_leaking_vars.rs:32:36 + | +LL | LendingIterator::for_each(&(), f); + | ^ the trait `LendingIterator` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/hr_alias_normalization_leaking_vars.rs:24:1 + | +LL | trait LendingIterator { + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. From 12173eba3e86f0c6e2395b418fd2ce5dacd2d58e Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Thu, 6 Nov 2025 18:49:51 +0000 Subject: [PATCH 253/585] explicit leak check enum --- compiler/rustc_hir_typeck/src/coercion.rs | 133 +++++++++++++--------- 1 file changed, 82 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 32104a5c0cf7..9c4c8edd10b7 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -113,6 +113,11 @@ fn success<'tcx>( Ok(InferOk { value: (adj, target), obligations }) } +enum LeakCheck { + Yes, + Default, +} + impl<'f, 'tcx> Coerce<'f, 'tcx> { fn new( fcx: &'f FnCtxt<'f, 'tcx>, @@ -123,9 +128,16 @@ fn new( Coerce { fcx, cause, allow_two_phase, use_lub: false, coerce_never } } - fn unify_raw(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { + fn unify_raw( + &self, + a: Ty<'tcx>, + b: Ty<'tcx>, + leak_check: LeakCheck, + ) -> InferResult<'tcx, Ty<'tcx>> { debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); - self.commit_if_ok(|_| { + self.commit_if_ok(|snapshot| { + let outer_universe = self.infcx.universe(); + let at = self.at(&self.cause, self.fcx.param_env); let res = if self.use_lub { @@ -138,7 +150,7 @@ fn unify_raw(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { // In the new solver, lazy norm may allow us to shallowly equate // more types, but we emit possibly impossible-to-satisfy obligations. // Filter these cases out to make sure our coercion is more accurate. - match res { + let res = match res { Ok(InferOk { value, obligations }) if self.next_trait_solver() => { let ocx = ObligationCtxt::new(self); ocx.register_obligations(obligations); @@ -149,13 +161,35 @@ fn unify_raw(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { } } res => res, + }; + + // We leak check here mostly because lub operations are + // kind of scuffed around binders. Instead of computing an actual + // lub'd binder we instead: + // - Equate the binders + // - Return the lhs of the lub operation + // + // This may lead to incomplete type inference for the resulting type + // of a `match` or `if .. else`, etc. This is a backwards compat + // hazard for if/when we start handling `lub` more correctly. + // + // In order to actually ensure that equating the binders *does* + // result in equal binders, and that the lhs is actually a supertype + // of the rhs, we must perform a leak check here. + // + // FIXME: Type relations should handle leak checks + // themselves whenever a binder is entered. + if matches!(leak_check, LeakCheck::Yes) { + self.leak_check(outer_universe, Some(snapshot))?; } + + res }) } /// Unify two types (using sub or lub). - fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - self.unify_raw(a, b) + fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>, leak_check: LeakCheck) -> CoerceResult<'tcx> { + self.unify_raw(a, b, leak_check) .and_then(|InferOk { value: ty, obligations }| success(vec![], ty, obligations)) } @@ -166,8 +200,9 @@ fn unify_and( b: Ty<'tcx>, adjustments: impl IntoIterator>, final_adjustment: Adjust, + leak_check: LeakCheck, ) -> CoerceResult<'tcx> { - self.unify_raw(a, b).and_then(|InferOk { value: ty, obligations }| { + self.unify_raw(a, b, leak_check).and_then(|InferOk { value: ty, obligations }| { success( adjustments .into_iter() @@ -196,7 +231,7 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { ); } else { // Otherwise the only coercion we can do is unification. - return self.unify(a, b); + return self.unify(a, b, LeakCheck::Default); } } @@ -266,7 +301,7 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { } _ => { // Otherwise, just use unification rules. - self.unify(a, b) + self.unify(a, b, LeakCheck::Default) } } } @@ -305,7 +340,7 @@ fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResu } else { // One unresolved type variable: just apply subtyping, we may be able // to do something useful. - self.unify(a, b) + self.unify(a, b, LeakCheck::Default) } } @@ -332,7 +367,7 @@ fn coerce_to_ref( coerce_mutbls(mutbl, mutbl_b)?; (r_a, ty::TypeAndMut { ty, mutbl }) } - _ => return self.unify(a, b), + _ => return self.unify(a, b, LeakCheck::Default), }; // Look at each step in the `Deref` chain and check if @@ -383,7 +418,7 @@ fn coerce_to_ref( // the `Target` type with the pointee of `b`. This is necessary // to properly account for the differing variances of the pointees // of `&` vs `&mut` references. - match self.unify_raw(autorefd_deref_ty, b) { + match self.unify_raw(autorefd_deref_ty, b, LeakCheck::Default) { Ok(ok) => Some(ok), Err(err) => { if first_error.is_none() { @@ -580,6 +615,7 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc target, reborrow.into_iter().flat_map(|(deref, autoref)| [deref, autoref]), Adjust::Pointer(PointerCoercion::Unsize), + LeakCheck::Default, )?; // Create an obligation for `Source: CoerceUnsized`. @@ -794,7 +830,7 @@ fn coerce_to_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { // To complete the reborrow, we need to make sure we can unify the inner types, and if so we // add the adjustments. - self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b)) + self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b), LeakCheck::Default) } fn coerce_from_safe_fn( @@ -805,39 +841,26 @@ fn coerce_from_safe_fn( ) -> CoerceResult<'tcx> { debug_assert!(self.shallow_resolve(b) == b); - self.commit_if_ok(|snapshot| { - let outer_universe = self.infcx.universe(); - - let result = if let ty::FnPtr(_, hdr_b) = b.kind() - && fn_ty_a.safety().is_safe() - && hdr_b.safety.is_unsafe() - { - let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - self.unify_and( - unsafe_a, - b, - adjustment - .map(|kind| Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }), - Adjust::Pointer(PointerCoercion::UnsafeFnPointer), - ) - } else { - let a = Ty::new_fn_ptr(self.tcx, fn_ty_a); - match adjustment { - Some(adjust) => self.unify_and(a, b, [], adjust), - None => self.unify(a, b), - } - }; - - // FIXME(#73154): This is a hack. Currently LUB can generate - // unsolvable constraints. Additionally, it returns `a` - // unconditionally, even when the "LUB" is `b`. In the future, we - // want the coerced type to be the actual supertype of these two, - // but for now, we want to just error to ensure we don't lock - // ourselves into a specific behavior with NLL. - self.leak_check(outer_universe, Some(snapshot))?; - - result - }) + if let ty::FnPtr(_, hdr_b) = b.kind() + && fn_ty_a.safety().is_safe() + && hdr_b.safety.is_unsafe() + { + let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); + self.unify_and( + unsafe_a, + b, + adjustment + .map(|kind| Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }), + Adjust::Pointer(PointerCoercion::UnsafeFnPointer), + LeakCheck::Yes, + ) + } else { + let a = Ty::new_fn_ptr(self.tcx, fn_ty_a); + match adjustment { + Some(adjust) => self.unify_and(a, b, [], adjust, LeakCheck::Yes), + None => self.unify(a, b, LeakCheck::Yes), + } + } } fn coerce_from_fn_pointer( @@ -901,7 +924,7 @@ fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { obligations.extend(o2); Ok(InferOk { value, obligations }) } - _ => self.unify(a, b), + _ => self.unify(a, b, LeakCheck::Default), } } @@ -946,9 +969,10 @@ fn coerce_closure_to_fn( b, [], Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)), + LeakCheck::Default, ) } - _ => self.unify(a, b), + _ => self.unify(a, b, LeakCheck::Default), } } @@ -965,7 +989,7 @@ fn coerce_to_raw_ptr( let (is_ref, mt_a) = match *a.kind() { ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }), ty::RawPtr(ty, mutbl) => (false, ty::TypeAndMut { ty, mutbl }), - _ => return self.unify(a, b), + _ => return self.unify(a, b, LeakCheck::Default), }; coerce_mutbls(mt_a.mutbl, mutbl_b)?; @@ -980,11 +1004,18 @@ fn coerce_to_raw_ptr( b, [Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }], Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), + LeakCheck::Default, ) } else if mt_a.mutbl != mutbl_b { - self.unify_and(a_raw, b, [], Adjust::Pointer(PointerCoercion::MutToConstPointer)) + self.unify_and( + a_raw, + b, + [], + Adjust::Pointer(PointerCoercion::MutToConstPointer), + LeakCheck::Default, + ) } else { - self.unify(a_raw, b) + self.unify(a_raw, b, LeakCheck::Default) } } } @@ -1083,7 +1114,7 @@ pub(crate) fn deref_steps_for_suggestion( // We don't ever need two-phase here since we throw out the result of the coercion. let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true); coerce.autoderef(DUMMY_SP, expr_ty).find_map(|(ty, steps)| { - self.probe(|_| coerce.unify_raw(ty, target)).ok().map(|_| steps) + self.probe(|_| coerce.unify_raw(ty, target, LeakCheck::Default)).ok().map(|_| steps) }) } From 2676c9363c053302492770ecf429bbd8a6a0b172 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Tue, 28 Oct 2025 17:02:51 +0000 Subject: [PATCH 254/585] Properly handle closure<->closure and fndef<->fndef coerce-lubs - leak checking the lub for fndef<->fndef coerce-lubs - start lubbing closure<->closure coerce-lubs and leak check it --- compiler/rustc_hir_typeck/src/coercion.rs | 84 +++++++++++-------- tests/ui/coercion/issue-88097.rs | 3 + tests/ui/coercion/leak_check_fndef_lub.rs | 32 +++++++ .../leak_check_fndef_lub_deadcode_breakage.rs | 29 +++++++ ...k_check_fndef_lub_deadcode_breakage.stderr | 12 +++ .../lub_closures_before_fnptr_coercion.rs | 70 ++++++++++++++++ 6 files changed, 193 insertions(+), 37 deletions(-) create mode 100644 tests/ui/coercion/leak_check_fndef_lub.rs create mode 100644 tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.rs create mode 100644 tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.stderr create mode 100644 tests/ui/coercion/lub_closures_before_fnptr_coercion.rs diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 9c4c8edd10b7..9aded3f92c76 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1163,8 +1163,9 @@ fn try_find_coercion_lub( exprs.len() ); - // The following check fixes #88097, where the compiler erroneously - // attempted to coerce a closure type to itself via a function pointer. + // Fast Path: don't go through the coercion logic if we're coercing + // a type to itself. This is unfortunately quite perf relevant so + // we do it even though it may mask bugs in the coercion logic. if prev_ty == new_ty { return Ok(prev_ty); } @@ -1193,34 +1194,51 @@ fn try_find_coercion_lub( if is_capturing_closure(prev_ty) || is_capturing_closure(new_ty) { (None, None) } else { - match (prev_ty.kind(), new_ty.kind()) { - (ty::FnDef(..), ty::FnDef(..)) => { - // Don't reify if the function types have a LUB, i.e., they - // are the same function and their parameters have a LUB. - match self.commit_if_ok(|_| { - // We need to eagerly handle nested obligations due to lazy norm. - if self.next_trait_solver() { - let ocx = ObligationCtxt::new(self); - let value = ocx.lub(cause, self.param_env, prev_ty, new_ty)?; - if ocx.try_evaluate_obligations().is_empty() { - Ok(InferOk { - value, - obligations: ocx.into_pending_obligations(), - }) - } else { - Err(TypeError::Mismatch) - } + let lubbed_tys = || { + self.commit_if_ok(|snapshot| { + let outer_universe = self.infcx.universe(); + + // We need to eagerly handle nested obligations due to lazy norm. + let result = if self.next_trait_solver() { + let ocx = ObligationCtxt::new(self); + let value = ocx.lub(cause, self.param_env, prev_ty, new_ty)?; + if ocx.try_evaluate_obligations().is_empty() { + Ok(InferOk { value, obligations: ocx.into_pending_obligations() }) } else { - self.at(cause, self.param_env).lub(prev_ty, new_ty) - } - }) { - // We have a LUB of prev_ty and new_ty, just return it. - Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), - Err(_) => { - (Some(prev_ty.fn_sig(self.tcx)), Some(new_ty.fn_sig(self.tcx))) + Err(TypeError::Mismatch) } + } else { + self.at(cause, self.param_env).lub(prev_ty, new_ty) + }; + + self.leak_check(outer_universe, Some(snapshot))?; + result + }) + }; + + match (prev_ty.kind(), new_ty.kind()) { + // Don't coerce pairs of fndefs or pairs of closures to fn ptrs + // if they can just be lubbed. + // + // See #88097 or `lub_closures_before_fnptr_coercion.rs` for where + // we would erroneously coerce closures to fnptrs when attempting to + // coerce a closure to itself. + (ty::FnDef(..), ty::FnDef(..)) => match lubbed_tys() { + Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), + Err(_) => (Some(prev_ty.fn_sig(self.tcx)), Some(new_ty.fn_sig(self.tcx))), + }, + (ty::Closure(_, args_a), ty::Closure(_, args_b)) => match lubbed_tys() { + Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), + Err(_) => { + let a_sig = self + .tcx + .signature_unclosure(args_a.as_closure().sig(), hir::Safety::Safe); + let b_sig = self + .tcx + .signature_unclosure(args_b.as_closure().sig(), hir::Safety::Safe); + (Some(a_sig), Some(b_sig)) } - } + }, (ty::Closure(_, args), ty::FnDef(..)) => { let b_sig = new_ty.fn_sig(self.tcx); let a_sig = @@ -1233,16 +1251,8 @@ fn try_find_coercion_lub( self.tcx.signature_unclosure(args.as_closure().sig(), a_sig.safety()); (Some(a_sig), Some(b_sig)) } - (ty::Closure(_, args_a), ty::Closure(_, args_b)) => ( - Some( - self.tcx - .signature_unclosure(args_a.as_closure().sig(), hir::Safety::Safe), - ), - Some( - self.tcx - .signature_unclosure(args_b.as_closure().sig(), hir::Safety::Safe), - ), - ), + // ty::FnPtr x ty::FnPtr is fine to just be handled through a normal `unify` + // call using `lub` which is what will happen on the normal path. _ => (None, None), } } diff --git a/tests/ui/coercion/issue-88097.rs b/tests/ui/coercion/issue-88097.rs index f636323d6236..a5804e3b789c 100644 --- a/tests/ui/coercion/issue-88097.rs +++ b/tests/ui/coercion/issue-88097.rs @@ -3,6 +3,9 @@ // behavior has been fixed. //@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver fn peculiar() -> impl Fn(u8) -> u8 { return |x| x + 1 diff --git a/tests/ui/coercion/leak_check_fndef_lub.rs b/tests/ui/coercion/leak_check_fndef_lub.rs new file mode 100644 index 000000000000..b13a62db20be --- /dev/null +++ b/tests/ui/coercion/leak_check_fndef_lub.rs @@ -0,0 +1,32 @@ +//@ check-pass + +fn foo() {} + +fn fndef_lub_leak_check() { + macro_rules! lub { + ($lhs:expr, $rhs:expr) => { + if true { $lhs } else { $rhs } + }; + } + + // These don't currently lub but could in theory one day. + // If that happens this test should be adjusted to use + // fn ptrs that can't be lub'd. + let lhs = foo:: fn(&'static (), &'a ())>; + let rhs = foo:: fn(&'a (), &'static ())>; + + // If we leak check then we know we should coerce these + // to `fn()`, if we don't leak check we may try to keep + // them as `FnDef`s which would result in a borrowck + // error. + let lubbed = lub!(lhs, rhs); + + // assert that we coerced lhs/rhs to a fn ptr + is_fnptr(lubbed); +} + +trait FnPtr {} +impl FnPtr for fn() {} +fn is_fnptr(_: T) {} + +fn main() {} diff --git a/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.rs b/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.rs new file mode 100644 index 000000000000..dda6bd6101c4 --- /dev/null +++ b/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.rs @@ -0,0 +1,29 @@ +fn foo() {} + +fn fndef_lub_leak_check() { + macro_rules! lub { + ($lhs:expr, $rhs:expr) => { + if true { $lhs } else { $rhs } + }; + } + + // These don't currently lub but could in theory one day. + // If that happens this test should be adjusted to use + // fn ptrs that can't be lub'd. + let lhs = foo:: fn(&'static (), &'a ())>; + let rhs = foo:: fn(&'a (), &'static ())>; + + loop {} + + // If we leak check then we know we should coerce these + // to `fn()`, if we don't leak check we may try to keep + // them as `FnDef`s which would cause this code to compile + // as borrowck won't emit errors for deadcode. + let lubbed = lub!(lhs, rhs); + + // assert that `lubbed` is a ZST/`FnDef` + unsafe { std::mem::transmute::<_, ()>(lubbed) } + //~^ ERROR: cannot transmute between types of different sizes +} + +fn main() {} diff --git a/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.stderr b/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.stderr new file mode 100644 index 000000000000..f7336d49e8ca --- /dev/null +++ b/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.stderr @@ -0,0 +1,12 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/leak_check_fndef_lub_deadcode_breakage.rs:25:14 + | +LL | unsafe { std::mem::transmute::<_, ()>(lubbed) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `fn()` (64 bits) + = note: target type: `()` (0 bits) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/coercion/lub_closures_before_fnptr_coercion.rs b/tests/ui/coercion/lub_closures_before_fnptr_coercion.rs new file mode 100644 index 000000000000..b2c421ece570 --- /dev/null +++ b/tests/ui/coercion/lub_closures_before_fnptr_coercion.rs @@ -0,0 +1,70 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +#![feature(type_alias_impl_trait)] + +// Test that when lubbing two equal closure tys with different +// structural identities (i.e. `PartialEq::eq` on `ty::Ty` would be false) +// we don't coerce-lub to a fnptr. +// +// Most of this test is involved jank to be able to leak the hidden type +// of an opaque with a hidden type of `Closure`. This then allows +// us to substitute `C1` and `C2` for arbitrary types in the parent scope. +// +// See: + +struct WaddupGamers(Option, U); +impl, U> Unpin for WaddupGamers {} +unsafe impl, U> Send for WaddupGamers {} +pub trait Leak { + type Unpin; + type Send; +} +impl Leak for (T,) { + type Unpin = T; + type Send = T; +} +fn define() -> impl Sized { + WaddupGamers(None::, || ()) +} + +fn require_unpin(_: T) {} +fn require_send(_: T) {} +fn mk() -> T { todo!() } + +type NameMe = impl Sized; +type NameMe2 = impl Sized; + +#[define_opaque(NameMe, NameMe2)] +fn leak() +where + T: Leak, Send = NameMe2>, +{ + require_unpin(define:: fn(&'a ())>()); + require_send(define:: fn(&'a ())>()); + + // This is the actual logic for lubbing two closures + // with syntactically different `ty::Ty`s: + + // lhs: Closure fn(&'a1 ())> + let lhs = mk::>(); + // lhs: Closure fn(&'a2 ())> + let rhs = mk::>(); + + macro_rules! lub { + ($lhs:expr, $rhs:expr) => { + if true { $lhs } else { $rhs } + }; + } + + // Lubbed to either: + // - `Closure fn(&'a ())>` + // - `fn(&())` + let lubbed = lub!(lhs, rhs); + + // Use transmute to assert the size of `lubbed` is (), i.e. + // that it is a ZST closure type not a fnptr. + unsafe { std::mem::transmute::<_, ()>(lubbed) }; +} + +fn main() {} From 76bd21ad6644dddfabe8720340d18ad829745d07 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Tue, 28 Oct 2025 17:16:51 +0000 Subject: [PATCH 255/585] account for safe target features in fndef<->closure and fndef<->fndef coerce-lubs --- compiler/rustc_borrowck/src/type_check/mod.rs | 9 +- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- .../src/check_consts/check.rs | 2 +- .../rustc_const_eval/src/interpret/cast.rs | 2 +- compiler/rustc_hir_typeck/src/coercion.rs | 377 ++++++++---------- compiler/rustc_middle/src/ty/adjustment.rs | 5 +- compiler/rustc_middle/src/ty/context.rs | 10 +- compiler/rustc_mir_transform/src/gvn.rs | 2 +- .../src/mentioned_items.rs | 2 +- compiler/rustc_mir_transform/src/validate.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 2 +- compiler/rustc_public/src/mir/body.rs | 2 +- .../src/unstable/convert/stable/ty.rs | 4 +- .../clippy_utils/src/qualify_min_const_fn.rs | 2 +- .../build_correct_coerce.main.built.after.mir | 2 +- .../const_prop/reify_fn_ptr.main.GVN.diff | 2 +- tests/mir-opt/const_prop/reify_fn_ptr.rs | 2 +- .../gvn.fn_pointers.GVN.panic-abort.diff | 4 +- .../gvn.fn_pointers.GVN.panic-unwind.diff | 4 +- .../leak_check_fndef_lub_deadcode_breakage.rs | 2 + ...k_check_fndef_lub_deadcode_breakage.stderr | 2 +- .../coercion/lub_coercion_handles_safety.rs | 52 +++ 23 files changed, 266 insertions(+), 229 deletions(-) create mode 100644 tests/ui/coercion/lub_coercion_handles_safety.rs diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 5f86e8646c03..43005fca2984 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1061,7 +1061,10 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { Rvalue::Cast(cast_kind, op, ty) => { match *cast_kind { - CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, coercion_source) => { + CastKind::PointerCoercion( + PointerCoercion::ReifyFnPointer(target_safety), + coercion_source, + ) => { let is_implicit_coercion = coercion_source == CoercionSource::Implicit; let src_ty = op.ty(self.body, tcx); let mut src_sig = src_ty.fn_sig(tcx); @@ -1078,6 +1081,10 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { src_sig = safe_sig; } + if src_sig.safety().is_safe() && target_safety.is_unsafe() { + src_sig = tcx.safe_to_unsafe_sig(src_sig); + } + // HACK: This shouldn't be necessary... We can remove this when we actually // get binders with where clauses, then elaborate implied bounds into that // binder, and implement a higher-ranked subtyping algorithm that actually diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index e445f9457477..a0bee4e18214 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -689,7 +689,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: lval.write_cvalue(fx, res); } Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _), + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(_), _), ref operand, to_ty, ) => { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 233f9e787398..de626d04e785 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -405,7 +405,7 @@ pub(crate) fn codegen_rvalue_operand( let lladdr = bx.ptrtoint(llptr, llcast_ty); OperandValue::Immediate(lladdr) } - mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _) => { + mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(_), _) => { match *operand.layout.ty.kind() { ty::FnDef(def_id, args) => { let instance = ty::Instance::resolve_for_fn_ptr( diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 66a2afa0aa7d..78e4066ca910 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -627,7 +627,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { | PointerCoercion::ArrayToPointer | PointerCoercion::UnsafeFnPointer | PointerCoercion::ClosureFnPointer(_) - | PointerCoercion::ReifyFnPointer, + | PointerCoercion::ReifyFnPointer(_), _, ), _, diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index cf5ee03bedae..3485a5c625ba 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -74,7 +74,7 @@ pub fn cast( bug!("{cast_kind:?} casts are for borrowck only, not runtime MIR"); } - CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _) => { + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(_), _) => { // All reifications must be monomorphic, bail out otherwise. ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 9aded3f92c76..a90702105fbf 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -53,7 +53,7 @@ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion, }; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor}; @@ -291,13 +291,13 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { ty::FnPtr(a_sig_tys, a_hdr) => { // We permit coercion of fn pointers to drop the // unsafe qualifier. - self.coerce_from_fn_pointer(a_sig_tys.with(a_hdr), b) + self.coerce_from_fn_pointer(a, a_sig_tys.with(a_hdr), b) } - ty::Closure(closure_def_id_a, args_a) => { + ty::Closure(..) => { // Non-capturing closures are coercible to // function pointers or unsafe function pointers. // It cannot convert closures that require unsafe. - self.coerce_closure_to_fn(a, closure_def_id_a, args_a, b) + self.coerce_closure_to_fn(a, b) } _ => { // Otherwise, just use unification rules. @@ -833,45 +833,23 @@ fn coerce_to_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b), LeakCheck::Default) } - fn coerce_from_safe_fn( - &self, - fn_ty_a: ty::PolyFnSig<'tcx>, - b: Ty<'tcx>, - adjustment: Option, - ) -> CoerceResult<'tcx> { - debug_assert!(self.shallow_resolve(b) == b); - - if let ty::FnPtr(_, hdr_b) = b.kind() - && fn_ty_a.safety().is_safe() - && hdr_b.safety.is_unsafe() - { - let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - self.unify_and( - unsafe_a, - b, - adjustment - .map(|kind| Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }), - Adjust::Pointer(PointerCoercion::UnsafeFnPointer), - LeakCheck::Yes, - ) - } else { - let a = Ty::new_fn_ptr(self.tcx, fn_ty_a); - match adjustment { - Some(adjust) => self.unify_and(a, b, [], adjust, LeakCheck::Yes), - None => self.unify(a, b, LeakCheck::Yes), - } - } - } - fn coerce_from_fn_pointer( &self, - fn_ty_a: ty::PolyFnSig<'tcx>, + a: Ty<'tcx>, + a_sig: ty::PolyFnSig<'tcx>, b: Ty<'tcx>, ) -> CoerceResult<'tcx> { - debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer"); + debug!(?a_sig, ?b, "coerce_from_fn_pointer"); debug_assert!(self.shallow_resolve(b) == b); - self.coerce_from_safe_fn(fn_ty_a, b, None) + match b.kind() { + ty::FnPtr(_, b_hdr) if a_sig.safety().is_safe() && b_hdr.safety.is_unsafe() => { + let a = self.tcx.safe_to_unsafe_fn_ty(a_sig); + let adjust = Adjust::Pointer(PointerCoercion::UnsafeFnPointer); + self.unify_and(a, b, [], adjust, LeakCheck::Yes) + } + _ => self.unify(a, b, LeakCheck::Yes), + } } fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { @@ -881,45 +859,17 @@ fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { match b.kind() { ty::FnPtr(_, b_hdr) => { - let mut a_sig = a.fn_sig(self.tcx); - if let ty::FnDef(def_id, _) = *a.kind() { - // Intrinsics are not coercible to function pointers - if self.tcx.intrinsic(def_id).is_some() { - return Err(TypeError::IntrinsicCast); - } - - let fn_attrs = self.tcx.codegen_fn_attrs(def_id); - if matches!(fn_attrs.inline, InlineAttr::Force { .. }) { - return Err(TypeError::ForceInlineCast); - } - - if b_hdr.safety.is_safe() - && self.tcx.codegen_fn_attrs(def_id).safe_target_features - { - // Allow the coercion if the current function has all the features that would be - // needed to call the coercee safely. - if let Some(safe_sig) = self.tcx.adjust_target_feature_sig( - def_id, - a_sig, - self.fcx.body_id.into(), - ) { - a_sig = safe_sig; - } else { - return Err(TypeError::TargetFeatureCast(def_id)); - } - } - } + let a_sig = self.sig_for_fn_def_coercion(a, Some(b_hdr.safety))?; // FIXME: we shouldn't be normalizing here as coercion is inside of // a probe. This can probably cause ICEs. let InferOk { value: a_sig, mut obligations } = self.at(&self.cause, self.param_env).normalize(a_sig); + let a = Ty::new_fn_ptr(self.tcx, a_sig); - let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn( - a_sig, - b, - Some(Adjust::Pointer(PointerCoercion::ReifyFnPointer)), - )?; + let adjust = Adjust::Pointer(PointerCoercion::ReifyFnPointer(b_hdr.safety)); + let InferOk { value, obligations: o2 } = + self.unify_and(a, b, [], adjust, LeakCheck::Yes)?; obligations.extend(o2); Ok(InferOk { value, obligations }) @@ -930,47 +880,20 @@ fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { /// Attempts to coerce from a closure to a function pointer. Fails /// if the closure has any upvars. - fn coerce_closure_to_fn( - &self, - a: Ty<'tcx>, - closure_def_id_a: DefId, - args_a: GenericArgsRef<'tcx>, - b: Ty<'tcx>, - ) -> CoerceResult<'tcx> { + fn coerce_closure_to_fn(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { debug_assert!(self.shallow_resolve(a) == a); debug_assert!(self.shallow_resolve(b) == b); match b.kind() { - // At this point we haven't done capture analysis, which means - // that the ClosureArgs just contains an inference variable instead - // of tuple of captured types. - // - // All we care here is if any variable is being captured and not the exact paths, - // so we check `upvars_mentioned` for root variables being captured. - ty::FnPtr(_, hdr) - if self - .tcx - .upvars_mentioned(closure_def_id_a.expect_local()) - .is_none_or(|u| u.is_empty()) => - { - // We coerce the closure, which has fn type - // `extern "rust-call" fn((arg0,arg1,...)) -> _` - // to - // `fn(arg0,arg1,...) -> _` - // or - // `unsafe fn(arg0,arg1,...) -> _` - let closure_sig = args_a.as_closure().sig(); + ty::FnPtr(_, hdr) => { let safety = hdr.safety; - let pointer_ty = - Ty::new_fn_ptr(self.tcx, self.tcx.signature_unclosure(closure_sig, safety)); + let terr = TypeError::Sorts(ty::error::ExpectedFound::new(a, b)); + let closure_sig = self.sig_for_closure_coercion(a, Some(hdr.safety), terr)?; + let pointer_ty = Ty::new_fn_ptr(self.tcx, closure_sig); debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); - self.unify_and( - pointer_ty, - b, - [], - Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)), - LeakCheck::Default, - ) + + let adjust = Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)); + self.unify_and(pointer_ty, b, [], adjust, LeakCheck::Default) } _ => self.unify(a, b, LeakCheck::Default), } @@ -1137,6 +1060,94 @@ pub(crate) fn deref_once_mutably_for_diagnostic(&self, expr_ty: Ty<'tcx>) -> Opt }) } + #[instrument(level = "debug", skip(self), ret)] + fn sig_for_coerce_lub( + &self, + ty: Ty<'tcx>, + closure_upvars_terr: TypeError<'tcx>, + ) -> Result, TypeError<'tcx>> { + match ty.kind() { + ty::FnDef(..) => self.sig_for_fn_def_coercion(ty, None), + ty::Closure(..) => self.sig_for_closure_coercion(ty, None, closure_upvars_terr), + _ => unreachable!("`sig_for_fn_def_closure_coerce_lub` called with wrong ty: {:?}", ty), + } + } + + fn sig_for_fn_def_coercion( + &self, + fndef: Ty<'tcx>, + expected_safety: Option, + ) -> Result, TypeError<'tcx>> { + let tcx = self.tcx; + + let &ty::FnDef(def_id, _) = fndef.kind() else { + unreachable!("`sig_for_fn_def_coercion` called with non-fndef: {:?}", fndef); + }; + + // Intrinsics are not coercible to function pointers + if tcx.intrinsic(def_id).is_some() { + return Err(TypeError::IntrinsicCast); + } + + let fn_attrs = tcx.codegen_fn_attrs(def_id); + if matches!(fn_attrs.inline, InlineAttr::Force { .. }) { + return Err(TypeError::ForceInlineCast); + } + + let sig = fndef.fn_sig(tcx); + let sig = if fn_attrs.safe_target_features { + // Allow the coercion if the current function has all the features that would be + // needed to call the coercee safely. + match tcx.adjust_target_feature_sig(def_id, sig, self.body_id.into()) { + Some(adjusted_sig) => adjusted_sig, + None if matches!(expected_safety, Some(hir::Safety::Safe)) => { + return Err(TypeError::TargetFeatureCast(def_id)); + } + None => sig, + } + } else { + sig + }; + + if sig.safety().is_safe() && matches!(expected_safety, Some(hir::Safety::Unsafe)) { + Ok(tcx.safe_to_unsafe_sig(sig)) + } else { + Ok(sig) + } + } + + fn sig_for_closure_coercion( + &self, + closure: Ty<'tcx>, + expected_safety: Option, + closure_upvars_terr: TypeError<'tcx>, + ) -> Result, TypeError<'tcx>> { + let tcx = self.tcx; + + let ty::Closure(closure_def, closure_args) = closure.kind() else { + unreachable!("`sig_for_closure_coercion` called with non closure ty: {:?}", closure); + }; + + // At this point we haven't done capture analysis, which means + // that the ClosureArgs just contains an inference variable instead + // of tuple of captured types. + // + // All we care here is if any variable is being captured and not the exact paths, + // so we check `upvars_mentioned` for root variables being captured. + if !tcx.upvars_mentioned(closure_def.expect_local()).is_none_or(|u| u.is_empty()) { + return Err(closure_upvars_terr); + } + + // We coerce the closure, which has fn type + // `extern "rust-call" fn((arg0,arg1,...)) -> _` + // to + // `fn(arg0,arg1,...) -> _` + // or + // `unsafe fn(arg0,arg1,...) -> _` + let closure_sig = closure_args.as_closure().sig(); + Ok(tcx.signature_unclosure(closure_sig, expected_safety.unwrap_or(hir::Safety::Safe))) + } + /// Given some expressions, their known unified type and another expression, /// tries to unify the types, potentially inserting coercions on any of the /// provided expressions and returns their LUB (aka "common supertype"). @@ -1170,94 +1181,64 @@ fn try_find_coercion_lub( return Ok(prev_ty); } - let is_force_inline = |ty: Ty<'tcx>| { - if let ty::FnDef(did, _) = ty.kind() { - matches!(self.tcx.codegen_fn_attrs(did).inline, InlineAttr::Force { .. }) - } else { - false - } - }; - if is_force_inline(prev_ty) || is_force_inline(new_ty) { - return Err(TypeError::ForceInlineCast); - } + let terr = TypeError::Sorts(ty::error::ExpectedFound::new(prev_ty, new_ty)); + let opt_sigs = match (prev_ty.kind(), new_ty.kind()) { + // Don't coerce pairs of fndefs or pairs of closures to fn ptrs + // if they can just be lubbed. + // + // See #88097 or `lub_closures_before_fnptr_coercion.rs` for where + // we would erroneously coerce closures to fnptrs when attempting to + // coerce a closure to itself. + (ty::FnDef(..), ty::FnDef(..)) | (ty::Closure(..), ty::Closure(..)) => { + let lubbed_ty = self.commit_if_ok(|snapshot| { + let outer_universe = self.infcx.universe(); - // Special-case that coercion alone cannot handle: - // Function items or non-capturing closures of differing IDs or GenericArgs. - let (a_sig, b_sig) = { - let is_capturing_closure = |ty: Ty<'tcx>| { - if let &ty::Closure(closure_def_id, _args) = ty.kind() { - self.tcx.upvars_mentioned(closure_def_id.expect_local()).is_some() - } else { - false - } - }; - if is_capturing_closure(prev_ty) || is_capturing_closure(new_ty) { - (None, None) - } else { - let lubbed_tys = || { - self.commit_if_ok(|snapshot| { - let outer_universe = self.infcx.universe(); - - // We need to eagerly handle nested obligations due to lazy norm. - let result = if self.next_trait_solver() { - let ocx = ObligationCtxt::new(self); - let value = ocx.lub(cause, self.param_env, prev_ty, new_ty)?; - if ocx.try_evaluate_obligations().is_empty() { - Ok(InferOk { value, obligations: ocx.into_pending_obligations() }) - } else { - Err(TypeError::Mismatch) - } + // We need to eagerly handle nested obligations due to lazy norm. + let result = if self.next_trait_solver() { + let ocx = ObligationCtxt::new(self); + let value = ocx.lub(cause, self.param_env, prev_ty, new_ty)?; + if ocx.try_evaluate_obligations().is_empty() { + Ok(InferOk { value, obligations: ocx.into_pending_obligations() }) } else { - self.at(cause, self.param_env).lub(prev_ty, new_ty) - }; - - self.leak_check(outer_universe, Some(snapshot))?; - result - }) - }; - - match (prev_ty.kind(), new_ty.kind()) { - // Don't coerce pairs of fndefs or pairs of closures to fn ptrs - // if they can just be lubbed. - // - // See #88097 or `lub_closures_before_fnptr_coercion.rs` for where - // we would erroneously coerce closures to fnptrs when attempting to - // coerce a closure to itself. - (ty::FnDef(..), ty::FnDef(..)) => match lubbed_tys() { - Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), - Err(_) => (Some(prev_ty.fn_sig(self.tcx)), Some(new_ty.fn_sig(self.tcx))), - }, - (ty::Closure(_, args_a), ty::Closure(_, args_b)) => match lubbed_tys() { - Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), - Err(_) => { - let a_sig = self - .tcx - .signature_unclosure(args_a.as_closure().sig(), hir::Safety::Safe); - let b_sig = self - .tcx - .signature_unclosure(args_b.as_closure().sig(), hir::Safety::Safe); - (Some(a_sig), Some(b_sig)) + Err(TypeError::Mismatch) } - }, - (ty::Closure(_, args), ty::FnDef(..)) => { - let b_sig = new_ty.fn_sig(self.tcx); - let a_sig = - self.tcx.signature_unclosure(args.as_closure().sig(), b_sig.safety()); - (Some(a_sig), Some(b_sig)) + } else { + self.at(cause, self.param_env).lub(prev_ty, new_ty) + }; + + self.leak_check(outer_universe, Some(snapshot))?; + result + }); + + match lubbed_ty { + Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), + Err(_) => { + let a_sig = self.sig_for_coerce_lub(prev_ty, terr)?; + let b_sig = self.sig_for_coerce_lub(new_ty, terr)?; + Some((a_sig, b_sig)) } - (ty::FnDef(..), ty::Closure(_, args)) => { - let a_sig = prev_ty.fn_sig(self.tcx); - let b_sig = - self.tcx.signature_unclosure(args.as_closure().sig(), a_sig.safety()); - (Some(a_sig), Some(b_sig)) - } - // ty::FnPtr x ty::FnPtr is fine to just be handled through a normal `unify` - // call using `lub` which is what will happen on the normal path. - _ => (None, None), } } + + (ty::Closure(..), ty::FnDef(..)) | (ty::FnDef(..), ty::Closure(..)) => { + let a_sig = self.sig_for_coerce_lub(prev_ty, terr)?; + let b_sig = self.sig_for_coerce_lub(new_ty, terr)?; + Some((a_sig, b_sig)) + } + // ty::FnPtr x ty::FnPtr is fine to just be handled through a normal `unify` + // call using `lub` which is what will happen on the normal path. + (ty::FnPtr(..), ty::FnPtr(..)) => None, + _ => None, }; - if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) { + + if let Some((mut a_sig, mut b_sig)) = opt_sigs { + // Allow coercing safe sigs to unsafe sigs + if a_sig.safety().is_safe() && b_sig.safety().is_unsafe() { + a_sig = self.tcx.safe_to_unsafe_sig(a_sig); + } else if b_sig.safety().is_safe() && a_sig.safety().is_unsafe() { + b_sig = self.tcx.safe_to_unsafe_sig(b_sig); + }; + // The signature must match. let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig)); let sig = self @@ -1268,29 +1249,13 @@ fn try_find_coercion_lub( // Reify both sides and return the reified fn pointer type. let fn_ptr = Ty::new_fn_ptr(self.tcx, sig); let prev_adjustment = match prev_ty.kind() { - ty::Closure(..) => { - Adjust::Pointer(PointerCoercion::ClosureFnPointer(a_sig.safety())) - } - ty::FnDef(def_id, ..) => { - // Intrinsics are not coercible to function pointers - if self.tcx.intrinsic(def_id).is_some() { - return Err(TypeError::IntrinsicCast); - } - Adjust::Pointer(PointerCoercion::ReifyFnPointer) - } + ty::Closure(..) => Adjust::Pointer(PointerCoercion::ClosureFnPointer(sig.safety())), + ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer(sig.safety())), _ => span_bug!(cause.span, "should not try to coerce a {prev_ty} to a fn pointer"), }; let next_adjustment = match new_ty.kind() { - ty::Closure(..) => { - Adjust::Pointer(PointerCoercion::ClosureFnPointer(b_sig.safety())) - } - ty::FnDef(def_id, ..) => { - // Intrinsics are not coercible to function pointers - if self.tcx.intrinsic(def_id).is_some() { - return Err(TypeError::IntrinsicCast); - } - Adjust::Pointer(PointerCoercion::ReifyFnPointer) - } + ty::Closure(..) => Adjust::Pointer(PointerCoercion::ClosureFnPointer(sig.safety())), + ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer(sig.safety())), _ => span_bug!(new.span, "should not try to coerce a {new_ty} to a fn pointer"), }; for expr in exprs.iter().map(|e| e.as_coercion_site()) { diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 2920c9cb42ab..c806366b518a 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -9,8 +9,9 @@ #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum PointerCoercion { - /// Go from a fn-item type to a fn-pointer type. - ReifyFnPointer, + /// Go from a fn-item type to a fn pointer or an unsafe fn pointer. + /// It cannot convert an unsafe fn-item to a safe fn pointer. + ReifyFnPointer(hir::Safety), /// Go from a safe fn pointer to an unsafe fn pointer. UnsafeFnPointer, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0cd36d5e971d..baf4d364714a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2837,7 +2837,7 @@ impl<'tcx> TyCtxt<'tcx> { ); impl<'tcx> TyCtxt<'tcx> { - /// Given a `fn` type, returns an equivalent `unsafe fn` type; + /// Given a `fn` sig, returns an equivalent `unsafe fn` type; /// that is, a `fn` type that is equivalent in every way for being /// unsafe. pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> { @@ -2845,6 +2845,14 @@ pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> { Ty::new_fn_ptr(self, sig.map_bound(|sig| ty::FnSig { safety: hir::Safety::Unsafe, ..sig })) } + /// Given a `fn` sig, returns an equivalent `unsafe fn` sig; + /// that is, a `fn` sig that is equivalent in every way for being + /// unsafe. + pub fn safe_to_unsafe_sig(self, sig: PolyFnSig<'tcx>) -> PolyFnSig<'tcx> { + assert!(sig.safety().is_safe()); + sig.map_bound(|sig| ty::FnSig { safety: hir::Safety::Unsafe, ..sig }) + } + /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. pub fn trait_may_define_assoc_item(self, trait_def_id: DefId, assoc_name: Ident) -> bool { diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index d9c26faaf445..ebfeba5ad225 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1518,7 +1518,7 @@ fn simplify_cast( return Some(value); } - if let CastKind::PointerCoercion(ReifyFnPointer | ClosureFnPointer(_), _) = kind { + if let CastKind::PointerCoercion(ReifyFnPointer(_) | ClosureFnPointer(_), _) = kind { // Each reification of a generic fn may get a different pointer. // Do not try to merge them. return Some(self.new_opaque(to)); diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs index f011d394f616..a9f2c32171c3 100644 --- a/compiler/rustc_mir_transform/src/mentioned_items.rs +++ b/compiler/rustc_mir_transform/src/mentioned_items.rs @@ -109,7 +109,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { } // And finally, function pointer reification casts. mir::Rvalue::Cast( - mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _), + mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(_), _), ref operand, _, ) => { diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 91617be085c3..cf8247c12abd 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1272,7 +1272,7 @@ macro_rules! check_kinds { match kind { // FIXME: Add Checks for these CastKind::PointerWithExposedProvenance | CastKind::PointerExposeProvenance => {} - CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _) => { + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(_), _) => { // FIXME: check signature compatibility. check_kinds!( op_ty, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index f33f22460467..948f965ed7ad 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -765,7 +765,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { } } mir::Rvalue::Cast( - mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _), + mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(_), _), ref operand, _, ) => { diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs index fde4d40bea10..03f289f30f42 100644 --- a/compiler/rustc_public/src/mir/body.rs +++ b/compiler/rustc_public/src/mir/body.rs @@ -978,7 +978,7 @@ pub enum Safety { #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum PointerCoercion { /// Go from a fn-item type to a fn-pointer type. - ReifyFnPointer, + ReifyFnPointer(Safety), /// Go from a safe fn pointer to an unsafe fn pointer. UnsafeFnPointer, diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 36fc5724d51a..ca8234280be8 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -130,7 +130,9 @@ fn stable<'cx>( ) -> Self::T { use rustc_middle::ty::adjustment::PointerCoercion; match self { - PointerCoercion::ReifyFnPointer => crate::mir::PointerCoercion::ReifyFnPointer, + PointerCoercion::ReifyFnPointer(safety) => { + crate::mir::PointerCoercion::ReifyFnPointer(safety.stable(tables, cx)) + } PointerCoercion::UnsafeFnPointer => crate::mir::PointerCoercion::UnsafeFnPointer, PointerCoercion::ClosureFnPointer(safety) => { crate::mir::PointerCoercion::ClosureFnPointer(safety.stable(tables, cx)) diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 1fc8e86f3193..462cc644d4be 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -150,7 +150,7 @@ fn check_rvalue<'tcx>( CastKind::PointerCoercion( PointerCoercion::UnsafeFnPointer | PointerCoercion::ClosureFnPointer(_) - | PointerCoercion::ReifyFnPointer, + | PointerCoercion::ReifyFnPointer(_), _, ), _, diff --git a/tests/mir-opt/build_correct_coerce.main.built.after.mir b/tests/mir-opt/build_correct_coerce.main.built.after.mir index 583a5ecd2270..1f2a271b6294 100644 --- a/tests/mir-opt/build_correct_coerce.main.built.after.mir +++ b/tests/mir-opt/build_correct_coerce.main.built.after.mir @@ -9,7 +9,7 @@ fn main() -> () { bb0: { StorageLive(_1); - _1 = foo as for<'a> fn(&'a (), &'a ()) (PointerCoercion(ReifyFnPointer, AsCast)); + _1 = foo as for<'a> fn(&'a (), &'a ()) (PointerCoercion(ReifyFnPointer(Safe), AsCast)); FakeRead(ForLet(None), _1); _0 = const (); StorageDead(_1); diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff index 50a17326c2aa..7919c816b561 100644 --- a/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff +++ b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff @@ -13,7 +13,7 @@ StorageLive(_1); StorageLive(_2); StorageLive(_3); - _3 = main as fn() (PointerCoercion(ReifyFnPointer, AsCast)); + _3 = main as fn() (PointerCoercion(ReifyFnPointer(Safe), AsCast)); _2 = move _3 as usize (PointerExposeProvenance); StorageDead(_3); _1 = move _2 as *const fn() (PointerWithExposedProvenance); diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.rs b/tests/mir-opt/const_prop/reify_fn_ptr.rs index d56f21e586aa..92b9a923a424 100644 --- a/tests/mir-opt/const_prop/reify_fn_ptr.rs +++ b/tests/mir-opt/const_prop/reify_fn_ptr.rs @@ -3,7 +3,7 @@ fn main() { // CHECK-LABEL: fn main( - // CHECK: [[ptr:_.*]] = main as fn() (PointerCoercion(ReifyFnPointer, AsCast)); + // CHECK: [[ptr:_.*]] = main as fn() (PointerCoercion(ReifyFnPointer(Safe), AsCast)); // CHECK: [[addr:_.*]] = move [[ptr]] as usize (PointerExposeProvenance); // CHECK: [[back:_.*]] = move [[addr]] as *const fn() (PointerWithExposedProvenance); let _ = main as usize as *const fn(); diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff index f3f631956374..90920dd0be8f 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff @@ -37,7 +37,7 @@ bb0: { - StorageLive(_1); + nop; - _1 = identity:: as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer, AsCast)); + _1 = identity:: as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer(Safe), AsCast)); StorageLive(_2); StorageLive(_3); _3 = copy _1; @@ -50,7 +50,7 @@ StorageDead(_2); - StorageLive(_4); + nop; - _4 = identity:: as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer, AsCast)); + _4 = identity:: as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer(Safe), AsCast)); StorageLive(_5); StorageLive(_6); _6 = copy _4; diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff index 029e736a9795..0aca8e508f5c 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff @@ -37,7 +37,7 @@ bb0: { - StorageLive(_1); + nop; - _1 = identity:: as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer, AsCast)); + _1 = identity:: as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer(Safe), AsCast)); StorageLive(_2); StorageLive(_3); _3 = copy _1; @@ -50,7 +50,7 @@ StorageDead(_2); - StorageLive(_4); + nop; - _4 = identity:: as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer, AsCast)); + _4 = identity:: as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer(Safe), AsCast)); StorageLive(_5); StorageLive(_6); _6 = copy _4; diff --git a/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.rs b/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.rs index dda6bd6101c4..e2743bf39ab6 100644 --- a/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.rs +++ b/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.rs @@ -1,3 +1,5 @@ +//@ normalize-stderr: "32 bits" -> "64 bits" + fn foo() {} fn fndef_lub_leak_check() { diff --git a/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.stderr b/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.stderr index f7336d49e8ca..60e63ee93269 100644 --- a/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.stderr +++ b/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.stderr @@ -1,5 +1,5 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/leak_check_fndef_lub_deadcode_breakage.rs:25:14 + --> $DIR/leak_check_fndef_lub_deadcode_breakage.rs:27:14 | LL | unsafe { std::mem::transmute::<_, ()>(lubbed) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/coercion/lub_coercion_handles_safety.rs b/tests/ui/coercion/lub_coercion_handles_safety.rs new file mode 100644 index 000000000000..e44874f46cec --- /dev/null +++ b/tests/ui/coercion/lub_coercion_handles_safety.rs @@ -0,0 +1,52 @@ +//@ check-pass + +//@ only-x86_64 +// because target features + +macro_rules! lub { + ($lhs:expr, $rhs:expr) => { + if true { $lhs } else { $rhs } + }; +} + +fn safety_lub() { + unsafe fn lhs() {} + fn rhs() {} + + // We have two different fn defs, the only valid lub here + // is to go to fnptrs. However, in order to go to fnptrs + // `rhs` must coerce from a *safe* function to an *unsafe* + // one. + let lubbed = lub!(lhs, rhs); + is_unsafe_fnptr(lubbed); +} + +#[target_feature(enable = "sse2")] +fn target_feature_aware_safety_lub() { + #[target_feature(enable = "sse2")] + fn lhs() {} + fn rhs() {} + unsafe fn rhs_unsafe() {} + + // We have two different fn defs, the only valid lub here + // is to go to fnptrs. However, in order to go to fnptrs + // `lhs` must coerce from an unsafe fn to a safe one due + // to the correct target features being enabled + let lubbed = lub!(lhs, rhs); + is_fnptr(lubbed); + + // Similar case here except we must recognise that rhs + // is an unsafe fn so lhs must be an unsafe fn even though + // it *could* be safe + let lubbed = lub!(lhs, rhs_unsafe); + is_unsafe_fnptr(lubbed); +} + +trait FnPtr {} +impl FnPtr for fn() {} +fn is_fnptr(_: T) {} +trait UnsafeFnPtr {} +impl UnsafeFnPtr for unsafe fn() {} +fn is_unsafe_fnptr(_: T) {} + +fn main() {} From 7f61da9c69e5b88fadf3efc789a62c12ea751b2c Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Tue, 28 Oct 2025 17:16:51 +0000 Subject: [PATCH 256/585] account for safe target features in fndef<->closure and fndef<->fndef coerce-lubs --- clippy_utils/src/qualify_min_const_fn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 1fc8e86f3193..462cc644d4be 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -150,7 +150,7 @@ fn check_rvalue<'tcx>( CastKind::PointerCoercion( PointerCoercion::UnsafeFnPointer | PointerCoercion::ClosureFnPointer(_) - | PointerCoercion::ReifyFnPointer, + | PointerCoercion::ReifyFnPointer(_), _, ), _, From 85cf2825f4b0bbfc405724bf887bc5bcb199d9c6 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Tue, 28 Oct 2025 17:16:51 +0000 Subject: [PATCH 257/585] account for safe target features in fndef<->closure and fndef<->fndef coerce-lubs --- src/base.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base.rs b/src/base.rs index e445f9457477..a0bee4e18214 100644 --- a/src/base.rs +++ b/src/base.rs @@ -689,7 +689,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: lval.write_cvalue(fx, res); } Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _), + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(_), _), ref operand, to_ty, ) => { From 24a3f58adef9bd1e3222da49bdaacf3d434dca90 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Thu, 30 Oct 2025 16:16:14 +0000 Subject: [PATCH 258/585] remove redundant `lub` --- compiler/rustc_hir_typeck/src/coercion.rs | 37 +++++++++-------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index a90702105fbf..6daeb917014c 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1298,30 +1298,21 @@ fn try_find_coercion_lub( } } - match self.commit_if_ok(|_| coerce.coerce(prev_ty, new_ty)) { - Err(_) => { - // Avoid giving strange errors on failed attempts. - if let Some(e) = first_error { - Err(e) - } else { - Err(self - .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) - .unwrap_err()) - } - } - Ok(ok) => { - let (adjustments, target) = self.register_infer_ok_obligations(ok); - for expr in exprs { - let expr = expr.as_coercion_site(); - self.apply_adjustments(expr, adjustments.clone()); - } - debug!( - "coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?} ({:?})", - prev_ty, new_ty, target - ); - Ok(target) - } + let ok = self + .commit_if_ok(|_| coerce.coerce(prev_ty, new_ty)) + // Avoid giving strange errors on failed attempts. + .map_err(|e| first_error.unwrap_or(e))?; + + let (adjustments, target) = self.register_infer_ok_obligations(ok); + for expr in exprs { + let expr = expr.as_coercion_site(); + self.apply_adjustments(expr, adjustments.clone()); } + debug!( + "coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?} ({:?})", + prev_ty, new_ty, target + ); + Ok(target) } } From 46d8adeb616bcc2534d9a16ce8b3056ea12ea451 Mon Sep 17 00:00:00 2001 From: tiif Date: Fri, 21 Nov 2025 14:52:09 +0000 Subject: [PATCH 259/585] Use TypingEnv::fully_monomorphized for evaluating const without generic param path --- compiler/rustc_trait_selection/src/traits/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 6032bcacec6a..01b7d354b433 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -637,7 +637,7 @@ pub fn try_evaluate_const<'tcx>( // Since there is no generic parameter, we can just drop the environment // to prevent query cycle. - let typing_env = infcx.typing_env(ty::ParamEnv::empty()); + let typing_env = ty::TypingEnv::fully_monomorphized(); (uv.args, typing_env) } From af66b68f63ff869287a18f04486bc4ccf96ca6f9 Mon Sep 17 00:00:00 2001 From: tiif Date: Fri, 21 Nov 2025 15:02:06 +0000 Subject: [PATCH 260/585] refactor: make the match exhaustive --- compiler/rustc_trait_selection/src/traits/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 01b7d354b433..3af90bde86e6 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -618,7 +618,7 @@ pub fn try_evaluate_const<'tcx>( (args, typing_env) } - _ => { + Some(ty::AnonConstKind::MCG) | Some(ty::AnonConstKind::NonTypeSystem) | None => { // We are only dealing with "truly" generic/uninferred constants here: // - GCEConsts have been handled separately // - Repeat expr count back compat consts have also been handled separately From e4f02e40b656025af3de5010f389fff7326e0821 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Wed, 3 Dec 2025 15:04:32 +0100 Subject: [PATCH 261/585] fix guard patterns interaction with never type --- compiler/rustc_hir/src/hir.rs | 5 +++-- compiler/rustc_middle/src/hir/mod.rs | 3 ++- tests/ui/reachable/guard_read_for_never.rs | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 tests/ui/reachable/guard_read_for_never.rs diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 075ef83e456d..77e86fdce38d 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1807,8 +1807,9 @@ pub fn is_guaranteed_to_constitute_read_for_never(&self) -> bool { // Does not constitute a read. PatKind::Wild => false, - // Might not constitute a read, since the condition might be false. - PatKind::Guard(_, _) => true, + // The guard cannot affect if we make a read or not (it runs after the inner pattern + // has matched), therefore it's irrelevant. + PatKind::Guard(pat, _) => pat.is_guaranteed_to_constitute_read_for_never(), // This is unnecessarily restrictive when the pattern that doesn't // constitute a read is unreachable. diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 08b262df2f6e..0ab5a792e040 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -259,7 +259,8 @@ pub fn expr_guaranteed_to_constitute_read_for_never(self, expr: &Expr<'_>) -> bo expr.hir_id != lhs.hir_id } - // See note on `PatKind::Or` below for why this is `all`. + // See note on `PatKind::Or` in `Pat::is_guaranteed_to_constitute_read_for_never` + // for why this is `all`. ExprKind::Match(scrutinee, arms, _) => { assert_eq!(scrutinee.hir_id, expr.hir_id); arms.iter().all(|arm| arm.pat.is_guaranteed_to_constitute_read_for_never()) diff --git a/tests/ui/reachable/guard_read_for_never.rs b/tests/ui/reachable/guard_read_for_never.rs new file mode 100644 index 000000000000..7061da635301 --- /dev/null +++ b/tests/ui/reachable/guard_read_for_never.rs @@ -0,0 +1,16 @@ +// Regression test for +// +//@ check-pass +#![feature(guard_patterns, never_type)] +#![expect(incomplete_features, unused_parens)] +#![deny(unreachable_code)] + +fn main() { + unsafe { + let x = std::ptr::null::(); + + // This should not constitute a read for never, therefore no code here is unreachable + let (_ if false): ! = *x; + (); + } +} From ccde7d48f3e83bb8f0fba30fa089b1f96ec8f095 Mon Sep 17 00:00:00 2001 From: Roy Ammerschuber Date: Mon, 10 Nov 2025 17:43:21 +0100 Subject: [PATCH 262/585] Support retagging of wildcard references in tree borrows --- .../tree_borrows/diagnostics.rs | 109 +++- .../src/borrow_tracker/tree_borrows/mod.rs | 15 +- .../src/borrow_tracker/tree_borrows/tree.rs | 477 +++++++++++------- .../borrow_tracker/tree_borrows/wildcard.rs | 47 +- .../illegal_read_despite_exposed1.rs | 6 +- ...llegal_read_despite_exposed1.stack.stderr} | 6 +- .../illegal_read_despite_exposed1.tree.stderr | 25 + .../illegal_read_despite_exposed2.rs | 10 +- ...llegal_read_despite_exposed2.stack.stderr} | 12 +- .../illegal_read_despite_exposed2.tree.stderr | 31 ++ .../illegal_write_despite_exposed1.rs | 7 +- ...legal_write_despite_exposed1.stack.stderr} | 6 +- ...illegal_write_despite_exposed1.tree.stderr | 25 + .../wildcard/cross_tree_from_main.rs | 36 ++ .../wildcard/cross_tree_from_main.stderr | 25 + .../wildcard/cross_tree_update_main.rs | 37 ++ .../wildcard/cross_tree_update_main.stderr | 25 + .../cross_tree_update_main_invalid_exposed.rs | 44 ++ ...ss_tree_update_main_invalid_exposed.stderr | 14 + .../wildcard/cross_tree_update_newer.rs | 47 ++ .../wildcard/cross_tree_update_newer.stderr | 25 + .../cross_tree_update_newer_exposed.rs | 48 ++ .../cross_tree_update_newer_exposed.stderr | 25 + .../wildcard/cross_tree_update_older.rs | 47 ++ .../wildcard/cross_tree_update_older.stderr | 25 + ...cross_tree_update_older_invalid_exposed.rs | 53 ++ ...s_tree_update_older_invalid_exposed.stderr | 25 + ...ross_tree_update_older_invalid_exposed2.rs | 59 +++ ..._tree_update_older_invalid_exposed2.stderr | 25 + .../wildcard/protected_wildcard.rs | 39 ++ .../wildcard/protected_wildcard.stderr | 37 ++ .../strongly_protected_wildcard.stderr | 9 +- .../wildcard/subtree_internal_relatedness.rs | 44 ++ .../subtree_internal_relatedness.stderr | 25 + .../subtree_internal_relatedness_wildcard.rs | 49 ++ ...btree_internal_relatedness_wildcard.stderr | 25 + .../fail/tree_borrows/write_to_shr.stderr | 26 - .../pass/tree_borrows/wildcard/formatting.rs | 36 ++ .../tree_borrows/wildcard/formatting.stderr | 17 + .../pass/tree_borrows/wildcard/reborrow.rs | 224 ++++++++ .../tree_borrows/wildcard/undetected_ub.rs | 84 +-- .../pass/tree_borrows/wildcard/wildcard.rs | 1 - src/tools/miri/tests/utils/macros.rs | 4 +- 43 files changed, 1661 insertions(+), 295 deletions(-) rename src/tools/miri/tests/fail/{stacked_borrows => both_borrows}/illegal_read_despite_exposed1.rs (70%) rename src/tools/miri/tests/fail/{stacked_borrows/illegal_read_despite_exposed1.stderr => both_borrows/illegal_read_despite_exposed1.stack.stderr} (82%) create mode 100644 src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed1.tree.stderr rename src/tools/miri/tests/fail/{stacked_borrows => both_borrows}/illegal_read_despite_exposed2.rs (65%) rename src/tools/miri/tests/fail/{stacked_borrows/illegal_read_despite_exposed2.stderr => both_borrows/illegal_read_despite_exposed2.stack.stderr} (60%) create mode 100644 src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed2.tree.stderr rename src/tools/miri/tests/fail/{stacked_borrows => both_borrows}/illegal_write_despite_exposed1.rs (69%) rename src/tools/miri/tests/fail/{stacked_borrows/illegal_write_despite_exposed1.stderr => both_borrows/illegal_write_despite_exposed1.stack.stderr} (82%) create mode 100644 src/tools/miri/tests/fail/both_borrows/illegal_write_despite_exposed1.tree.stderr create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_from_main.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_from_main.stderr create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main.stderr create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed.stderr create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer.stderr create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer_exposed.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer_exposed.stderr create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older.stderr create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed.stderr create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed2.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed2.stderr create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.stderr create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness.stderr create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness_wildcard.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness_wildcard.stderr delete mode 100644 src/tools/miri/tests/fail/tree_borrows/write_to_shr.stderr create mode 100644 src/tools/miri/tests/pass/tree_borrows/wildcard/formatting.rs create mode 100644 src/tools/miri/tests/pass/tree_borrows/wildcard/formatting.stderr create mode 100644 src/tools/miri/tests/pass/tree_borrows/wildcard/reborrow.rs diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs index c454bb43a2f5..a91f35a9dcad 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -488,6 +488,8 @@ struct DisplayFmtPadding { indent_middle: S, /// Indentation for the last child. indent_last: S, + /// Replaces `join_last` for a wildcard root. + wildcard_root: S, } /// How to show whether a location has been accessed /// @@ -561,6 +563,11 @@ fn print_protector(&self, protector: Option<&ProtectorKind>) -> &'static str { }) .unwrap_or("") } + + /// Print extra text if the tag is exposed. + fn print_exposed(&self, exposed: bool) -> S { + if exposed { " (exposed)" } else { "" } + } } /// Track the indentation of the tree. @@ -607,23 +614,21 @@ fn char_repeat(c: char, n: usize) -> String { struct DisplayRepr { tag: BorTag, name: Option, + exposed: bool, rperm: Vec>, children: Vec, } impl DisplayRepr { - fn from(tree: &Tree, show_unnamed: bool) -> Option { + fn from(tree: &Tree, root: UniIndex, show_unnamed: bool) -> Option { let mut v = Vec::new(); - extraction_aux(tree, tree.root, show_unnamed, &mut v); + extraction_aux(tree, root, show_unnamed, &mut v); let Some(root) = v.pop() else { if show_unnamed { unreachable!( "This allocation contains no tags, not even a root. This should not happen." ); } - eprintln!( - "This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags." - ); return None; }; assert!(v.is_empty()); @@ -637,6 +642,7 @@ fn extraction_aux( ) { let node = tree.nodes.get(idx).unwrap(); let name = node.debug_info.name.clone(); + let exposed = node.is_exposed; let children_sorted = { let mut children = node.children.iter().cloned().collect::>(); children.sort_by_key(|idx| tree.nodes.get(*idx).unwrap().tag); @@ -661,12 +667,13 @@ fn extraction_aux( for child_idx in children_sorted { extraction_aux(tree, child_idx, show_unnamed, &mut children); } - acc.push(DisplayRepr { tag: node.tag, name, rperm, children }); + acc.push(DisplayRepr { tag: node.tag, name, rperm, children, exposed }); } } } fn print( - &self, + main_root: &Option, + wildcard_subtrees: &[DisplayRepr], fmt: &DisplayFmt, indenter: &mut DisplayIndent, protected_tags: &FxHashMap, @@ -703,15 +710,41 @@ fn print( block.push(s); } // This is the actual work - print_aux( - self, - &range_padding, - fmt, - indenter, - protected_tags, - true, /* root _is_ the last child */ - &mut block, - ); + if let Some(root) = main_root { + print_aux( + root, + &range_padding, + fmt, + indenter, + protected_tags, + true, /* root _is_ the last child */ + false, /* not a wildcard_root*/ + &mut block, + ); + } + for tree in wildcard_subtrees.iter() { + let mut gap_line = String::new(); + gap_line.push_str(fmt.perm.open); + for (i, &pad) in range_padding.iter().enumerate() { + if i > 0 { + gap_line.push_str(fmt.perm.sep); + } + gap_line.push_str(&format!("{}{}", char_repeat(' ', pad), " ")); + } + gap_line.push_str(fmt.perm.close); + block.push(gap_line); + + print_aux( + tree, + &range_padding, + fmt, + indenter, + protected_tags, + true, /* root _is_ the last child */ + true, /* wildcard_root*/ + &mut block, + ); + } // Then it's just prettifying it with a border of dashes. { let wr = &fmt.wrapper; @@ -741,6 +774,7 @@ fn print_aux( indent: &mut DisplayIndent, protected_tags: &FxHashMap, is_last_child: bool, + is_wildcard_root: bool, acc: &mut Vec, ) { let mut line = String::new(); @@ -760,7 +794,9 @@ fn print_aux( indent.write(&mut line); { // padding - line.push_str(if is_last_child { + line.push_str(if is_wildcard_root { + fmt.padding.wildcard_root + } else if is_last_child { fmt.padding.join_last } else { fmt.padding.join_middle @@ -777,12 +813,22 @@ fn print_aux( line.push_str(&fmt.print_tag(tree.tag, &tree.name)); let protector = protected_tags.get(&tree.tag); line.push_str(fmt.print_protector(protector)); + line.push_str(fmt.print_exposed(tree.exposed)); // Push the line to the accumulator then recurse. acc.push(line); let nb_children = tree.children.len(); for (i, child) in tree.children.iter().enumerate() { indent.increment(fmt, is_last_child); - print_aux(child, padding, fmt, indent, protected_tags, i + 1 == nb_children, acc); + print_aux( + child, + padding, + fmt, + indent, + protected_tags, + /* is_last_child */ i + 1 == nb_children, + /* is_wildcard_root */ false, + acc, + ); indent.decrement(fmt); } } @@ -803,6 +849,7 @@ fn print_aux( indent_last: " ", join_haschild: "┬", join_default: "─", + wildcard_root: "*", }, accessed: DisplayFmtAccess { yes: " ", no: "?", meh: "-" }, }; @@ -816,15 +863,27 @@ pub fn print_tree( ) -> InterpResult<'tcx> { let mut indenter = DisplayIndent::new(); let ranges = self.locations.iter_all().map(|(range, _loc)| range).collect::>(); - if let Some(repr) = DisplayRepr::from(self, show_unnamed) { - repr.print( - &DEFAULT_FORMATTER, - &mut indenter, - protected_tags, - ranges, - /* print warning message about tags not shown */ !show_unnamed, + let main_tree = DisplayRepr::from(self, self.roots[0], show_unnamed); + let wildcard_subtrees = self.roots[1..] + .iter() + .filter_map(|root| DisplayRepr::from(self, *root, show_unnamed)) + .collect::>(); + + if main_tree.is_none() && wildcard_subtrees.is_empty() { + eprintln!( + "This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags." ); } + + DisplayRepr::print( + &main_tree, + wildcard_subtrees.as_slice(), + &DEFAULT_FORMATTER, + &mut indenter, + protected_tags, + ranges, + /* print warning message about tags not shown */ !show_unnamed, + ); interp_ok(()) } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 2a1c98e5266b..e1da12282cd9 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -239,18 +239,14 @@ fn tb_reborrow( return interp_ok(new_prov); } }; + let new_prov = Provenance::Concrete { alloc_id, tag: new_tag }; log_creation(this, Some((alloc_id, base_offset, parent_prov)))?; - let orig_tag = match parent_prov { - ProvenanceExtra::Wildcard => return interp_ok(place.ptr().provenance), // TODO: handle retagging wildcard pointers - ProvenanceExtra::Concrete(tag) => tag, - }; - trace!( "reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}", new_tag, - orig_tag, + parent_prov, place.layout.ty, interpret::Pointer::new(alloc_id, base_offset), ptr_size.bytes() @@ -281,7 +277,7 @@ fn tb_reborrow( assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here // There's not actually any bytes here where accesses could even be tracked. // Just produce the new provenance, nothing else to do. - return interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag })); + return interp_ok(Some(new_prov)); } let protected = new_perm.protector.is_some(); @@ -367,11 +363,10 @@ fn tb_reborrow( } } } - // Record the parent-child pair in the tree. tree_borrows.new_child( base_offset, - orig_tag, + parent_prov, new_tag, inside_perms, new_perm.outside_perm, @@ -380,7 +375,7 @@ fn tb_reborrow( )?; drop(tree_borrows); - interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag })) + interp_ok(Some(new_prov)) } fn tb_retag_place( diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 07edf20fc46c..7fc9fa786e10 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -91,11 +91,11 @@ fn perform_transition( nodes: &mut UniValMap, wildcard_accesses: &mut UniValMap, access_kind: AccessKind, - access_cause: AccessCause, - access_range: Option, + access_cause: AccessCause, //diagnostics + access_range: Option, //diagnostics relatedness: AccessRelatedness, - span: Span, - location_range: Range, + span: Span, //diagnostics + location_range: Range, //diagnostics protected: bool, ) -> Result<(), TransitionError> { // Call this function now (i.e. only if we know `relatedness`), which @@ -294,8 +294,22 @@ pub struct Tree { pub(super) nodes: UniValMap, /// Associates with each location its state and wildcard access tracking. pub(super) locations: DedupRangeMap, - /// The index of the root node. - pub(super) root: UniIndex, + /// Contains both the root of the main tree as well as the roots of the wildcard subtrees. + /// + /// If we reborrow a reference which has wildcard provenance, then we do not know where in + /// the tree to attach them. Instead we create a new additional tree for this allocation + /// with this new reference as a root. We call this additional tree a wildcard subtree. + /// + /// The actual structure should be a single tree but with wildcard provenance we approximate + /// this with this ordered set of trees. Each wildcard subtree is the direct child of *some* exposed + /// tag (that is smaller than the root), but we do not know which. This also means that it can only be the + /// child of a tree that comes before it in the vec ensuring we don't have any cycles in our + /// approximated tree. + /// + /// Sorted according to `BorTag` from low to high. This also means the main root is `root[0]`. + /// + /// Has array size 2 because that still ensures the minimum size for SmallVec. + pub(super) roots: SmallVec<[UniIndex; 2]>, } /// A node in the borrow tree. Each node is uniquely identified by a tag via @@ -345,12 +359,13 @@ struct TreeVisitor<'tree> { } /// Whether to continue exploring the children recursively or not. +#[derive(Debug)] enum ContinueTraversal { Recurse, SkipSelfAndChildren, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum ChildrenVisitMode { VisitChildrenOfAccessed, SkipChildrenOfAccessed, @@ -384,7 +399,7 @@ struct TreeVisitorStack { impl TreeVisitorStack where NodeContinue: Fn(&NodeAppArgs<'_>) -> ContinueTraversal, - NodeApp: Fn(NodeAppArgs<'_>) -> Result<(), Err>, + NodeApp: FnMut(NodeAppArgs<'_>) -> Result<(), Err>, { fn should_continue_at( &self, @@ -405,12 +420,13 @@ fn propagate_at( (self.f_propagate)(NodeAppArgs { idx, rel_pos, nodes: this.nodes, loc: this.loc }) } + /// Returns the root of this tree. fn go_upwards_from_accessed( &mut self, this: &mut TreeVisitor<'_>, accessed_node: UniIndex, visit_children: ChildrenVisitMode, - ) -> Result<(), Err> { + ) -> Result { // We want to visit the accessed node's children first. // However, we will below walk up our parents and push their children (our cousins) // onto the stack. To ensure correct iteration order, this method thus finishes @@ -455,7 +471,7 @@ fn go_upwards_from_accessed( } // Reverse the stack, as discussed above. self.stack.reverse(); - Ok(()) + Ok(last_node) } fn finish_foreign_accesses(&mut self, this: &mut TreeVisitor<'_>) -> Result<(), Err> { @@ -536,18 +552,20 @@ impl<'tree> TreeVisitor<'tree> { /// Finally, remember that the iteration order is not relevant for UB, it only affects /// diagnostics. It also affects tree traversal optimizations built on top of this, so /// those need to be reviewed carefully as well whenever this changes. + /// + /// Returns the index of the root of the accessed tree. fn traverse_this_parents_children_other( mut self, start_idx: UniIndex, f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal, - f_propagate: impl Fn(NodeAppArgs<'_>) -> Result<(), Err>, - ) -> Result<(), Err> { + f_propagate: impl FnMut(NodeAppArgs<'_>) -> Result<(), Err>, + ) -> Result { let mut stack = TreeVisitorStack::new(f_continue, f_propagate); // Visits the accessed node itself, and all its parents, i.e. all nodes // undergoing a child access. Also pushes the children and the other // cousin nodes (i.e. all nodes undergoing a foreign access) to the stack // to be processed later. - stack.go_upwards_from_accessed( + let root = stack.go_upwards_from_accessed( &mut self, start_idx, ChildrenVisitMode::VisitChildrenOfAccessed, @@ -555,21 +573,24 @@ fn traverse_this_parents_children_other( // Now visit all the foreign nodes we remembered earlier. // For this we go bottom-up, but also allow f_continue to skip entire // subtrees from being visited if it would be a NOP. - stack.finish_foreign_accesses(&mut self) + stack.finish_foreign_accesses(&mut self)?; + Ok(root) } /// Like `traverse_this_parents_children_other`, but skips the children of `start_idx`. + /// + /// Returns the index of the root of the accessed tree. fn traverse_nonchildren( mut self, start_idx: UniIndex, f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal, - f_propagate: impl Fn(NodeAppArgs<'_>) -> Result<(), Err>, - ) -> Result<(), Err> { + f_propagate: impl FnMut(NodeAppArgs<'_>) -> Result<(), Err>, + ) -> Result { let mut stack = TreeVisitorStack::new(f_continue, f_propagate); // Visits the accessed node itself, and all its parents, i.e. all nodes // undergoing a child access. Also pushes the other cousin nodes to the // stack, but not the children of the accessed node. - stack.go_upwards_from_accessed( + let root = stack.go_upwards_from_accessed( &mut self, start_idx, ChildrenVisitMode::SkipChildrenOfAccessed, @@ -577,6 +598,27 @@ fn traverse_nonchildren( // Now visit all the foreign nodes we remembered earlier. // For this we go bottom-up, but also allow f_continue to skip entire // subtrees from being visited if it would be a NOP. + stack.finish_foreign_accesses(&mut self)?; + Ok(root) + } + + /// Traverses all children of `start_idx` including `start_idx` itself. + /// Uses `f_continue` to filter out subtrees and then processes each node + /// with `f_propagate` so that the children get processed before their + /// parents. + fn traverse_children_this( + mut self, + start_idx: UniIndex, + f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal, + f_propagate: impl FnMut(NodeAppArgs<'_>) -> Result<(), Err>, + ) -> Result<(), Err> { + let mut stack = TreeVisitorStack::new(f_continue, f_propagate); + + stack.stack.push(( + start_idx, + AccessRelatedness::ForeignAccess, + RecursionState::BeforeChildren, + )); stack.finish_foreign_accesses(&mut self) } } @@ -625,7 +667,7 @@ pub fn new(root_tag: BorTag, size: Size, span: Span) -> Self { let wildcard_accesses = UniValMap::default(); DedupRangeMap::new(size, LocationTree { perms, wildcard_accesses }) }; - Self { root: root_idx, nodes, locations, tag_mapping } + Self { roots: SmallVec::from_slice(&[root_idx]), nodes, locations, tag_mapping } } } @@ -639,7 +681,7 @@ impl<'tcx> Tree { pub(super) fn new_child( &mut self, base_offset: Size, - parent_tag: BorTag, + parent_prov: ProvenanceExtra, new_tag: BorTag, inside_perms: DedupRangeMap, outside_perm: Permission, @@ -647,7 +689,11 @@ pub(super) fn new_child( span: Span, ) -> InterpResult<'tcx> { let idx = self.tag_mapping.insert(new_tag); - let parent_idx = self.tag_mapping.get(&parent_tag).unwrap(); + let parent_idx = match parent_prov { + ProvenanceExtra::Concrete(parent_tag) => + Some(self.tag_mapping.get(&parent_tag).unwrap()), + ProvenanceExtra::Wildcard => None, + }; assert!(outside_perm.is_initial()); let default_strongest_idempotent = @@ -657,7 +703,7 @@ pub(super) fn new_child( idx, Node { tag: new_tag, - parent: Some(parent_idx), + parent: parent_idx, children: SmallVec::default(), default_initial_perm: outside_perm, default_initial_idempotent_foreign_access: default_strongest_idempotent, @@ -665,9 +711,17 @@ pub(super) fn new_child( debug_info: NodeDebugInfo::new(new_tag, outside_perm, span), }, ); - let parent_node = self.nodes.get_mut(parent_idx).unwrap(); - // Register new_tag as a child of parent_tag - parent_node.children.push(idx); + if let Some(parent_idx) = parent_idx { + let parent_node = self.nodes.get_mut(parent_idx).unwrap(); + // Register new_tag as a child of parent_tag + parent_node.children.push(idx); + } else { + // If the parent had wildcard provenance, then register the idx + // as a new wildcard root. + // This preserves the orderedness of `roots` because a newly created + // tag is greater than all previous tags. + self.roots.push(idx); + } // We need to know the weakest SIFA for `update_idempotent_foreign_access_after_retag`. let mut min_sifa = default_strongest_idempotent; @@ -691,19 +745,27 @@ pub(super) fn new_child( // We need to ensure the consistency of the wildcard access tracking data structure. // For this, we insert the correct entry for this tag based on its parent, if it exists. + // If we are inserting a new wildcard root (with Wildcard as parent_prov) then we insert + // the special wildcard root initial state instead. for (_range, loc) in self.locations.iter_mut_all() { - if let Some(parent_access) = loc.wildcard_accesses.get(parent_idx) { - loc.wildcard_accesses.insert(idx, parent_access.for_new_child()); + if let Some(parent_idx) = parent_idx { + if let Some(parent_access) = loc.wildcard_accesses.get(parent_idx) { + loc.wildcard_accesses.insert(idx, parent_access.for_new_child()); + } + } else { + loc.wildcard_accesses.insert(idx, WildcardState::for_wildcard_root()); } } - - // Inserting the new perms might have broken the SIFA invariant (see - // `foreign_access_skipping.rs`) if the SIFA we inserted is weaker than that of some parent. - // We now weaken the recorded SIFA for our parents, until the invariant is restored. We - // could weaken them all to `None`, but it is more efficient to compute the SIFA for the new - // permission statically, and use that. For this we need the *minimum* SIFA (`None` needs - // more fixup than `Write`). - self.update_idempotent_foreign_access_after_retag(parent_idx, min_sifa); + // If the parent is a wildcard pointer, then it doesn't track SIFA and doesn't need to be updated. + if let Some(parent_idx) = parent_idx { + // Inserting the new perms might have broken the SIFA invariant (see + // `foreign_access_skipping.rs`) if the SIFA we inserted is weaker than that of some parent. + // We now weaken the recorded SIFA for our parents, until the invariant is restored. We + // could weaken them all to `None`, but it is more efficient to compute the SIFA for the new + // permission statically, and use that. For this we need the *minimum* SIFA (`None` needs + // more fixup than `Write`). + self.update_idempotent_foreign_access_after_retag(parent_idx, min_sifa); + } interp_ok(()) } @@ -772,52 +834,67 @@ pub fn dealloc( span, )?; - // The order in which we check if any nodes are invalidated only - // matters to diagnostics, so we use the root as a default tag. let start_idx = match prov { - ProvenanceExtra::Concrete(tag) => self.tag_mapping.get(&tag).unwrap(), - ProvenanceExtra::Wildcard => self.root, + ProvenanceExtra::Concrete(tag) => Some(self.tag_mapping.get(&tag).unwrap()), + ProvenanceExtra::Wildcard => None, }; // Check if this breaks any strong protector. // (Weak protectors are already handled by `perform_access`.) for (loc_range, loc) in self.locations.iter_mut(access_range.start, access_range.size) { - TreeVisitor { nodes: &mut self.nodes, loc }.traverse_this_parents_children_other( - start_idx, - // Visit all children, skipping none. - |_| ContinueTraversal::Recurse, - |args: NodeAppArgs<'_>| { - let node = args.nodes.get(args.idx).unwrap(); - let perm = args.loc.perms.entry(args.idx); + // Checks the tree containing `idx` for strong protector violations. + // It does this in traversal order. + let mut check_tree = |idx| { + TreeVisitor { nodes: &mut self.nodes, loc }.traverse_this_parents_children_other( + idx, + // Visit all children, skipping none. + |_| ContinueTraversal::Recurse, + |args: NodeAppArgs<'_>| { + let node = args.nodes.get(args.idx).unwrap(); - let perm = perm.get().copied().unwrap_or_else(|| node.default_location_state()); - if global.borrow().protected_tags.get(&node.tag) - == Some(&ProtectorKind::StrongProtector) - // Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`). - // Related to https://github.com/rust-lang/rust/issues/55005. - && !perm.permission.is_cell() - // Only trigger UB if the accessed bit is set, i.e. if the protector is actually protecting this offset. See #4579. - && perm.accessed - { - Err(TbError { - conflicting_info: &node.debug_info, - access_cause: diagnostics::AccessCause::Dealloc, - alloc_id, - error_offset: loc_range.start, - error_kind: TransitionError::ProtectedDealloc, - accessed_info: match prov { - ProvenanceExtra::Concrete(_) => - Some(&args.nodes.get(start_idx).unwrap().debug_info), - // We don't know from where the access came during a wildcard access. - ProvenanceExtra::Wildcard => None, - }, + let perm = args + .loc + .perms + .get(args.idx) + .copied() + .unwrap_or_else(|| node.default_location_state()); + if global.borrow().protected_tags.get(&node.tag) + == Some(&ProtectorKind::StrongProtector) + // Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`). + // Related to https://github.com/rust-lang/rust/issues/55005. + && !perm.permission.is_cell() + // Only trigger UB if the accessed bit is set, i.e. if the protector is actually protecting this offset. See #4579. + && perm.accessed + { + Err(TbError { + conflicting_info: &node.debug_info, + access_cause: diagnostics::AccessCause::Dealloc, + alloc_id, + error_offset: loc_range.start, + error_kind: TransitionError::ProtectedDealloc, + accessed_info: start_idx + .map(|idx| &args.nodes.get(idx).unwrap().debug_info), + } + .build()) + } else { + Ok(()) } - .build()) - } else { - Ok(()) - } - }, - )?; + }, + ) + }; + // If we have a start index we first check its subtree in traversal order. + // This results in us showing the error of the closest node instead of an + // arbitrary one. + let accessed_root = start_idx.map(&mut check_tree).transpose()?; + // Afterwards we check all other trees. + // We iterate over the list in reverse order to ensure that we do not visit + // a parent before its child. + for &root in self.roots.iter().rev() { + if Some(root) == accessed_root { + continue; + } + check_tree(root)?; + } } interp_ok(()) } @@ -849,20 +926,20 @@ pub fn perform_access( span: Span, // diagnostics ) -> InterpResult<'tcx> { #[cfg(feature = "expensive-consistency-checks")] - if matches!(prov, ProvenanceExtra::Wildcard) { + if self.roots.len() > 1 || matches!(prov, ProvenanceExtra::Wildcard) { self.verify_wildcard_consistency(global); } + let source_idx = match prov { ProvenanceExtra::Concrete(tag) => Some(self.tag_mapping.get(&tag).unwrap()), ProvenanceExtra::Wildcard => None, }; - if let Some((access_range, access_kind, access_cause)) = access_range_and_kind { // Default branch: this is a "normal" access through a known range. // We iterate over affected locations and traverse the tree for each of them. for (loc_range, loc) in self.locations.iter_mut(access_range.start, access_range.size) { loc.perform_access( - self.root, + self.roots.iter().copied(), &mut self.nodes, source_idx, loc_range, @@ -898,7 +975,7 @@ pub fn perform_access( { let access_cause = diagnostics::AccessCause::FnExit(access_kind); loc.perform_access( - self.root, + self.roots.iter().copied(), &mut self.nodes, Some(source_idx), loc_range, @@ -920,7 +997,9 @@ pub fn perform_access( /// Integration with the BorTag garbage collector impl Tree { pub fn remove_unreachable_tags(&mut self, live_tags: &FxHashSet) { - self.remove_useless_children(self.root, live_tags); + for i in 0..(self.roots.len()) { + self.remove_useless_children(self.roots[i], live_tags); + } // Right after the GC runs is a good moment to check if we can // merge some adjacent ranges that were made equal by the removal of some // tags (this does not necessarily mean that they have identical internal representations, @@ -1073,20 +1152,20 @@ impl<'tcx> LocationTree { /// * `visit_children`: Whether to skip updating the children of `access_source`. fn perform_access( &mut self, - root: UniIndex, + roots: impl Iterator, nodes: &mut UniValMap, access_source: Option, - loc_range: Range, - access_range: Option, + loc_range: Range, // diagnostics + access_range: Option, // diagnostics access_kind: AccessKind, - access_cause: diagnostics::AccessCause, + access_cause: diagnostics::AccessCause, // diagnostics global: &GlobalState, alloc_id: AllocId, // diagnostics span: Span, // diagnostics visit_children: ChildrenVisitMode, ) -> InterpResult<'tcx> { - if let Some(idx) = access_source { - self.perform_normal_access( + let accessed_root = if let Some(idx) = access_source { + Some(self.perform_normal_access( idx, nodes, loc_range.clone(), @@ -1097,13 +1176,38 @@ fn perform_access( alloc_id, span, visit_children, - ) + )?) } else { - // `SkipChildrenOfAccessed` only gets set on protector release. - // Since a wildcard reference are never protected this assert shouldn't fail. + // `SkipChildrenOfAccessed` only gets set on protector release, which only + // occurs on a known node. assert!(matches!(visit_children, ChildrenVisitMode::VisitChildrenOfAccessed)); + None + }; + + let accessed_root_tag = accessed_root.map(|idx| nodes.get(idx).unwrap().tag); + if matches!(visit_children, ChildrenVisitMode::SkipChildrenOfAccessed) { + // FIXME: approximate which roots could be children of the accessed node and only skip them instead of all other trees. + return interp_ok(()); + } + for root in roots { + // We don't perform a wildcard access on the tree we already performed a + // normal access on. + if Some(root) == accessed_root { + continue; + } + // The choice of `max_local_tag` requires some thought. + // This can only be a local access for nodes that are a parent of the accessed node + // and are therefore smaller, so the accessed node itself is a valid choice for `max_local_tag`. + // However, using `accessed_root` is better since that will be smaller. It is still a valid choice + // because for nodes *in other trees*, if they are a parent of the accessed node then they + // are a parent of `accessed_root`. + // + // As a consequence of this, since the root of the main tree is the smallest tag in the entire + // allocation, if the access occurred in the main tree then other subtrees will only see foreign accesses. self.perform_wildcard_access( root, + access_source, + /*max_local_tag*/ accessed_root_tag, nodes, loc_range.clone(), access_range, @@ -1112,11 +1216,14 @@ fn perform_access( global, alloc_id, span, - ) + )?; } + interp_ok(()) } /// Performs a normal access on the tree containing `access_source`. + /// + /// Returns the root index of this tree. /// * `access_source`: The index of the tag being accessed. /// * `visit_children`: Whether to skip the children of `access_source` /// during the access. Used for protector end access. @@ -1124,15 +1231,15 @@ fn perform_normal_access( &mut self, access_source: UniIndex, nodes: &mut UniValMap, - loc_range: Range, - access_range: Option, + loc_range: Range, // diagnostics + access_range: Option, // diagnostics access_kind: AccessKind, - access_cause: diagnostics::AccessCause, + access_cause: diagnostics::AccessCause, // diagnostics global: &GlobalState, alloc_id: AllocId, // diagnostics span: Span, // diagnostics visit_children: ChildrenVisitMode, - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, UniIndex> { // Performs the per-node work: // - insert the permission if it does not exist // - perform the access @@ -1141,7 +1248,7 @@ fn perform_normal_access( // - skip the traversal of the children in some cases // - do not record noop transitions // - // `perms_range` is only for diagnostics (it is the range of + // `loc_range` is only for diagnostics (it is the range of // the `RangeMap` on which we are currently working). let node_skipper = |args: &NodeAppArgs<'_>| -> ContinueTraversal { let node = args.nodes.get(args.idx).unwrap(); @@ -1150,7 +1257,7 @@ fn perform_normal_access( let old_state = perm.copied().unwrap_or_else(|| node.default_location_state()); old_state.skip_if_known_noop(access_kind, args.rel_pos) }; - let node_app = |args: NodeAppArgs<'_>| -> Result<(), _> { + let node_app = |args: NodeAppArgs<'_>| { let node = args.nodes.get_mut(args.idx).unwrap(); let mut perm = args.loc.perms.entry(args.idx); @@ -1164,7 +1271,7 @@ fn perform_normal_access( &mut args.loc.wildcard_accesses, access_kind, access_cause, - /* access_range */ access_range, + access_range, args.rel_pos, span, loc_range.clone(), @@ -1182,6 +1289,7 @@ fn perform_normal_access( .build() }) }; + let visitor = TreeVisitor { nodes, loc: self }; match visit_children { ChildrenVisitMode::VisitChildrenOfAccessed => @@ -1191,31 +1299,61 @@ fn perform_normal_access( } .into() } + /// Performs a wildcard access on the tree with root `root`. Takes the `access_relatedness` /// for each node from the `WildcardState` datastructure. /// * `root`: Root of the tree being accessed. + /// * `access_source`: the index of the accessed tag, if any. + /// This is only used for printing the correct tag on errors. + /// * `max_local_tag`: The access can only be local for nodes whose tag is + /// at most `max_local_tag`. fn perform_wildcard_access( &mut self, root: UniIndex, + access_source: Option, + max_local_tag: Option, nodes: &mut UniValMap, - loc_range: Range, - access_range: Option, + loc_range: Range, // diagnostics + access_range: Option, // diagnostics access_kind: AccessKind, - access_cause: diagnostics::AccessCause, + access_cause: diagnostics::AccessCause, // diagnostics global: &GlobalState, alloc_id: AllocId, // diagnostics span: Span, // diagnostics ) -> InterpResult<'tcx> { - let f_continue = - |idx: UniIndex, nodes: &UniValMap, loc: &LocationTree| -> ContinueTraversal { - let node = nodes.get(idx).unwrap(); - let perm = loc.perms.get(idx); - let wildcard_state = loc.wildcard_accesses.get(idx).cloned().unwrap_or_default(); + let get_relatedness = |idx: UniIndex, node: &Node, loc: &LocationTree| { + let wildcard_state = loc.wildcard_accesses.get(idx).cloned().unwrap_or_default(); + // If the tag is larger than `max_local_tag` then the access can only be foreign. + let only_foreign = max_local_tag.is_some_and(|max_local_tag| max_local_tag < node.tag); + wildcard_state.access_relatedness(access_kind, only_foreign) + }; + + // This does a traversal across the tree updating children before their parents. The + // difference to `perform_normal_access` is that we take the access relatedness from + // the wildcard tracking state of the node instead of from the visitor itself. + // + // Unlike for a normal access, the iteration order is important for improving the + // accuracy of wildcard accesses if `max_local_tag` is `Some`: processing the effects of this + // access further down the tree can cause exposed nodes to lose permissions, thus updating + // the wildcard data structure, which will be taken into account when processing the parent + // nodes. Also see the test `cross_tree_update_older_invalid_exposed2.rs` + // (Doing accesses in the opposite order cannot help with precision but the reasons are complicated; + // see .) + // + // Note, however, that this is an approximation: there can be situations where a node is + // marked as having an exposed foreign node, but actually that foreign node cannot be + // the source of the access due to `max_local_tag`. The wildcard tracking cannot know + // about `max_local_tag` so we will incorrectly assume that this might be a foreign access. + TreeVisitor { loc: self, nodes }.traverse_children_this( + root, + |args| -> ContinueTraversal { + let node = args.nodes.get(args.idx).unwrap(); + let perm = args.loc.perms.get(args.idx); let old_state = perm.copied().unwrap_or_else(|| node.default_location_state()); // If we know where, relative to this node, the wildcard access occurs, // then check if we can skip the entire subtree. - if let Some(relatedness) = wildcard_state.access_relatedness(access_kind) + if let Some(relatedness) = get_relatedness(args.idx, node, args.loc) && let Some(relatedness) = relatedness.to_relatedness() { // We can use the usual SIFA machinery to skip nodes. @@ -1223,78 +1361,64 @@ fn perform_wildcard_access( } else { ContinueTraversal::Recurse } - }; - // This does a traversal starting from the root through the tree updating - // the permissions of each node. - // The difference to `perform_access` is that we take the access - // relatedness from the wildcard tracking state of the node instead of - // from the visitor itself. - TreeVisitor { loc: self, nodes } - .traverse_this_parents_children_other( - root, - |args| f_continue(args.idx, args.nodes, args.loc), - |args| { - let node = args.nodes.get_mut(args.idx).unwrap(); - let mut entry = args.loc.perms.entry(args.idx); - let perm = entry.or_insert(node.default_location_state()); + }, + |args| { + let node = args.nodes.get_mut(args.idx).unwrap(); - let protected = global.borrow().protected_tags.contains_key(&node.tag); + let protected = global.borrow().protected_tags.contains_key(&node.tag); - let Some(wildcard_relatedness) = args - .loc - .wildcard_accesses - .get(args.idx) - .and_then(|s| s.access_relatedness(access_kind)) - else { - // There doesn't exist a valid exposed reference for this access to - // happen through. - // If this fails for one id, then it fails for all ids so this. - // Since we always check the root first, this means it should always - // fail on the root. - assert_eq!(root, args.idx); - return Err(no_valid_exposed_references_error( - alloc_id, - loc_range.start, - access_cause, - )); - }; - - let Some(relatedness) = wildcard_relatedness.to_relatedness() else { - // If the access type is Either, then we do not apply any transition - // to this node, but we still update each of its children. - // This is an imprecision! In the future, maybe we can still do some sort - // of best-effort update here. - return Ok(()); - }; - // We know the exact relatedness, so we can actually do precise checks. - perm.perform_transition( - args.idx, - args.nodes, - &mut args.loc.wildcard_accesses, - access_kind, + let Some(wildcard_relatedness) = get_relatedness(args.idx, node, args.loc) else { + // There doesn't exist a valid exposed reference for this access to + // happen through. + // This can only happen if `root` is the main root: We set + // `max_foreign_access==Write` on all wildcard roots, so at least a foreign access + // is always possible on all nodes in a wildcard subtree. + return Err(no_valid_exposed_references_error( + alloc_id, + loc_range.start, access_cause, - access_range, - relatedness, - span, - loc_range.clone(), - protected, - ) - .map_err(|trans| { - let node = args.nodes.get(args.idx).unwrap(); - TbError { - conflicting_info: &node.debug_info, - access_cause, - alloc_id, - error_offset: loc_range.start, - error_kind: trans, - // We don't know from where the access came during a wildcard access. - accessed_info: None, - } - .build() - }) - }, - ) - .into() + )); + }; + + let Some(relatedness) = wildcard_relatedness.to_relatedness() else { + // If the access type is Either, then we do not apply any transition + // to this node, but we still update each of its children. + // This is an imprecision! In the future, maybe we can still do some sort + // of best-effort update here. + return Ok(()); + }; + + let mut entry = args.loc.perms.entry(args.idx); + let perm = entry.or_insert(node.default_location_state()); + // We know the exact relatedness, so we can actually do precise checks. + perm.perform_transition( + args.idx, + args.nodes, + &mut args.loc.wildcard_accesses, + access_kind, + access_cause, + access_range, + relatedness, + span, + loc_range.clone(), + protected, + ) + .map_err(|trans| { + let node = args.nodes.get(args.idx).unwrap(); + TbError { + conflicting_info: &node.debug_info, + access_cause, + alloc_id, + error_offset: loc_range.start, + error_kind: trans, + accessed_info: access_source + .map(|idx| &args.nodes.get(idx).unwrap().debug_info), + } + .build() + }) + }, + )?; + interp_ok(()) } } @@ -1309,10 +1433,11 @@ pub fn default_location_state(&self) -> LocationState { impl VisitProvenance for Tree { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - // To ensure that the root never gets removed, we visit it - // (the `root` node of `Tree` is not an `Option<_>`) - visit(None, Some(self.nodes.get(self.root).unwrap().tag)); - + // To ensure that the roots never get removed, we visit them. + // FIXME: it should be possible to GC wildcard tree roots. + for id in self.roots.iter().copied() { + visit(None, Some(self.nodes.get(id).unwrap().tag)); + } // We also need to keep around any exposed tags through which // an access could still happen. for (_id, node) in self.nodes.iter() { diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/wildcard.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/wildcard.rs index 56a85e6f4ced..3b55a9e36ea6 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/wildcard.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/wildcard.rs @@ -88,10 +88,26 @@ fn max_local_access(&self) -> WildcardAccessLevel { } /// From where relative to the node with this wildcard info a read or write access could happen. - pub fn access_relatedness(&self, kind: AccessKind) -> Option { - match kind { + /// If `only_foreign` is true then we treat `LocalAccess` as impossible. This means we return + /// `None` if only a `LocalAccess` is possible, and we treat `EitherAccess` as a + /// `ForeignAccess`. + pub fn access_relatedness( + &self, + kind: AccessKind, + only_foreign: bool, + ) -> Option { + let rel = match kind { AccessKind::Read => self.read_access_relatedness(), AccessKind::Write => self.write_access_relatedness(), + }; + if only_foreign { + use WildcardAccessRelatedness as E; + match rel { + Some(E::EitherAccess | E::ForeignAccess) => Some(E::ForeignAccess), + Some(E::LocalAccess) | None => None, + } + } else { + rel } } @@ -131,6 +147,15 @@ pub fn for_new_child(&self) -> Self { ..Default::default() } } + /// Crates the initial `WildcardState` for a wildcard root. + /// This has `max_foreign_access==Write` as it actually is the child of *some* exposed node + /// through which we can receive foreign accesses. + /// + /// This is different from the main root which has `max_foreign_access==None`, since there + /// cannot be a foreign access to the root of the allocation. + pub fn for_wildcard_root() -> Self { + Self { max_foreign_access: WildcardAccessLevel::Write, ..Default::default() } + } /// Pushes the nodes of `children` onto the stack who's `max_foreign_access` /// needs to be updated. @@ -435,6 +460,10 @@ impl Tree { /// Checks that the wildcard tracking data structure is internally consistent and /// has the correct `exposed_as` values. pub fn verify_wildcard_consistency(&self, global: &GlobalState) { + // We rely on the fact that `roots` is ordered according to tag from low to high. + assert!(self.roots.is_sorted_by_key(|idx| self.nodes.get(*idx).unwrap().tag)); + let main_root_idx = self.roots[0]; + let protected_tags = &global.borrow().protected_tags; for (_, loc) in self.locations.iter_all() { let wildcard_accesses = &loc.wildcard_accesses; @@ -447,7 +476,8 @@ pub fn verify_wildcard_consistency(&self, global: &GlobalState) { let state = wildcard_accesses.get(id).unwrap(); let expected_exposed_as = if node.is_exposed { - let perm = perms.get(id).unwrap(); + let perm = + perms.get(id).copied().unwrap_or_else(|| node.default_location_state()); perm.permission() .strongest_allowed_child_access(protected_tags.contains_key(&node.tag)) @@ -477,7 +507,16 @@ pub fn verify_wildcard_consistency(&self, global: &GlobalState) { .max(parent_state.max_foreign_access) .max(parent_state.exposed_as) } else { - WildcardAccessLevel::None + if main_root_idx == id { + // There can never be a foreign access to the root of the allocation. + // So its foreign access level is always `None`. + WildcardAccessLevel::None + } else { + // For wildcard roots any access on a different subtree can be foreign + // to it. So a wildcard root has the maximum possible foreign access + // level. + WildcardAccessLevel::Write + } }; // Count how many children can be the source of wildcard reads or writes diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs b/src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed1.rs similarity index 70% rename from src/tools/miri/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs rename to src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed1.rs index 76516b7d924b..8cd72b589b8e 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs +++ b/src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed1.rs @@ -1,4 +1,6 @@ +//@revisions: stack tree //@compile-flags: -Zmiri-permissive-provenance +//@[tree]compile-flags: -Zmiri-tree-borrows fn main() { unsafe { @@ -12,6 +14,8 @@ fn main() { // And we test that it has uniqueness by doing a conflicting write. *exposed_ptr = 0; // Stack: Unknown( at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs:LL:CC + --> tests/fail/both_borrows/illegal_read_despite_exposed1.rs:LL:CC | LL | let _val = *root2; | ^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4] @@ -7,12 +7,12 @@ LL | let _val = *root2; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs:LL:CC + --> tests/fail/both_borrows/illegal_read_despite_exposed1.rs:LL:CC | LL | let root2 = &mut *exposed_ptr; | ^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs:LL:CC + --> tests/fail/both_borrows/illegal_read_despite_exposed1.rs:LL:CC | LL | *exposed_ptr = 0; | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed1.tree.stderr new file mode 100644 index 000000000000..e6c9a142c3f2 --- /dev/null +++ b/src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed1.tree.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden + --> tests/fail/both_borrows/illegal_read_despite_exposed1.rs:LL:CC + | +LL | let _val = *root2; + | ^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Disabled which forbids this child read access +help: the accessed tag was created here, in the initial state Reserved + --> tests/fail/both_borrows/illegal_read_despite_exposed1.rs:LL:CC + | +LL | let root2 = &mut *exposed_ptr; + | ^^^^^^^^^^^^^^^^^ +help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] + --> tests/fail/both_borrows/illegal_read_despite_exposed1.rs:LL:CC + | +LL | *exposed_ptr = 0; + | ^^^^^^^^^^^^^^^^ + = help: this transition corresponds to a loss of read and write permissions + +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/stacked_borrows/illegal_read_despite_exposed2.rs b/src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed2.rs similarity index 65% rename from src/tools/miri/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs rename to src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed2.rs index 97e0bf40c0dd..9e8c94031ce8 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs +++ b/src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed2.rs @@ -1,4 +1,6 @@ +//@revisions: stack tree //@compile-flags: -Zmiri-permissive-provenance +//@[tree]compile-flags: -Zmiri-tree-borrows fn main() { unsafe { @@ -7,6 +9,8 @@ fn main() { let exposed_ptr = addr as *mut i32; // From the exposed ptr, we get a new unique ptr. let root2 = &mut *exposed_ptr; + // Activate the reference (unnecessary on Stacked Borrows). + *root2 = 42; // let _fool = root2 as *mut _; // this would fool us, since SRW(N+1) remains on the stack // Stack: Unknown( at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs:LL:CC +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> tests/fail/both_borrows/illegal_read_despite_exposed2.rs:LL:CC | -LL | let _val = *root2; - | ^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *root2 = 3; + | ^^^^^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a Unique retag at offsets [0x0..0x4] - --> tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs:LL:CC + --> tests/fail/both_borrows/illegal_read_despite_exposed2.rs:LL:CC | LL | let root2 = &mut *exposed_ptr; | ^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a read access - --> tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs:LL:CC + --> tests/fail/both_borrows/illegal_read_despite_exposed2.rs:LL:CC | LL | let _val = *exposed_ptr; | ^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed2.tree.stderr new file mode 100644 index 000000000000..17ae8bc513da --- /dev/null +++ b/src/tools/miri/tests/fail/both_borrows/illegal_read_despite_exposed2.tree.stderr @@ -0,0 +1,31 @@ +error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden + --> tests/fail/both_borrows/illegal_read_despite_exposed2.rs:LL:CC + | +LL | *root2 = 3; + | ^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Frozen which forbids this child write access +help: the accessed tag was created here, in the initial state Reserved + --> tests/fail/both_borrows/illegal_read_despite_exposed2.rs:LL:CC + | +LL | let root2 = &mut *exposed_ptr; + | ^^^^^^^^^^^^^^^^^ +help: the accessed tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] + --> tests/fail/both_borrows/illegal_read_despite_exposed2.rs:LL:CC + | +LL | *root2 = 42; + | ^^^^^^^^^^^ + = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference +help: the accessed tag later transitioned to Frozen due to a foreign read access at offsets [0x0..0x4] + --> tests/fail/both_borrows/illegal_read_despite_exposed2.rs:LL:CC + | +LL | let _val = *exposed_ptr; + | ^^^^^^^^^^^^ + = help: this transition corresponds to a loss of write permissions + +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/stacked_borrows/illegal_write_despite_exposed1.rs b/src/tools/miri/tests/fail/both_borrows/illegal_write_despite_exposed1.rs similarity index 69% rename from src/tools/miri/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs rename to src/tools/miri/tests/fail/both_borrows/illegal_write_despite_exposed1.rs index 0e34c5c98fc1..a6c67f89980c 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write_despite_exposed1.rs @@ -1,4 +1,6 @@ +//@revisions: stack tree //@compile-flags: -Zmiri-permissive-provenance +//@[tree]compile-flags: -Zmiri-tree-borrows fn main() { unsafe { @@ -12,6 +14,9 @@ fn main() { // (The write is still fine, using the `root as *mut i32` provenance which got exposed.) *exposed_ptr = 0; // Stack: Unknown( at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs:LL:CC + --> tests/fail/both_borrows/illegal_write_despite_exposed1.rs:LL:CC | LL | let _val = *root2; | ^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4] @@ -7,12 +7,12 @@ LL | let _val = *root2; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadOnly retag at offsets [0x0..0x4] - --> tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs:LL:CC + --> tests/fail/both_borrows/illegal_write_despite_exposed1.rs:LL:CC | LL | let root2 = &*exposed_ptr; | ^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] by a write access - --> tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs:LL:CC + --> tests/fail/both_borrows/illegal_write_despite_exposed1.rs:LL:CC | LL | *exposed_ptr = 0; | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write_despite_exposed1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write_despite_exposed1.tree.stderr new file mode 100644 index 000000000000..2f6f7eb5e9db --- /dev/null +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write_despite_exposed1.tree.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden + --> tests/fail/both_borrows/illegal_write_despite_exposed1.rs:LL:CC + | +LL | let _val = *root2; + | ^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Disabled which forbids this child read access +help: the accessed tag was created here, in the initial state Frozen + --> tests/fail/both_borrows/illegal_write_despite_exposed1.rs:LL:CC + | +LL | let root2 = &*exposed_ptr; + | ^^^^^^^^^^^^^ +help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] + --> tests/fail/both_borrows/illegal_write_despite_exposed1.rs:LL:CC + | +LL | *exposed_ptr = 0; + | ^^^^^^^^^^^^^^^^ + = help: this transition corresponds to a loss of read permissions + +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/tree_borrows/wildcard/cross_tree_from_main.rs b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_from_main.rs new file mode 100644 index 000000000000..40099076f627 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_from_main.rs @@ -0,0 +1,36 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance + +/// Checks how accesses from one subtree affect other subtrees. +/// This test checks the case where the access is to the main tree. +pub fn main() { + let mut x: u32 = 42; + + let ptr_base = &mut x as *mut u32; + let ref1 = unsafe { &mut *ptr_base }; + let ref2 = unsafe { &mut *ptr_base }; + + let int1 = ref1 as *mut u32 as usize; + let wild = int1 as *mut u32; + + let reb3 = unsafe { &mut *wild }; + + // ┌────────────┐ + // │ │ + // │ ptr_base ├───────────┐ * + // │ │ │ │ + // └──────┬─────┘ │ │ + // │ │ │ + // │ │ │ + // ▼ ▼ ▼ + // ┌────────────┐ ┌───────────┐ ┌───────────┐ + // │ │ │ │ │ │ + // │ ref1(Res)* │ │ ref2(Res) │ │ reb3(Res) │ + // │ │ │ │ │ │ + // └────────────┘ └───────────┘ └───────────┘ + + // ref2 is part of the main tree and therefore foreign to all subtrees. + // Therefore, this disables reb3. + *ref2 = 13; + + let _fail = *reb3; //~ ERROR: /read access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_from_main.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_from_main.stderr new file mode 100644 index 000000000000..bdd75027c1f3 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_from_main.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/wildcard/cross_tree_from_main.rs:LL:CC + | +LL | let _fail = *reb3; + | ^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Disabled which forbids this child read access +help: the accessed tag was created here, in the initial state Reserved + --> tests/fail/tree_borrows/wildcard/cross_tree_from_main.rs:LL:CC + | +LL | let reb3 = unsafe { &mut *wild }; + | ^^^^^^^^^^ +help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] + --> tests/fail/tree_borrows/wildcard/cross_tree_from_main.rs:LL:CC + | +LL | *ref2 = 13; + | ^^^^^^^^^^ + = help: this transition corresponds to a loss of read and write permissions + +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/tree_borrows/wildcard/cross_tree_update_main.rs b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main.rs new file mode 100644 index 000000000000..a21dcfe2acf5 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main.rs @@ -0,0 +1,37 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance + +/// Checks how accesses from one subtree affect other subtrees. +/// This tests how main is effected by an access through a subtree. +pub fn main() { + let mut x: u32 = 42; + + let ptr_base = &mut x as *mut u32; + let ref1 = unsafe { &mut *ptr_base }; + let ref2 = unsafe { &mut *ptr_base }; + + let int1 = ref1 as *mut u32 as usize; + let wild = int1 as *mut u32; + + let reb = unsafe { &mut *wild }; + + // ┌────────────┐ + // │ │ + // │ ptr_base ├───────────┐ * + // │ │ │ │ + // └──────┬─────┘ │ │ + // │ │ │ + // │ │ │ + // ▼ ▼ ▼ + // ┌────────────┐ ┌───────────┐ ┌───────────┐ + // │ │ │ │ │ │ + // │ ref1(Res)* │ │ ref2(Res) │ │ reb(Res) │ + // │ │ │ │ │ │ + // └────────────┘ └───────────┘ └───────────┘ + + // Writes through the reborrowed reference causing a wildcard + // write on the main tree. This disables ref2 as it doesn't + // have any exposed children. + *reb = 13; + + let _fail = *ref2; //~ ERROR: /read access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main.stderr new file mode 100644 index 000000000000..285ffc4763df --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/wildcard/cross_tree_update_main.rs:LL:CC + | +LL | let _fail = *ref2; + | ^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Disabled which forbids this child read access +help: the accessed tag was created here, in the initial state Reserved + --> tests/fail/tree_borrows/wildcard/cross_tree_update_main.rs:LL:CC + | +LL | let ref2 = unsafe { &mut *ptr_base }; + | ^^^^^^^^^^^^^^ +help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] + --> tests/fail/tree_borrows/wildcard/cross_tree_update_main.rs:LL:CC + | +LL | *reb = 13; + | ^^^^^^^^^ + = help: this transition corresponds to a loss of read and write permissions + +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/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed.rs b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed.rs new file mode 100644 index 000000000000..641ffb4304d5 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed.rs @@ -0,0 +1,44 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance + +/// Checks how accesses from one subtree affect other subtrees. +/// This test checks that an access from a subtree performs a +/// wildcard access on all earlier trees, and that local +/// accesses are treated as access errors for tags that are +/// larger than the root of the accessed subtree. +pub fn main() { + let mut x: u32 = 42; + + let ptr_base = &mut x as *mut u32; + let ref1 = unsafe { &mut *ptr_base }; + + // Activates ref1. + *ref1 = 4; + + let int1 = ref1 as *mut u32 as usize; + let wild = int1 as *mut u32; + + let ref2 = unsafe { &mut *wild }; + + // Freezes ref1. + let ref3 = unsafe { &mut *ptr_base }; + let _int3 = ref3 as *mut u32 as usize; + + // ┌──────────────┐ + // │ │ + // │ptr_base(Act) ├───────────┐ * + // │ │ │ │ + // └──────┬───────┘ │ │ + // │ │ │ + // │ │ │ + // ▼ ▼ ▼ + // ┌─────────────┐ ┌────────────┐ ┌───────────┐ + // │ │ │ │ │ │ + // │ ref1(Frz)* │ │ ref3(Res)* │ │ ref2(Res) │ + // │ │ │ │ │ │ + // └─────────────┘ └────────────┘ └───────────┘ + + // Performs a wildcard access on the main root. However, as there are + // no exposed tags with write permissions and a tag smaller than ref2 + // this access fails. + *ref2 = 13; //~ ERROR: /write access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed.stderr new file mode 100644 index 000000000000..3d91ec4db882 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed.stderr @@ -0,0 +1,14 @@ +error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed.rs:LL:CC + | +LL | *ref2 = 13; + | ^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: there are no exposed tags which may perform this access here + +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/tree_borrows/wildcard/cross_tree_update_newer.rs b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer.rs new file mode 100644 index 000000000000..a65508c78b59 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer.rs @@ -0,0 +1,47 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance + +/// Checks how accesses from one subtree affect other subtrees. +/// This test checks that an access from an earlier created subtree +/// is foreign to a later created one. +pub fn main() { + let mut x: u32 = 42; + + let ref_base = &mut x; + + let int0 = ref_base as *mut u32 as usize; + let wild = int0 as *mut u32; + + let reb1 = unsafe { &mut *wild }; + + let reb2 = unsafe { &mut *wild }; + + let ref3 = &mut *reb1; + let _int3 = ref3 as *mut u32 as usize; + // ┌──────────────┐ + // │ │ + // │ptr_base(Res)*│ * * + // │ │ │ │ + // └──────────────┘ │ │ + // │ │ + // │ │ + // ▼ ▼ + // ┌────────────┐ ┌────────────┐ + // │ │ │ │ + // │ reb1(Res) ├ │ reb2(Res) ├ + // │ │ │ │ + // └──────┬─────┘ └────────────┘ + // │ + // │ + // ▼ + // ┌────────────┐ + // │ │ + // │ ref3(Res)* │ + // │ │ + // └────────────┘ + + // This access disables reb2 because ref3 cannot be a child of it + // as reb2 both has a higher tag and doesn't have any exposed children. + *ref3 = 13; + + let _fail = *reb2; //~ ERROR: /read access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer.stderr new file mode 100644 index 000000000000..c1ab12f3405b --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/wildcard/cross_tree_update_newer.rs:LL:CC + | +LL | let _fail = *reb2; + | ^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Disabled which forbids this child read access +help: the accessed tag was created here, in the initial state Reserved + --> tests/fail/tree_borrows/wildcard/cross_tree_update_newer.rs:LL:CC + | +LL | let reb2 = unsafe { &mut *wild }; + | ^^^^^^^^^^ +help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] + --> tests/fail/tree_borrows/wildcard/cross_tree_update_newer.rs:LL:CC + | +LL | *ref3 = 13; + | ^^^^^^^^^^ + = help: this transition corresponds to a loss of read and write permissions + +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/tree_borrows/wildcard/cross_tree_update_newer_exposed.rs b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer_exposed.rs new file mode 100644 index 000000000000..666eac1e7e61 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer_exposed.rs @@ -0,0 +1,48 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance + +/// Checks how accesses from one subtree affect other subtrees. +/// This test checks that an access from an earlier created subtree +/// is foreign to a later created one. +pub fn main() { + let mut x: u32 = 42; + + let ref_base = &mut x; + + let int0 = ref_base as *mut u32 as usize; + let wild = int0 as *mut u32; + + let reb1 = unsafe { &mut *wild }; + + let reb2 = unsafe { &mut *wild }; + let _int2 = reb2 as *mut u32 as usize; + + let ref3 = &mut *reb1; + let _int3 = ref3 as *mut u32 as usize; + // ┌──────────────┐ + // │ │ + // │ptr_base(Res)*│ * * + // │ │ │ │ + // └──────────────┘ │ │ + // │ │ + // │ │ + // ▼ ▼ + // ┌────────────┐ ┌────────────┐ + // │ │ │ │ + // │ reb1(Res) │ │ reb2(Res)* │ + // │ │ │ │ + // └──────┬─────┘ └────────────┘ + // │ + // │ + // ▼ + // ┌────────────┐ + // │ │ + // │ ref3(Res)* │ + // │ │ + // └────────────┘ + + // This access disables reb2 because ref3 cannot be a child of it + // as ref3's root has a lower tag than reb2. + *ref3 = 13; + + let _fail = *reb2; //~ ERROR: /read access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer_exposed.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer_exposed.stderr new file mode 100644 index 000000000000..e1232c751192 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_newer_exposed.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/wildcard/cross_tree_update_newer_exposed.rs:LL:CC + | +LL | let _fail = *reb2; + | ^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Disabled which forbids this child read access +help: the accessed tag was created here, in the initial state Reserved + --> tests/fail/tree_borrows/wildcard/cross_tree_update_newer_exposed.rs:LL:CC + | +LL | let reb2 = unsafe { &mut *wild }; + | ^^^^^^^^^^ +help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] + --> tests/fail/tree_borrows/wildcard/cross_tree_update_newer_exposed.rs:LL:CC + | +LL | *ref3 = 13; + | ^^^^^^^^^^ + = help: this transition corresponds to a loss of read and write permissions + +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/tree_borrows/wildcard/cross_tree_update_older.rs b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older.rs new file mode 100644 index 000000000000..35fbc30ff50b --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older.rs @@ -0,0 +1,47 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance + +/// Checks how accesses from one subtree affect other subtrees. +/// This test checks that an access from a newer created subtree +/// performs a wildcard access on all earlier trees. +pub fn main() { + let mut x: u32 = 42; + + let ref_base = &mut x; + + let int0 = ref_base as *mut u32 as usize; + let wild = int0 as *mut u32; + + let reb1 = unsafe { &mut *wild }; + + let reb2 = unsafe { &mut *wild }; + + let ref3 = &mut *reb2; + let _int3 = ref3 as *mut u32 as usize; + // ┌──────────────┐ + // │ │ + // │ptr_base(Res)*│ * * + // │ │ │ │ + // └──────────────┘ │ │ + // │ │ + // │ │ + // ▼ ▼ + // ┌────────────┐ ┌────────────┐ + // │ │ │ │ + // │ reb1(Res) ├ │ reb2(Res) ├ + // │ │ │ │ + // └────────────┘ └──────┬─────┘ + // │ + // │ + // ▼ + // ┌────────────┐ + // │ │ + // │ ref3(Res)* │ + // │ │ + // └────────────┘ + + // this access disables reb2 because ref3 cannot be a child of it + // as reb1 does not have any exposed children. + *ref3 = 13; + + let _fail = *reb1; //~ ERROR: /read access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older.stderr new file mode 100644 index 000000000000..54f041b555cb --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/wildcard/cross_tree_update_older.rs:LL:CC + | +LL | let _fail = *reb1; + | ^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Disabled which forbids this child read access +help: the accessed tag was created here, in the initial state Reserved + --> tests/fail/tree_borrows/wildcard/cross_tree_update_older.rs:LL:CC + | +LL | let reb1 = unsafe { &mut *wild }; + | ^^^^^^^^^^ +help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] + --> tests/fail/tree_borrows/wildcard/cross_tree_update_older.rs:LL:CC + | +LL | *ref3 = 13; + | ^^^^^^^^^^ + = help: this transition corresponds to a loss of read and write permissions + +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/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed.rs b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed.rs new file mode 100644 index 000000000000..0f87bb445fcd --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed.rs @@ -0,0 +1,53 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance + +/// Checks how accesses from one subtree affect other subtrees. +/// This test checks that an access from a newer created subtree +/// performs a wildcard access on all earlier trees, and that +/// either accesses are treated as foreign for tags that are +/// larger than the root of the accessed subtree. +pub fn main() { + let mut x: u32 = 42; + + let ref_base = &mut x; + + let int0 = ref_base as *mut u32 as usize; + let wild = int0 as *mut u32; + + let reb1 = unsafe { &mut *wild }; + + let reb2 = unsafe { &mut *wild }; + + let ref3 = &mut *reb1; + let _int3 = ref3 as *mut u32 as usize; + + let ref4 = &mut *reb2; + let _int4 = ref4 as *mut u32 as usize; + // ┌──────────────┐ + // │ │ + // │ptr_base(Res)*│ * * + // │ │ │ │ + // └──────────────┘ │ │ + // │ │ + // │ │ + // ▼ ▼ + // ┌────────────┐ ┌────────────┐ + // │ │ │ │ + // │ reb1(Res) ├ │ reb2(Res) ├ + // │ │ │ │ + // └──────┬─────┘ └──────┬─────┘ + // │ │ + // │ │ + // ▼ ▼ + // ┌────────────┐ ┌────────────┐ + // │ │ │ │ + // │ ref3(Res)* │ │ ref4(Res)* │ + // │ │ │ │ + // └────────────┘ └────────────┘ + + // This access disables ref3 and reb1 because ref4 cannot be a child of it + // as reb2 has a smaller tag than ref3. + *ref4 = 13; + + // Fails because ref3 is disabled. + let _fail = *ref3; //~ ERROR: /read access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed.stderr new file mode 100644 index 000000000000..66787ef72f14 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed.rs:LL:CC + | +LL | let _fail = *ref3; + | ^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Disabled which forbids this child read access +help: the accessed tag was created here, in the initial state Reserved + --> tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed.rs:LL:CC + | +LL | let ref3 = &mut *reb1; + | ^^^^^^^^^^ +help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] + --> tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed.rs:LL:CC + | +LL | *ref4 = 13; + | ^^^^^^^^^^ + = help: this transition corresponds to a loss of read and write permissions + +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/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed2.rs b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed2.rs new file mode 100644 index 000000000000..f01ac26dc69c --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed2.rs @@ -0,0 +1,59 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance + +/// Checks how accesses from one subtree affect other subtrees. +/// This test checks that an access from a newer created subtree +/// performs a wildcard access on all earlier trees, and that +/// either accesses are treated as foreign for tags that are +/// larger than the root of the accessed subtree. +/// This tests the special case where these updates get propagated +/// up the tree. +pub fn main() { + let mut x: u32 = 42; + + let ref_base = &mut x; + + let int0 = ref_base as *mut u32 as usize; + let wild = int0 as *mut u32; + + let reb1 = unsafe { &mut *wild }; + + let reb2 = unsafe { &mut *wild }; + + let ref3 = &mut *reb1; + let _int3 = ref3 as *mut u32 as usize; + + let ref4 = &mut *reb2; + let _int4 = ref4 as *mut u32 as usize; + // ┌──────────────┐ + // │ │ + // │ptr_base(Res)*│ * * + // │ │ │ │ + // └──────────────┘ │ │ + // │ │ + // │ │ + // ▼ ▼ + // ┌────────────┐ ┌────────────┐ + // │ │ │ │ + // │ reb1(Res) ├ │ reb2(Res) ├ + // │ │ │ │ + // └──────┬─────┘ └──────┬─────┘ + // │ │ + // │ │ + // ▼ ▼ + // ┌────────────┐ ┌────────────┐ + // │ │ │ │ + // │ ref3(Res)* │ │ ref4(Res)* │ + // │ │ │ │ + // └────────────┘ └────────────┘ + + // This access disables ref3 and reb1 because ref4 cannot be a child of it + // as reb2 has a smaller tag than ref3. + // + // Because of the update order during a wildcard access (child before parent) + // ref3 gets disabled before we update reb1. So reb1 has no exposed children + // with write access at the time it gets updated so it also gets disabled. + *ref4 = 13; + + // Fails because reb1 is disabled. + let _fail = *reb1; //~ ERROR: /read access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed2.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed2.stderr new file mode 100644 index 000000000000..644d30cae035 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed2.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed2.rs:LL:CC + | +LL | let _fail = *reb1; + | ^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Disabled which forbids this child read access +help: the accessed tag was created here, in the initial state Reserved + --> tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed2.rs:LL:CC + | +LL | let reb1 = unsafe { &mut *wild }; + | ^^^^^^^^^^ +help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] + --> tests/fail/tree_borrows/wildcard/cross_tree_update_older_invalid_exposed2.rs:LL:CC + | +LL | *ref4 = 13; + | ^^^^^^^^^^ + = help: this transition corresponds to a loss of read and write permissions + +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/tree_borrows/wildcard/protected_wildcard.rs b/src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.rs new file mode 100644 index 000000000000..18fe931b9e35 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.rs @@ -0,0 +1,39 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance + +/// Checks if we pass a reference derived from a wildcard pointer +/// that it gets correctly protected. +pub fn main() { + let mut x: u32 = 32; + let ref1 = &mut x; + + let ref2 = &mut *ref1; + let int2 = ref2 as *mut u32 as usize; + + let wild = int2 as *mut u32; + let wild_ref = unsafe { &mut *wild }; + + let mut protect = |_arg: &mut u32| { + // _arg is a protected pointer with wildcard parent. + + // ┌────────────┐ + // │ │ + // │ ref1(Res) │ * + // │ │ │ + // └──────┬─────┘ │ + // │ │ + // │ │ + // ▼ ▼ + // ┌────────────┐ ┌────────────┐ + // │ │ │ │ + // │ ref2(Res)* │ │ _arg(Res) │ + // │ │ │ │ + // └────────────┘ └────────────┘ + + // Writes to ref1, causing a foreign write to ref2 and _arg. + // Since _arg is protected this is UB. + *ref1 = 13; //~ ERROR: /write access through .* is forbidden/ + }; + + // We pass a pointer with wildcard provenance to the function. + protect(wild_ref); +} diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.stderr new file mode 100644 index 000000000000..e257a3511f75 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.stderr @@ -0,0 +1,37 @@ +error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/wildcard/protected_wildcard.rs:LL:CC + | +LL | *ref1 = 13; + | ^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag is foreign to the protected tag (i.e., it is not a child) + = help: this foreign write access would cause the protected tag (currently Reserved) to become Disabled + = help: protected tags must never be Disabled +help: the accessed tag was created here + --> tests/fail/tree_borrows/wildcard/protected_wildcard.rs:LL:CC + | +LL | let mut protect = |_arg: &mut u32| { + | _______________________^ +... | +LL | | *ref1 = 13; +LL | | }; + | |_____^ +help: the protected tag was created here, in the initial state Reserved + --> tests/fail/tree_borrows/wildcard/protected_wildcard.rs:LL:CC + | +LL | let mut protect = |_arg: &mut u32| { + | ^^^^ + = note: BACKTRACE (of the first span): + = note: inside closure at tests/fail/tree_borrows/wildcard/protected_wildcard.rs:LL:CC +note: inside `main` + --> tests/fail/tree_borrows/wildcard/protected_wildcard.rs:LL:CC + | +LL | protect(wild_ref); + | ^^^^^^^^^^^^^^^^^ + +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/tree_borrows/wildcard/strongly_protected_wildcard.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.stderr index de92cf91e3e8..6e115b22feb1 100644 --- a/src/tools/miri/tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: deallocation through at ALLOC[0x0] is forbidden +error: Undefined Behavior: deallocation through at ALLOC[0x0] is forbidden --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | self.1.deallocate(From::from(ptr.cast()), layout); @@ -6,8 +6,13 @@ LL | self.1.deallocate(From::from(ptr.cast()), layout); | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information - = help: the allocation of the accessed tag also contains the strongly protected tag + = help: the allocation of the accessed tag also contains the strongly protected tag = help: the strongly protected tag disallows deallocations +help: the accessed tag was created here + --> tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC + | +LL | drop(unsafe { Box::from_raw(raw as *mut i32) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the strongly protected tag was created here, in the initial state Reserved --> tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness.rs b/src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness.rs new file mode 100644 index 000000000000..7ce243abcefc --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness.rs @@ -0,0 +1,44 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance + +// Checks if we correctly infer the relatedness of nodes that are +// part of the same wildcard root. +pub fn main() { + let mut x: u32 = 42; + + let ref_base = &mut x; + + let int1 = ref_base as *mut u32 as usize; + let wild = int1 as *mut u32; + + let reb = unsafe { &mut *wild }; + let ptr_reb = reb as *mut u32; + let ref1 = unsafe { &mut *ptr_reb }; + let ref2 = unsafe { &mut *ptr_reb }; + + // ┌──────────────┐ + // │ │ + // │ptr_base(Res)*│ * + // │ │ │ + // └──────────────┘ │ + // │ + // │ + // ▼ + // ┌────────────┐ + // │ │ + // │ reb(Res) ├───────────┐ + // │ │ │ + // └──────┬─────┘ │ + // │ │ + // │ │ + // ▼ ▼ + // ┌────────────┐ ┌───────────┐ + // │ │ │ │ + // │ ref1(Res) │ │ ref2(Res) │ + // │ │ │ │ + // └────────────┘ └───────────┘ + + // ref1 is foreign to ref2, so this should disable ref2. + *ref1 = 13; + + let _fail = *ref2; //~ ERROR: /read access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness.stderr new file mode 100644 index 000000000000..4b4f73a73b79 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/wildcard/subtree_internal_relatedness.rs:LL:CC + | +LL | let _fail = *ref2; + | ^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Disabled which forbids this child read access +help: the accessed tag was created here, in the initial state Reserved + --> tests/fail/tree_borrows/wildcard/subtree_internal_relatedness.rs:LL:CC + | +LL | let ref2 = unsafe { &mut *ptr_reb }; + | ^^^^^^^^^^^^^ +help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] + --> tests/fail/tree_borrows/wildcard/subtree_internal_relatedness.rs:LL:CC + | +LL | *ref1 = 13; + | ^^^^^^^^^^ + = help: this transition corresponds to a loss of read and write permissions + +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/tree_borrows/wildcard/subtree_internal_relatedness_wildcard.rs b/src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness_wildcard.rs new file mode 100644 index 000000000000..7b115f788ae6 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness_wildcard.rs @@ -0,0 +1,49 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance + +// Checks if we correctly infer the relatedness of nodes that are +// part of the same wildcard root during a wildcard access. +pub fn main() { + let mut x: u32 = 42; + + let ref_base = &mut x; + + let int = ref_base as *mut u32 as usize; + let wild = int as *mut u32; + + let reb = unsafe { &mut *wild }; + let ptr_reb = reb as *mut u32; + let ref1 = unsafe { &mut *ptr_reb }; + let _int1 = ref1 as *mut u32 as usize; + let ref2 = unsafe { &mut *ptr_reb }; + + // ┌──────────────┐ + // │ │ + // │ptr_base(Res)*│ * + // │ │ │ + // └──────────────┘ │ + // │ + // │ + // ▼ + // ┌────────────┐ + // │ │ + // │ reb(Res) ├───────────┐ + // │ │ │ + // └──────┬─────┘ │ + // │ │ + // │ │ + // ▼ ▼ + // ┌────────────┐ ┌───────────┐ + // │ │ │ │ + // │ ref1(Res)* │ │ ref2(Res) │ + // │ │ │ │ + // └────────────┘ └───────────┘ + + // Writes either through ref1 or ptr_base. + // This disables ref2 as the access is foreign to it in either case. + unsafe { *wild = 13 }; + + // This is fine because the earlier write could have come from ref1. + let _succ = *ref1; + // ref2 is disabled so this fails. + let _fail = *ref2; //~ ERROR: /read access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness_wildcard.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness_wildcard.stderr new file mode 100644 index 000000000000..e1a8bebe91c9 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/subtree_internal_relatedness_wildcard.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: read access through at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/wildcard/subtree_internal_relatedness_wildcard.rs:LL:CC + | +LL | let _fail = *ref2; + | ^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Disabled which forbids this child read access +help: the accessed tag was created here, in the initial state Reserved + --> tests/fail/tree_borrows/wildcard/subtree_internal_relatedness_wildcard.rs:LL:CC + | +LL | let ref2 = unsafe { &mut *ptr_reb }; + | ^^^^^^^^^^^^^ +help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4] + --> tests/fail/tree_borrows/wildcard/subtree_internal_relatedness_wildcard.rs:LL:CC + | +LL | unsafe { *wild = 13 }; + | ^^^^^^^^^^ + = help: this transition corresponds to a loss of read and write permissions + +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/tree_borrows/write_to_shr.stderr b/src/tools/miri/tests/fail/tree_borrows/write_to_shr.stderr deleted file mode 100644 index f57b28cbf44c..000000000000 --- a/src/tools/miri/tests/fail/tree_borrows/write_to_shr.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: Undefined Behavior: write access through is forbidden - --> $DIR/write_to_shr.rs:LL:CC - | -LL | *xmut = 31; - | ^^^^^^^^^^ write access through is forbidden - | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental - = help: the accessed tag is a child of the conflicting tag - = help: the conflicting tag has state Frozen which forbids child write accesses -help: the accessed tag was created here - --> $DIR/write_to_shr.rs:LL:CC - | -LL | let xmut = unsafe { &mut *(xref as *const u64 as *mut u64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: the conflicting tag was created here, in the initial state Frozen - --> $DIR/write_to_shr.rs:LL:CC - | -LL | let xref = unsafe { &*(x as *mut u64) }; - | ^^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/write_to_shr.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/pass/tree_borrows/wildcard/formatting.rs b/src/tools/miri/tests/pass/tree_borrows/wildcard/formatting.rs new file mode 100644 index 000000000000..1f6b797a3d77 --- /dev/null +++ b/src/tools/miri/tests/pass/tree_borrows/wildcard/formatting.rs @@ -0,0 +1,36 @@ +// We disable the GC for this test because it would change what is printed. +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance -Zmiri-provenance-gc=0 + +#[path = "../../../utils/mod.rs"] +#[macro_use] +mod utils; + +fn main() { + unsafe { + let x = &0u8; + name!(x); + let xa = &*x; + name!(xa); + let xb = &*x; + name!(xb); + let wild = xb as *const u8 as usize as *const u8; + + let y = &*wild; + name!(y); + let ya = &*y; + name!(ya); + let yb = &*y; + name!(yb); + let _int = ya as *const u8 as usize; + + let z = &*wild; + name!(z); + + let u = &*wild; + name!(u); + let ua = &*u; + name!(ua); + let alloc_id = alloc_id!(x); + print_state!(alloc_id); + } +} diff --git a/src/tools/miri/tests/pass/tree_borrows/wildcard/formatting.stderr b/src/tools/miri/tests/pass/tree_borrows/wildcard/formatting.stderr new file mode 100644 index 000000000000..583c84534395 --- /dev/null +++ b/src/tools/miri/tests/pass/tree_borrows/wildcard/formatting.stderr @@ -0,0 +1,17 @@ +────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Act | └─┬── +| Frz | └─┬── +| Frz | ├──── +| Frz | └──── (exposed) +| | +| Frz | *─┬── +| Frz | ├──── (exposed) +| Frz | └──── +| | +| Frz | *──── +| | +| Frz | *─┬── +| Frz | └──── +────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree_borrows/wildcard/reborrow.rs b/src/tools/miri/tests/pass/tree_borrows/wildcard/reborrow.rs new file mode 100644 index 000000000000..fbb50d5acd27 --- /dev/null +++ b/src/tools/miri/tests/pass/tree_borrows/wildcard/reborrow.rs @@ -0,0 +1,224 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance + +pub fn main() { + multiple_exposed_siblings1(); + multiple_exposed_siblings2(); + reborrow3(); + returned_mut_is_usable(); + only_foreign_is_temporary(); +} + +/// Checks that accessing through a reborrowed wildcard doesn't +/// disable any exposed reference. +fn multiple_exposed_siblings1() { + let mut x: u32 = 42; + + let ptr_base = &mut x as *mut u32; + + let ref1 = unsafe { &mut *ptr_base }; + let int1 = ref1 as *mut u32 as usize; + + let ref2 = unsafe { &mut *ptr_base }; + let _int2 = ref2 as *mut u32 as usize; + + let wild = int1 as *mut u32; + + let reb = unsafe { &mut *wild }; + + // ┌────────────┐ + // │ │ + // │ ptr_base ├────────────┐ * + // │ │ │ │ + // └──────┬─────┘ │ │ + // │ │ │ + // │ │ │ + // ▼ ▼ ▼ + // ┌────────────┐ ┌────────────┐ ┌────────────┐ + // │ │ │ │ │ │ + // │ ref1(Res)* │ │ ref2(Res)* │ │ reb(Res) │ + // │ │ │ │ │ │ + // └────────────┘ └────────────┘ └────────────┘ + + // Could either have as a parent ref1 or ref2. + // So we can't disable either of them. + *reb = 13; + + // We can still access either ref1 or ref2. + // Although it is actually UB to access both of them. + assert_eq!(*ref2, 13); + assert_eq!(*ref1, 13); +} + +/// Checks that wildcard accesses do not invalidate any exposed +/// nodes through which the access could have happened. +/// It checks this for the case where some reborrowed wildcard +/// pointers are exposed as well. +fn multiple_exposed_siblings2() { + let mut x: u32 = 42; + + let ptr_base = &mut x as *mut u32; + let int = ptr_base as usize; + + let wild = int as *mut u32; + + let reb_ptr = unsafe { &mut *wild } as *mut u32; + + let ref1 = unsafe { &mut *reb_ptr }; + let _int1 = ref1 as *mut u32 as usize; + + let ref2 = unsafe { &mut *reb_ptr }; + let _int2 = ref2 as *mut u32 as usize; + + // ┌────────────┐ + // │ │ + // │ ptr_base* │ * + // │ │ │ + // └────────────┘ │ + // │ + // │ + // ▼ + // ┌────────────┐ + // │ │ + // │ reb ├────────────┐ + // │ │ │ + // └──────┬─────┘ │ + // │ │ + // │ │ + // ▼ ▼ + // ┌────────────┐ ┌────────────┐ + // │ │ │ │ + // │ ref1(Res)* │ │ ref2(Res)* │ + // │ │ │ │ + // └────────────┘ └────────────┘ + + // Writes either through ref1, ref2 or ptr_base, which are all exposed. + // Since we don't know which we do not apply any transitions to any of + // the references. + unsafe { wild.write(13) }; + + // We should be able to access either ref1 or ref2. + // Although it is actually UB to access ref1 and ref2 together. + assert_eq!(*ref2, 13); + assert_eq!(*ref1, 13); +} + +/// Checks that accessing a reborrowed wildcard reference doesn't +/// invalidate other reborrowed wildcard references, if they +/// are also exposed. +fn reborrow3() { + let mut x: u32 = 42; + + let ptr_base = &mut x as *mut u32; + let int = ptr_base as usize; + + let wild = int as *mut u32; + + let reb1 = unsafe { &mut *wild }; + let ref2 = &mut *reb1; + let _int = ref2 as *mut u32 as usize; + + let reb3 = unsafe { &mut *wild }; + + // ┌────────────┐ + // │ │ + // │ ptr_base* │ * * + // │ │ │ │ + // └────────────┘ │ │ + // │ │ + // │ │ + // ▼ ▼ + // ┌────────────┐ ┌────────────┐ + // │ │ │ │ + // │ reb1(Res) | │ reb3(Res) | + // │ │ │ │ + // └──────┬─────┘ └────────────┘ + // │ + // │ + // ▼ + // ┌────────────┐ + // │ │ + // │ ref2(Res)* │ + // │ │ + // └────────────┘ + + // This is the only valid ordering these accesses can happen in. + + // reb3 could be a child of ref2 so we don't disable ref2, reb1. + *reb3 = 1; + // Disables reb3 as it cannot be an ancestor of ref2. + *ref2 = 2; + // Disables ref2 (and reb3 if it wasn't already). + *reb1 = 3; +} + +/// Analogous to same test in `../tree-borrows.rs` but with returning a +/// reborrowed wildcard reference. +fn returned_mut_is_usable() { + let mut x: u32 = 32; + let ref1 = &mut x; + + let y = protect(ref1); + + fn protect(arg: &mut u32) -> &mut u32 { + // Reborrow `arg` through a wildcard. + let int = arg as *mut u32 as usize; + let wild = int as *mut u32; + let ref2 = unsafe { &mut *wild }; + + // Activate the reference so that it is vulnerable to foreign reads. + *ref2 = 42; + + ref2 + // An implicit read through `arg` is inserted here. + } + + *y = 4; +} + +/// When accessing an allocation through a tag that was created from wildcard reference +/// we treat nodes with a larger tag as if the access could only have been foreign to them. +/// This change in access relatedness should not be visible in later accesses. +fn only_foreign_is_temporary() { + let mut x = 0u32; + let wild = &mut x as *mut u32 as usize as *mut u32; + + let reb1 = unsafe { &mut *wild }; + let reb2 = unsafe { &mut *wild }; + let ref3 = &mut *reb1; + let _int = ref3 as *mut u32 as usize; + + let reb4 = unsafe { &mut *wild }; + + // + // + // * * * + // │ │ │ + // │ │ │ + // │ │ │ + // │ │ │ + // ▼ ▼ ▼ + // ┌────────────┐ ┌────────────┐ ┌────────────┐ + // │ │ │ │ │ │ + // │ reb1(Res) │ │ reb2(Res) │ │ reb4(Res) │ + // │ │ │ │ │ │ + // └──────┬─────┘ └────────────┘ └────────────┘ + // │ + // │ + // ▼ + // ┌────────────┐ + // │ │ + // │ ref3(Res)* │ + // │ │ + // └────────────┘ + + // Performs a foreign read on ref3 and doesn't update reb1. + // This temporarily treats ref3 as if only foreign accesses are possible to + // it. This is because the accessed tag reb2 has a larger tag than ref3. + let _x = *reb2; + // Should not update ref3, reb1 as we don't know if the access is local or foreign. + // This should stop treating ref3 as only foreign because the accessed tag reb4 + // has a larger tag than ref3. + *reb4 = 32; + // The previous write could have been local to ref3, so this access should still work. + *ref3 = 4; +} diff --git a/src/tools/miri/tests/pass/tree_borrows/wildcard/undetected_ub.rs b/src/tools/miri/tests/pass/tree_borrows/wildcard/undetected_ub.rs index c34fbcb50119..73392543f7d2 100644 --- a/src/tools/miri/tests/pass/tree_borrows/wildcard/undetected_ub.rs +++ b/src/tools/miri/tests/pass/tree_borrows/wildcard/undetected_ub.rs @@ -4,7 +4,7 @@ pub fn main() { uncertain_provenance(); protected_exposed(); - protected_wildcard(); + cross_tree_update_older_invalid_exposed(); } /// Currently, if we do not know for a tag if an access is local or foreign, @@ -101,45 +101,61 @@ fn protect(ref3: &mut u32) { } protect(ref1); - // ref2 is disabled, so this read causes UB, but we currently don't protect this. + // ref2 should be disabled, so this read causes UB, but we currently don't detect this. let _fail = *ref2; } -/// Currently, we do not assign protectors to wildcard references. -/// This test has UB because it does a foreign write to a protected reference. -/// However, that reference is a wildcard, so this doesn't get detected. -#[allow(unused_variables)] -pub fn protected_wildcard() { - let mut x: u32 = 32; - let ref1 = &mut x; - let ref2 = &mut *ref1; +/// Checks how accesses from one subtree affect other subtrees. +/// This test shows an example where we don't update a node whose exposed +/// children are greater than `max_local_tag`. +pub fn cross_tree_update_older_invalid_exposed() { + let mut x: [u32; 2] = [42, 43]; - let int = ref2 as *mut u32 as usize; - let wild = int as *mut u32; - let wild_ref = unsafe { &mut *wild }; + let ref_base = &mut x; - let mut protect = |arg: &mut u32| { - // arg is a protected pointer with wildcard provenance. + let int0 = ref_base as *mut u32 as usize; + let wild = int0 as *mut u32; - // ┌────────────┐ - // │ │ - // │ ref1(Res) │ - // │ │ - // └──────┬─────┘ - // │ - // │ - // ▼ - // ┌────────────┐ - // │ │ - // │ ref2(Res)* │ - // │ │ - // └────────────┘ + let reb1 = unsafe { &mut *wild }; + *reb1 = 44; - // Writes to ref1, disabling ref2, i.e. disabling all exposed references. - // Since a wildcard reference is protected, this is UB. But we currently don't detect this. - *ref1 = 13; - }; + // We need this reference to be at a different location, + // so that creating it doesn't freeze reb1. + let reb2 = unsafe { &mut *wild.wrapping_add(1) }; + let reb2_ptr = (reb2 as *mut u32).wrapping_sub(1); - // We pass a pointer with wildcard provenance to the function. - protect(wild_ref); + let ref3 = &mut *reb1; + let _int3 = ref3 as *mut u32 as usize; + + // ┌──────────────┐ + // │ │ + // │ptr_base(Res)*│ * * + // │ │ │ │ + // └──────────────┘ │ │ + // │ │ + // │ │ + // ▼ ▼ + // ┌────────────┐ ┌────────────┐ + // │ │ │ │ + // │ reb1(Act) │ │ reb2(Res) │ + // │ │ │ │ + // └──────┬─────┘ └────────────┘ + // │ + // │ + // ▼ + // ┌────────────┐ + // │ │ + // │ ref3(Res)* │ + // │ │ + // └────────────┘ + + // This access doesn't freeze reb1 even though no access could have come from its + // child ref3 (since ref3>reb2). This is because ref3 doesnt get disabled during this + // access. + // + // ref3 doesn't get frozen because it's still reserved. + let _y = unsafe { *reb2_ptr }; + + // reb1 should be frozen so a write should be UB. But we currently don't detect this. + *reb1 = 4; } diff --git a/src/tools/miri/tests/pass/tree_borrows/wildcard/wildcard.rs b/src/tools/miri/tests/pass/tree_borrows/wildcard/wildcard.rs index c406bfe01f62..01385313dc1e 100644 --- a/src/tools/miri/tests/pass/tree_borrows/wildcard/wildcard.rs +++ b/src/tools/miri/tests/pass/tree_borrows/wildcard/wildcard.rs @@ -151,7 +151,6 @@ fn protector_conflicted_release() { /// Analogous to same test in `../tree-borrows.rs` but with a protected wildcard reference. fn returned_mut_is_usable() { - // NOTE: Currently we ignore protectors on wildcard references. fn reborrow(x: &mut u8) -> &mut u8 { let y = &mut *x; // Activate the reference so that it is vulnerable to foreign reads. diff --git a/src/tools/miri/tests/utils/macros.rs b/src/tools/miri/tests/utils/macros.rs index 3f5b9f78ee01..25f40ed994f6 100644 --- a/src/tools/miri/tests/utils/macros.rs +++ b/src/tools/miri/tests/utils/macros.rs @@ -9,7 +9,7 @@ /// The id obtained can be passed directly to `print_state!`. macro_rules! alloc_id { ($ptr:expr) => { - $crate::utils::miri_get_alloc_id($ptr as *const u8 as *const ()) + $crate::utils::miri_get_alloc_id($ptr as *const _ as *const ()) }; } @@ -52,6 +52,6 @@ macro_rules! name { }; ($ptr:expr => $nth_parent:expr, $name:expr) => { let name = $name.as_bytes(); - $crate::utils::miri_pointer_name($ptr as *const u8 as *const (), $nth_parent, name); + $crate::utils::miri_pointer_name($ptr as *const _ as *const (), $nth_parent, name); }; } From eb03ea4435fe93f4688d1a0ae61e266cfa53f845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 3 Dec 2025 16:20:30 +0100 Subject: [PATCH 263/585] Revert "implement and test `Iterator::{exactly_one, collect_array}`" This reverts commit 699184bba4f5e6df163d5d08883e09509ac79e86. --- library/core/src/iter/traits/iterator.rs | 56 ------------------------ 1 file changed, 56 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f89838208651..29230b166538 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -4034,62 +4034,6 @@ unsafe fn __iterator_get_unchecked(&mut self, _idx: usize) -> Self::Item { unreachable!("Always specialized"); } - - /// Checks if the iterator contains *exactly* one element. - /// If so, returns this one element. - /// - /// See also [`collect_array`](Iterator::collect_array) for lengths other than `1`. - /// - /// # Examples - /// - /// ``` - /// #![feature(exact_length_collection)] - /// - /// assert_eq!([1].into_iter().exactly_one(), Some(1)); - /// assert_eq!([].into_iter().exactly_one(), None::<()>); - /// - /// // There is exactly one even integer in the array: - /// assert_eq!([1, 2, 3].into_iter().filter(|x| x % 2 == 0).exactly_one(), Some(2)); - /// // But there are two odds, which is too many: - /// assert_eq!([1, 2, 3].into_iter().filter(|x| x % 2 == 1).exactly_one(), None); - /// ``` - #[inline] - #[unstable(feature = "exact_length_collection", issue = "149266")] - fn exactly_one(self) -> Option - where - Self: Sized, - { - self.collect_array::<1>().map(|[i]| i) - } - - /// Checks if an iterator has *exactly* `N` elements. - /// If so, returns those `N` elements in an array. - /// - /// See also [`exactly_one`](Iterator::exactly_one) when expecting a single element. - /// - /// # Examples - /// - /// ``` - /// #![feature(exact_length_collection)] - /// - /// assert_eq!([1, 2, 3, 4].into_iter().collect_array(), Some([1, 2, 3, 4])); - /// assert_eq!([1, 2].into_iter().chain([3, 4]).collect_array(), Some([1, 2, 3, 4])); - /// - /// // Iterator contains too few elements: - /// assert_eq!([1, 2].into_iter().collect_array::<4>(), None); - /// // Iterator contains too many elements: - /// assert_eq!([1, 2, 3, 4, 5].into_iter().collect_array::<4>(), None); - /// // Taking 4 makes it work again: - /// assert_eq!([1, 2, 3, 4, 5].into_iter().take(4).collect_array(), Some([1, 2, 3, 4])); - /// ``` - #[inline] - #[unstable(feature = "exact_length_collection", issue = "149266")] - fn collect_array(mut self) -> Option<[Self::Item; N]> - where - Self: Sized, - { - self.next_chunk().ok().filter(|_| self.next().is_none()) - } } trait SpecIterEq: Iterator { From c3407323ada81bac2341fa3947fd00660bf7729b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 3 Dec 2025 16:22:57 +0100 Subject: [PATCH 264/585] Revert "fixup warnings around the compiler" This reverts commit f20175293aa8372766250e56e2570f3c06640e0b. --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 3 +-- src/librustdoc/html/format.rs | 6 ++---- src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs | 6 ++---- tests/ui/const-generics/type-dependent/issue-71805.rs | 4 ++-- tests/ui/mir/mir-inlining/ice-issue-77564.rs | 7 +++---- 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 5a49d0f07a49..6dff79374f20 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -86,8 +86,7 @@ fn get_dylib_metadata(&self, target: &Target, path: &Path) -> Result { let lib = lib.map_err(|e| { format!("failed to parse aix dylib '{}': {}", path.display(), e) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 2b9562f26574..eee13ff2b0dc 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1126,8 +1126,7 @@ pub(crate) fn print_impl( } if impl_.kind.is_fake_variadic() && let Some(generics) = ty.generics() - // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 - && let Ok(inner_type) = Itertools::exactly_one(generics) + && let Ok(inner_type) = generics.exactly_one() { let last = ty.last(); if f.alternate() { @@ -1207,8 +1206,7 @@ fn print_type( } } else if let clean::Type::Path { path } = type_ && let Some(generics) = path.generics() - // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 - && let Ok(ty) = Itertools::exactly_one(generics) + && let Ok(ty) = generics.exactly_one() && self.kind.is_fake_variadic() { print_anchor(path.def_id(), path.last(), cx).fmt(f)?; diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 08e7c7593cb2..0d783fde3313 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -92,8 +92,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { (matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir_attrs(v.hir_id))) .then_some((v.def_id, v.span)) }); - // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 - if let Ok((id, span)) = Itertools::exactly_one(iter) + if let Ok((id, span)) = iter.exactly_one() && !find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(..)) { self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); @@ -105,8 +104,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { .iter() .filter(|field| !cx.effective_visibilities.is_exported(field.def_id)); if fields.len() > 1 - // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 - && let Ok(field) = Itertools::exactly_one(private_fields) + && let Ok(field) = private_fields.exactly_one() && let TyKind::Tup([]) = field.ty.kind { span_lint_and_then( diff --git a/tests/ui/const-generics/type-dependent/issue-71805.rs b/tests/ui/const-generics/type-dependent/issue-71805.rs index de04a809da60..27c101df107c 100644 --- a/tests/ui/const-generics/type-dependent/issue-71805.rs +++ b/tests/ui/const-generics/type-dependent/issue-71805.rs @@ -4,7 +4,7 @@ trait CollectSlice<'a>: Iterator { fn inner_array(&mut self) -> [Self::Item; N]; - fn custom_collect_array(&mut self) -> [Self::Item; N] { + fn collect_array(&mut self) -> [Self::Item; N] { let result = self.inner_array(); assert!(self.next().is_none()); result @@ -34,5 +34,5 @@ impl<'a, I: ?Sized> CollectSlice<'a> for I fn main() { let mut foos = [0u64; 9].iter().cloned(); - let _bar: [u64; 9] = foos.custom_collect_array::<9_usize>(); + let _bar: [u64; 9] = foos.collect_array::<9_usize>(); } diff --git a/tests/ui/mir/mir-inlining/ice-issue-77564.rs b/tests/ui/mir/mir-inlining/ice-issue-77564.rs index 256ff295184d..fce6d1d174f6 100644 --- a/tests/ui/mir/mir-inlining/ice-issue-77564.rs +++ b/tests/ui/mir/mir-inlining/ice-issue-77564.rs @@ -29,11 +29,10 @@ impl CollectArray for I fn main() { assert_eq!( - CollectArray::collect_array( - &mut [[1, 2], [3, 4]] + [[1, 2], [3, 4]] .iter() - .map(|row| CollectArray::collect_array(&mut row.iter())) - ), + .map(|row| row.iter().collect_array()) + .collect_array(), [[&1, &2], [&3, &4]] ); } From 298d13e9d0caacd05d722a902eefa5e495f4db40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 3 Dec 2025 16:22:57 +0100 Subject: [PATCH 265/585] Revert "fixup warnings around the compiler" This reverts commit f20175293aa8372766250e56e2570f3c06640e0b. --- clippy_lints/src/manual_non_exhaustive.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 08e7c7593cb2..0d783fde3313 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -92,8 +92,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { (matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir_attrs(v.hir_id))) .then_some((v.def_id, v.span)) }); - // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 - if let Ok((id, span)) = Itertools::exactly_one(iter) + if let Ok((id, span)) = iter.exactly_one() && !find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(..)) { self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); @@ -105,8 +104,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { .iter() .filter(|field| !cx.effective_visibilities.is_exported(field.def_id)); if fields.len() > 1 - // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 - && let Ok(field) = Itertools::exactly_one(private_fields) + && let Ok(field) = private_fields.exactly_one() && let TyKind::Tup([]) = field.ty.kind { span_lint_and_then( From 1864bf6a510a7e9df23777591f3389b6feb27e90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 18 Oct 2025 11:25:13 +0200 Subject: [PATCH 266/585] ICE when applying test to crate root --- tests/crashes/114920.rs | 2 -- tests/ui/macros/test-on-crate-root.rs | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) delete mode 100644 tests/crashes/114920.rs create mode 100644 tests/ui/macros/test-on-crate-root.rs diff --git a/tests/crashes/114920.rs b/tests/crashes/114920.rs deleted file mode 100644 index 9aa7598e10fc..000000000000 --- a/tests/crashes/114920.rs +++ /dev/null @@ -1,2 +0,0 @@ -//@ known-bug: #114920 -#![core::prelude::v1::test] diff --git a/tests/ui/macros/test-on-crate-root.rs b/tests/ui/macros/test-on-crate-root.rs new file mode 100644 index 000000000000..80635a458902 --- /dev/null +++ b/tests/ui/macros/test-on-crate-root.rs @@ -0,0 +1,8 @@ +// ICE when applying `#![test]` to the crate root, +// though only when specified with a full path. `#![test]` is not enough. +// Fixes #114920 +#![core::prelude::v1::test] + + + +fn main() {} // not important to reproduce the issue From 9dd3caeebefbb36f90ea13e5ec4b37048067ca59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 18 Oct 2025 12:10:21 +0200 Subject: [PATCH 267/585] only discard items with `#[test]` on it when target is valid --- compiler/rustc_builtin_macros/src/test.rs | 20 +- .../ui/feature-gates/gating-of-test-attrs.rs | 48 +++ .../feature-gates/gating-of-test-attrs.stderr | 181 +++++++++++ .../issue-43106-gating-of-builtin-attrs.rs | 32 -- ...issue-43106-gating-of-builtin-attrs.stderr | 304 +++++++++--------- tests/ui/macros/attr-empty-expr.rs | 11 - tests/ui/macros/attr-empty-expr.stderr | 20 -- tests/ui/macros/issue-111749.rs | 4 +- tests/ui/macros/issue-111749.stderr | 16 +- tests/ui/macros/test-on-crate-root.rs | 3 +- tests/ui/macros/test-on-crate-root.stderr | 25 ++ 11 files changed, 431 insertions(+), 233 deletions(-) create mode 100644 tests/ui/feature-gates/gating-of-test-attrs.rs create mode 100644 tests/ui/feature-gates/gating-of-test-attrs.stderr delete mode 100644 tests/ui/macros/attr-empty-expr.rs delete mode 100644 tests/ui/macros/attr-empty-expr.stderr create mode 100644 tests/ui/macros/test-on-crate-root.stderr diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 532539f893ae..8f6244e418fd 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -34,10 +34,6 @@ pub(crate) fn expand_test_case( check_builtin_macro_attribute(ecx, meta_item, sym::test_case); warn_on_duplicate_attribute(ecx, &anno_item, sym::test_case); - if !ecx.ecfg.should_test { - return vec![]; - } - let sp = ecx.with_def_site_ctxt(attr_sp); let (mut item, is_stmt) = match anno_item { Annotatable::Item(item) => (item, false), @@ -54,6 +50,10 @@ pub(crate) fn expand_test_case( } }; + if !ecx.ecfg.should_test { + return vec![]; + } + // `#[test_case]` is valid on functions, consts, and statics. Only modify // the item in those cases. match &mut item.kind { @@ -113,11 +113,6 @@ pub(crate) fn expand_test_or_bench( item: Annotatable, is_bench: bool, ) -> Vec { - // If we're not in test configuration, remove the annotated item - if !cx.ecfg.should_test { - return vec![]; - } - let (item, is_stmt) = match item { Annotatable::Item(i) => (i, false), Annotatable::Stmt(box ast::Stmt { kind: ast::StmtKind::Item(i), .. }) => (i, true), @@ -136,6 +131,11 @@ pub(crate) fn expand_test_or_bench( }; }; + // If we're not in test configuration, remove the annotated item + if !cx.ecfg.should_test { + return vec![]; + } + if let Some(attr) = attr::find_by_name(&item.attrs, sym::naked) { cx.dcx().emit_err(errors::NakedFunctionTestingAttribute { testing_span: attr_sp, @@ -407,7 +407,7 @@ pub(crate) fn expand_test_or_bench( fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) { let dcx = cx.dcx(); - let msg = "the `#[test]` attribute may only be used on a non-associated function"; + let msg = "the `#[test]` attribute may only be used on a free function"; let level = match item.map(|i| &i.kind) { // These were a warning before #92959 and need to continue being that to avoid breaking // stable user code (#94508). diff --git a/tests/ui/feature-gates/gating-of-test-attrs.rs b/tests/ui/feature-gates/gating-of-test-attrs.rs new file mode 100644 index 000000000000..22b0454e1741 --- /dev/null +++ b/tests/ui/feature-gates/gating-of-test-attrs.rs @@ -0,0 +1,48 @@ +#![feature(test)] + +// test is a built-in macro, not a built-in attribute, but it kind of acts like both. +// check its target checking anyway here +#[test] +//~^ ERROR the `#[test]` attribute may only be used on a non-associated function +mod test { + mod inner { #![test] } + //~^ ERROR inner macro attributes are unstable + //~| ERROR the `#[test]` attribute may only be used on a non-associated function + + #[test] + //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + struct S; + + #[test] + //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + type T = S; + + #[test] + //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + impl S { } +} + +// At time of unit test authorship, if compiling without `--test` then +// non-crate-level #[bench] attributes seem to be ignored. + +#[bench] +//~^ ERROR the `#[test]` attribute may only be used on a non-associated function +mod bench { + mod inner { #![bench] } + //~^ ERROR inner macro attributes are unstable + //~| ERROR the `#[test]` attribute may only be used on a non-associated function + + #[bench] + //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + struct S; + + #[bench] + //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + type T = S; + + #[bench] + //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + impl S { } +} + +fn main() {} diff --git a/tests/ui/feature-gates/gating-of-test-attrs.stderr b/tests/ui/feature-gates/gating-of-test-attrs.stderr new file mode 100644 index 000000000000..339a68f5d5e4 --- /dev/null +++ b/tests/ui/feature-gates/gating-of-test-attrs.stderr @@ -0,0 +1,181 @@ +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/gating-of-test-attrs.rs:5:1 + | +LL | #[test] + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions +LL | +LL | / mod test { +LL | | mod inner { #![test] } +... | +LL | | impl S { } +LL | | } + | |_- expected a non-associated function, found a module + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL - #[test] +LL + #[cfg(test)] + | + +error[E0658]: inner macro attributes are unstable + --> $DIR/gating-of-test-attrs.rs:8:20 + | +LL | mod inner { #![test] } + | ^^^^ + | + = note: see issue #54726 for more information + = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/gating-of-test-attrs.rs:8:17 + | +LL | mod inner { #![test] } + | ------------^^^^^^^^-- + | | | + | | the `#[test]` macro causes a function to be run as a test and has no effect on non-functions + | expected a non-associated function, found a module + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL - mod inner { #![test] } +LL + mod inner { #[cfg(test)] } + | + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/gating-of-test-attrs.rs:12:5 + | +LL | #[test] + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions +LL | +LL | struct S; + | --------- expected a non-associated function, found a struct + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL - #[test] +LL + #[cfg(test)] + | + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/gating-of-test-attrs.rs:16:5 + | +LL | #[test] + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions +LL | +LL | type T = S; + | ----------- expected a non-associated function, found a type alias + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL - #[test] +LL + #[cfg(test)] + | + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/gating-of-test-attrs.rs:20:5 + | +LL | #[test] + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions +LL | +LL | impl S { } + | ---------- expected a non-associated function, found an implementation + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL - #[test] +LL + #[cfg(test)] + | + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/gating-of-test-attrs.rs:28:1 + | +LL | #[bench] + | ^^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions +LL | +LL | / mod bench { +LL | | mod inner { #![bench] } +... | +LL | | impl S { } +LL | | } + | |_- expected a non-associated function, found a module + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL - #[bench] +LL + #[cfg(test)] + | + +error[E0658]: inner macro attributes are unstable + --> $DIR/gating-of-test-attrs.rs:31:20 + | +LL | mod inner { #![bench] } + | ^^^^^ + | + = note: see issue #54726 for more information + = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/gating-of-test-attrs.rs:31:17 + | +LL | mod inner { #![bench] } + | ------------^^^^^^^^^-- + | | | + | | the `#[test]` macro causes a function to be run as a test and has no effect on non-functions + | expected a non-associated function, found a module + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL - mod inner { #![bench] } +LL + mod inner { #[cfg(test)] } + | + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/gating-of-test-attrs.rs:35:5 + | +LL | #[bench] + | ^^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions +LL | +LL | struct S; + | --------- expected a non-associated function, found a struct + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL - #[bench] +LL + #[cfg(test)] + | + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/gating-of-test-attrs.rs:39:5 + | +LL | #[bench] + | ^^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions +LL | +LL | type T = S; + | ----------- expected a non-associated function, found a type alias + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL - #[bench] +LL + #[cfg(test)] + | + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/gating-of-test-attrs.rs:43:5 + | +LL | #[bench] + | ^^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions +LL | +LL | impl S { } + | ---------- expected a non-associated function, found an implementation + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL - #[bench] +LL + #[cfg(test)] + | + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index 8d67bf37279d..5b32c5ca0dfa 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -250,38 +250,6 @@ mod inner { #![macro_export] } //~| HELP remove the attribute } -// At time of unit test authorship, if compiling without `--test` then -// non-crate-level #[test] attributes seem to be ignored. - -#[test] -mod test { mod inner { #![test] } - - fn f() { } - - struct S; - - type T = S; - - impl S { } -} - -// At time of unit test authorship, if compiling without `--test` then -// non-crate-level #[bench] attributes seem to be ignored. - -#[bench] -mod bench { - mod inner { #![bench] } - - #[bench] - struct S; - - #[bench] - type T = S; - - #[bench] - impl S { } -} - #[path = "3800"] mod path { mod inner { #![path="3800"] } diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index f7e8d9c7c400..d8b1dc91acc4 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -1,5 +1,5 @@ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:529:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | mod inner { #![macro_escape] } = help: try an outer attribute: `#[macro_use]` warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:526:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:494:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL | #[deny(x5100)] impl S { } | ^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -203,7 +203,7 @@ LL | #![reexport_test_harness_main = "2900"] | + warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:739:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:1 | LL | #[link(name = "x")] | ^^^^^^^^^^^^^^^^^^^ @@ -219,7 +219,7 @@ LL | | } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:865:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:833:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -230,7 +230,7 @@ LL | #![crate_type = "0800"] | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:889:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:857:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL | #![feature(x0600)] | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:914:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:882:1 | LL | #[no_main] | ^^^^^^^^^^ @@ -252,7 +252,7 @@ LL | #![no_main] | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:938:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:906:1 | LL | #[no_builtins] | ^^^^^^^^^^^^^^ @@ -279,13 +279,13 @@ LL | #![feature(rust1)] = note: `#[warn(stable_features)]` on by default warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:473:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:508:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -296,7 +296,7 @@ LL | #![reexport_test_harness_main = "2900"] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:480:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -307,7 +307,7 @@ LL | #![reexport_test_harness_main = "2900"] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:516:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:484:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -318,7 +318,7 @@ LL | #![reexport_test_harness_main = "2900"] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:520:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -329,7 +329,7 @@ LL | #![reexport_test_harness_main = "2900"] impl S { } | + warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:17 | LL | mod inner { #![link(name = "x")] } | ------------^^^^^^^^^^^^^^^^^^^^-- not an `extern` block @@ -337,7 +337,7 @@ LL | mod inner { #![link(name = "x")] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 | LL | #[link(name = "x")] fn f() { } | ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block @@ -345,7 +345,7 @@ LL | #[link(name = "x")] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:723:5 | LL | #[link(name = "x")] struct S; | ^^^^^^^^^^^^^^^^^^^ --------- not an `extern` block @@ -353,7 +353,7 @@ LL | #[link(name = "x")] struct S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 | LL | #[link(name = "x")] type T = S; | ^^^^^^^^^^^^^^^^^^^ ----------- not an `extern` block @@ -361,7 +361,7 @@ LL | #[link(name = "x")] type T = S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 | LL | #[link(name = "x")] impl S { } | ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block @@ -369,7 +369,7 @@ LL | #[link(name = "x")] impl S { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:5 | LL | #[link(name = "x")] extern "Rust" {} | ^^^^^^^^^^^^^^^^^^^ @@ -377,13 +377,13 @@ LL | #[link(name = "x")] extern "Rust" {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:869:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:837:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:872:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:840:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -394,7 +394,7 @@ LL | #![crate_type = "0800"] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:876:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:844:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -405,7 +405,7 @@ LL | #![crate_type = "0800"] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:880:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:848:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -416,7 +416,7 @@ LL | #![crate_type = "0800"] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:884:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:852:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -427,13 +427,13 @@ LL | #![crate_type = "0800"] impl S { } | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:893:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:861:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:896:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:864:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ @@ -444,7 +444,7 @@ LL | #![feature(x0600)] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:900:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:868:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ @@ -455,7 +455,7 @@ LL | #![feature(x0600)] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:904:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:872:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ @@ -466,7 +466,7 @@ LL | #![feature(x0600)] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:908:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:876:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ @@ -477,13 +477,13 @@ LL | #![feature(x0600)] impl S { } | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:918:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:886:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:921:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:889:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ @@ -494,7 +494,7 @@ LL | #![no_main] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:893:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ @@ -505,7 +505,7 @@ LL | #![no_main] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:897:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ @@ -516,7 +516,7 @@ LL | #![no_main] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:901:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ @@ -527,13 +527,13 @@ LL | #![no_main] impl S { } | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:942:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:910:17 | LL | mod inner { #![no_builtins] } | ^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:945:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:913:5 | LL | #[no_builtins] fn f() { } | ^^^^^^^^^^^^^^ @@ -544,7 +544,7 @@ LL | #![no_builtins] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:917:5 | LL | #[no_builtins] struct S; | ^^^^^^^^^^^^^^ @@ -555,7 +555,7 @@ LL | #![no_builtins] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:921:5 | LL | #[no_builtins] type T = S; | ^^^^^^^^^^^^^^ @@ -566,7 +566,7 @@ LL | #![no_builtins] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:5 | LL | #[no_builtins] impl S { } | ^^^^^^^^^^^^^^ @@ -667,7 +667,7 @@ LL | #[macro_export] impl S { } = help: `#[macro_export]` can only be applied to macro defs warning: `#[path]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:289:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:257:5 | LL | #[path = "3800"] fn f() { } | ^^^^^^^^^^^^^^^^ @@ -676,7 +676,7 @@ LL | #[path = "3800"] fn f() { } = help: `#[path]` can only be applied to modules warning: `#[path]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:295:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:263:5 | LL | #[path = "3800"] struct S; | ^^^^^^^^^^^^^^^^ @@ -685,7 +685,7 @@ LL | #[path = "3800"] struct S; = help: `#[path]` can only be applied to modules warning: `#[path]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:301:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:5 | LL | #[path = "3800"] type T = S; | ^^^^^^^^^^^^^^^^ @@ -694,7 +694,7 @@ LL | #[path = "3800"] type T = S; = help: `#[path]` can only be applied to modules warning: `#[path]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:307:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:5 | LL | #[path = "3800"] impl S { } | ^^^^^^^^^^^^^^^^ @@ -703,7 +703,7 @@ LL | #[path = "3800"] impl S { } = help: `#[path]` can only be applied to modules warning: `#[automatically_derived]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:314:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:282:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -712,7 +712,7 @@ LL | #[automatically_derived] = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[automatically_derived]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:320:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:288:17 | LL | mod inner { #![automatically_derived] } | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -721,7 +721,7 @@ LL | mod inner { #![automatically_derived] } = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[automatically_derived]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:326:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:294:5 | LL | #[automatically_derived] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -730,7 +730,7 @@ LL | #[automatically_derived] fn f() { } = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[automatically_derived]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:300:5 | LL | #[automatically_derived] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -739,7 +739,7 @@ LL | #[automatically_derived] struct S; = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[automatically_derived]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:306:5 | LL | #[automatically_derived] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -748,7 +748,7 @@ LL | #[automatically_derived] type T = S; = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[automatically_derived]` attribute cannot be used on traits - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:312:5 | LL | #[automatically_derived] trait W { } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -757,7 +757,7 @@ LL | #[automatically_derived] trait W { } = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[automatically_derived]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:318:5 | LL | #[automatically_derived] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -766,7 +766,7 @@ LL | #[automatically_derived] impl S { } = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[no_mangle]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:359:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:327:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ @@ -775,7 +775,7 @@ LL | #[no_mangle] = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:365:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:333:17 | LL | mod inner { #![no_mangle] } | ^^^^^^^^^^^^^ @@ -784,7 +784,7 @@ LL | mod inner { #![no_mangle] } = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:5 | LL | #[no_mangle] struct S; | ^^^^^^^^^^^^ @@ -793,7 +793,7 @@ LL | #[no_mangle] struct S; = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5 | LL | #[no_mangle] type T = S; | ^^^^^^^^^^^^ @@ -802,7 +802,7 @@ LL | #[no_mangle] type T = S; = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:385:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:353:5 | LL | #[no_mangle] impl S { } | ^^^^^^^^^^^^ @@ -811,7 +811,7 @@ LL | #[no_mangle] impl S { } = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on required trait methods - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:360:9 | LL | #[no_mangle] fn foo(); | ^^^^^^^^^^^^ @@ -820,7 +820,7 @@ LL | #[no_mangle] fn foo(); = help: `#[no_mangle]` can be applied to functions, inherent methods, statics, and trait methods in impl blocks warning: `#[no_mangle]` attribute cannot be used on provided trait methods - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:366:9 | LL | #[no_mangle] fn bar() {} | ^^^^^^^^^^^^ @@ -829,7 +829,7 @@ LL | #[no_mangle] fn bar() {} = help: `#[no_mangle]` can be applied to functions, inherent methods, statics, and trait methods in impl blocks warning: `#[should_panic]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:406:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ @@ -838,7 +838,7 @@ LL | #[should_panic] = help: `#[should_panic]` can only be applied to functions warning: `#[should_panic]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:412:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:17 | LL | mod inner { #![should_panic] } | ^^^^^^^^^^^^^^^^ @@ -847,7 +847,7 @@ LL | mod inner { #![should_panic] } = help: `#[should_panic]` can only be applied to functions warning: `#[should_panic]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:388:5 | LL | #[should_panic] struct S; | ^^^^^^^^^^^^^^^ @@ -856,7 +856,7 @@ LL | #[should_panic] struct S; = help: `#[should_panic]` can only be applied to functions warning: `#[should_panic]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:394:5 | LL | #[should_panic] type T = S; | ^^^^^^^^^^^^^^^ @@ -865,7 +865,7 @@ LL | #[should_panic] type T = S; = help: `#[should_panic]` can only be applied to functions warning: `#[should_panic]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:432:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:400:5 | LL | #[should_panic] impl S { } | ^^^^^^^^^^^^^^^ @@ -874,7 +874,7 @@ LL | #[should_panic] impl S { } = help: `#[should_panic]` can only be applied to functions warning: `#[ignore]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:407:1 | LL | #[ignore] | ^^^^^^^^^ @@ -883,7 +883,7 @@ LL | #[ignore] = help: `#[ignore]` can only be applied to functions warning: `#[ignore]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:445:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:413:17 | LL | mod inner { #![ignore] } | ^^^^^^^^^^ @@ -892,7 +892,7 @@ LL | mod inner { #![ignore] } = help: `#[ignore]` can only be applied to functions warning: `#[ignore]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:453:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:5 | LL | #[ignore] struct S; | ^^^^^^^^^ @@ -901,7 +901,7 @@ LL | #[ignore] struct S; = help: `#[ignore]` can only be applied to functions warning: `#[ignore]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5 | LL | #[ignore] type T = S; | ^^^^^^^^^ @@ -910,7 +910,7 @@ LL | #[ignore] type T = S; = help: `#[ignore]` can only be applied to functions warning: `#[ignore]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:465:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 | LL | #[ignore] impl S { } | ^^^^^^^^^ @@ -919,7 +919,7 @@ LL | #[ignore] impl S { } = help: `#[ignore]` can only be applied to functions warning: `#[no_implicit_prelude]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:444:5 | LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -928,7 +928,7 @@ LL | #[no_implicit_prelude] fn f() { } = help: `#[no_implicit_prelude]` can be applied to crates and modules warning: `#[no_implicit_prelude]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:5 | LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -937,7 +937,7 @@ LL | #[no_implicit_prelude] struct S; = help: `#[no_implicit_prelude]` can be applied to crates and modules warning: `#[no_implicit_prelude]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:456:5 | LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -946,7 +946,7 @@ LL | #[no_implicit_prelude] type T = S; = help: `#[no_implicit_prelude]` can be applied to crates and modules warning: `#[no_implicit_prelude]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:494:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:5 | LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -955,7 +955,7 @@ LL | #[no_implicit_prelude] impl S { } = help: `#[no_implicit_prelude]` can be applied to crates and modules warning: `#[macro_escape]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:533:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ @@ -964,7 +964,7 @@ LL | #[macro_escape] fn f() { } = help: `#[macro_escape]` can be applied to crates, extern crates, and modules warning: `#[macro_escape]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:539:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ @@ -973,7 +973,7 @@ LL | #[macro_escape] struct S; = help: `#[macro_escape]` can be applied to crates, extern crates, and modules warning: `#[macro_escape]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:545:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:513:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ @@ -982,7 +982,7 @@ LL | #[macro_escape] type T = S; = help: `#[macro_escape]` can be applied to crates, extern crates, and modules warning: `#[macro_escape]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:551:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ @@ -991,13 +991,13 @@ LL | #[macro_escape] impl S { } = help: `#[macro_escape]` can be applied to crates, extern crates, and modules warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:558:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:526:1 | LL | #[no_std] | ^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:560:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:528:1 | LL | / mod no_std { LL | | @@ -1007,61 +1007,61 @@ LL | | } | |_^ warning: the `#![no_std]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:562:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:530:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:565:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:533:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:565:15 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:533:15 | LL | #[no_std] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:569:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:537:5 | LL | #[no_std] struct S; | ^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:569:15 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:537:15 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:573:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:573:15 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:15 | LL | #[no_std] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:577:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:545:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:577:15 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:545:15 | LL | #[no_std] impl S { } | ^^^^^^^^^^ warning: `#[cold]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:599:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:567:1 | LL | #[cold] | ^^^^^^^ @@ -1070,7 +1070,7 @@ LL | #[cold] = help: `#[cold]` can only be applied to functions warning: `#[cold]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:606:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:574:17 | LL | mod inner { #![cold] } | ^^^^^^^^ @@ -1079,7 +1079,7 @@ LL | mod inner { #![cold] } = help: `#[cold]` can only be applied to functions warning: `#[cold]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:582:5 | LL | #[cold] struct S; | ^^^^^^^ @@ -1088,7 +1088,7 @@ LL | #[cold] struct S; = help: `#[cold]` can only be applied to functions warning: `#[cold]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:588:5 | LL | #[cold] type T = S; | ^^^^^^^ @@ -1097,7 +1097,7 @@ LL | #[cold] type T = S; = help: `#[cold]` can only be applied to functions warning: `#[cold]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:594:5 | LL | #[cold] impl S { } | ^^^^^^^ @@ -1106,7 +1106,7 @@ LL | #[cold] impl S { } = help: `#[cold]` can only be applied to functions warning: `#[link_name]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:633:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:601:1 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -1115,7 +1115,7 @@ LL | #[link_name = "1900"] = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on foreign modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:607:5 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -1124,7 +1124,7 @@ LL | #[link_name = "1900"] = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:17 | LL | mod inner { #![link_name="1900"] } | ^^^^^^^^^^^^^^^^^^^^ @@ -1133,7 +1133,7 @@ LL | mod inner { #![link_name="1900"] } = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5 | LL | #[link_name = "1900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^ @@ -1142,7 +1142,7 @@ LL | #[link_name = "1900"] fn f() { } = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:658:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:5 | LL | #[link_name = "1900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^ @@ -1151,7 +1151,7 @@ LL | #[link_name = "1900"] struct S; = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:664:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:632:5 | LL | #[link_name = "1900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^ @@ -1160,7 +1160,7 @@ LL | #[link_name = "1900"] type T = S; = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:670:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:5 | LL | #[link_name = "1900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^ @@ -1169,7 +1169,7 @@ LL | #[link_name = "1900"] impl S { } = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_section]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:1 | LL | #[link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1178,7 +1178,7 @@ LL | #[link_section = "1800"] = help: `#[link_section]` can be applied to functions and statics warning: `#[link_section]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:17 | LL | mod inner { #![link_section="1800"] } | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -1187,7 +1187,7 @@ LL | mod inner { #![link_section="1800"] } = help: `#[link_section]` can be applied to functions and statics warning: `#[link_section]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:5 | LL | #[link_section = "1800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1196,7 +1196,7 @@ LL | #[link_section = "1800"] struct S; = help: `#[link_section]` can be applied to functions and statics warning: `#[link_section]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:5 | LL | #[link_section = "1800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1205,7 +1205,7 @@ LL | #[link_section = "1800"] type T = S; = help: `#[link_section]` can be applied to functions and statics warning: `#[link_section]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5 | LL | #[link_section = "1800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1214,7 +1214,7 @@ LL | #[link_section = "1800"] impl S { } = help: `#[link_section]` can be applied to functions and statics warning: `#[link_section]` attribute cannot be used on traits - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:5 | LL | #[link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1223,7 +1223,7 @@ LL | #[link_section = "1800"] = help: `#[link_section]` can be applied to functions and statics warning: `#[must_use]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:1 | LL | #[must_use] | ^^^^^^^^^^^ @@ -1232,7 +1232,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to data types, functions, traits, and unions warning: `#[must_use]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:795:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:17 | LL | mod inner { #![must_use] } | ^^^^^^^^^^^^ @@ -1241,7 +1241,7 @@ LL | mod inner { #![must_use] } = help: `#[must_use]` can be applied to data types, functions, traits, and unions warning: `#[must_use]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:804:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:772:5 | LL | #[must_use] type T = S; | ^^^^^^^^^^^ @@ -1250,7 +1250,7 @@ LL | #[must_use] type T = S; = help: `#[must_use]` can be applied to data types, functions, traits, and unions warning: `#[must_use]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:809:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:5 | LL | #[must_use] impl S { } | ^^^^^^^^^^^ @@ -1259,13 +1259,13 @@ LL | #[must_use] impl S { } = help: `#[must_use]` can be applied to data types, functions, traits, and unions warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:1 | LL | #[windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:817:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:1 | LL | / mod windows_subsystem { LL | | @@ -1275,67 +1275,67 @@ LL | | } | |_^ warning: the `#![windows_subsystem]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:787:17 | LL | mod inner { #![windows_subsystem="windows"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:5 | LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:38 | LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:794:5 | LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:794:38 | LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:5 | LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:38 | LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:5 | LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:38 | LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:841:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:809:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:811:1 | LL | / mod crate_name { LL | | @@ -1345,67 +1345,67 @@ LL | | } | |_^ warning: the `#![crate_name]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:845:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:813:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:848:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:816:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:848:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:816:28 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:852:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:820:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:852:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:820:28 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:856:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:824:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:856:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:824:28 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:828:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:828:28 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:962:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:930:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:932:1 | LL | / mod recursion_limit { LL | | @@ -1415,67 +1415,67 @@ LL | | } | |_^ warning: the `#![recursion_limit]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:966:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:934:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:969:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:969:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:31 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:973:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:941:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:973:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:941:31 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:977:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:945:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:977:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:945:31 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:981:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:981:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:31 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:986:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:954:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:988:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:956:1 | LL | / mod type_length_limit { LL | | @@ -1485,55 +1485,55 @@ LL | | } | |_^ warning: the `#![type_length_limit]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:990:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:958:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:993:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:993:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:33 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:997:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:965:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:997:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:965:33 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:1001:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:969:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:1001:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:969:33 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:1005:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:973:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:1005:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:973:33 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^ diff --git a/tests/ui/macros/attr-empty-expr.rs b/tests/ui/macros/attr-empty-expr.rs deleted file mode 100644 index d4d1a3ee71e6..000000000000 --- a/tests/ui/macros/attr-empty-expr.rs +++ /dev/null @@ -1,11 +0,0 @@ -// AST-based macro attributes expanding to an empty expression produce an error and not ICE. - -#![feature(custom_test_frameworks)] -#![feature(stmt_expr_attributes)] -#![feature(test)] - -fn main() { - let _ = #[test] 0; //~ ERROR removing an expression is not supported in this position - let _ = #[bench] 1; //~ ERROR removing an expression is not supported in this position - let _ = #[test_case] 2; //~ ERROR removing an expression is not supported in this position -} diff --git a/tests/ui/macros/attr-empty-expr.stderr b/tests/ui/macros/attr-empty-expr.stderr deleted file mode 100644 index 53721053bcc0..000000000000 --- a/tests/ui/macros/attr-empty-expr.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: removing an expression is not supported in this position - --> $DIR/attr-empty-expr.rs:8:13 - | -LL | let _ = #[test] 0; - | ^^^^^^^ - -error: removing an expression is not supported in this position - --> $DIR/attr-empty-expr.rs:9:13 - | -LL | let _ = #[bench] 1; - | ^^^^^^^^ - -error: removing an expression is not supported in this position - --> $DIR/attr-empty-expr.rs:10:13 - | -LL | let _ = #[test_case] 2; - | ^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/tests/ui/macros/issue-111749.rs b/tests/ui/macros/issue-111749.rs index 6c45e4e8cd71..779a854ea582 100644 --- a/tests/ui/macros/issue-111749.rs +++ b/tests/ui/macros/issue-111749.rs @@ -5,8 +5,8 @@ macro_rules! cbor_map { } fn main() { - cbor_map! { #[test(test)] 4}; - //~^ ERROR removing an expression is not supported in this position + cbor_map! { #[test(test)] 4i32}; + //~^ ERROR the `#[test]` attribute may only be used on a non-associated function //~| ERROR attribute must be of the form `#[test]` //~| WARNING this was previously accepted by the compiler but is being phased out } diff --git a/tests/ui/macros/issue-111749.stderr b/tests/ui/macros/issue-111749.stderr index ae953e042e09..3afdd0ad4baf 100644 --- a/tests/ui/macros/issue-111749.stderr +++ b/tests/ui/macros/issue-111749.stderr @@ -1,13 +1,19 @@ -error: removing an expression is not supported in this position +error: the `#[test]` attribute may only be used on a non-associated function --> $DIR/issue-111749.rs:8:17 | -LL | cbor_map! { #[test(test)] 4}; - | ^^^^^^^^^^^^^ +LL | cbor_map! { #[test(test)] 4i32}; + | ^^^^^^^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL - cbor_map! { #[test(test)] 4i32}; +LL + cbor_map! { #[cfg(test)] 4i32}; + | error: attribute must be of the form `#[test]` --> $DIR/issue-111749.rs:8:17 | -LL | cbor_map! { #[test(test)] 4}; +LL | cbor_map! { #[test(test)] 4i32}; | ^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -20,7 +26,7 @@ Future incompatibility report: Future breakage diagnostic: error: attribute must be of the form `#[test]` --> $DIR/issue-111749.rs:8:17 | -LL | cbor_map! { #[test(test)] 4}; +LL | cbor_map! { #[test(test)] 4i32}; | ^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/tests/ui/macros/test-on-crate-root.rs b/tests/ui/macros/test-on-crate-root.rs index 80635a458902..abe08536b1d6 100644 --- a/tests/ui/macros/test-on-crate-root.rs +++ b/tests/ui/macros/test-on-crate-root.rs @@ -2,7 +2,8 @@ // though only when specified with a full path. `#![test]` is not enough. // Fixes #114920 #![core::prelude::v1::test] - +//~^ ERROR inner macro attributes are unstable +//~| ERROR the `#[test]` attribute may only be used on a non-associated function fn main() {} // not important to reproduce the issue diff --git a/tests/ui/macros/test-on-crate-root.stderr b/tests/ui/macros/test-on-crate-root.stderr new file mode 100644 index 000000000000..5a5e0597284d --- /dev/null +++ b/tests/ui/macros/test-on-crate-root.stderr @@ -0,0 +1,25 @@ +error[E0658]: inner macro attributes are unstable + --> $DIR/test-on-crate-root.rs:3:4 + | +LL | #![core::prelude::v1::test] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #54726 for more information + = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-on-crate-root.rs:3:1 + | +LL | #![core::prelude::v1::test] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL - #![core::prelude::v1::test] +LL + #[cfg(test)] + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. From 97d4d2154f4764a62710f2e2a0f3cd90b55adeaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 18 Oct 2025 12:13:39 +0200 Subject: [PATCH 268/585] fixup name in diagnostics --- compiler/rustc_builtin_macros/src/test.rs | 21 ++++--- .../ui/feature-gates/gating-of-test-attrs.rs | 20 +++---- .../feature-gates/gating-of-test-attrs.stderr | 60 +++++-------------- tests/ui/macros/issue-111749.rs | 2 +- tests/ui/macros/issue-111749.stderr | 2 +- tests/ui/macros/test-on-crate-root.rs | 2 +- tests/ui/macros/test-on-crate-root.stderr | 6 +- tests/ui/test-attrs/issue-109816.rs | 2 +- tests/ui/test-attrs/issue-109816.stderr | 2 +- .../test-attr-non-associated-functions.rs | 4 +- .../test-attr-non-associated-functions.stderr | 4 +- tests/ui/test-attrs/test-on-not-fn.rs | 24 ++++---- tests/ui/test-attrs/test-on-not-fn.stderr | 24 ++++---- 13 files changed, 74 insertions(+), 99 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 8f6244e418fd..f31ad4f591b1 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -117,13 +117,13 @@ pub(crate) fn expand_test_or_bench( Annotatable::Item(i) => (i, false), Annotatable::Stmt(box ast::Stmt { kind: ast::StmtKind::Item(i), .. }) => (i, true), other => { - not_testable_error(cx, attr_sp, None); + not_testable_error(cx, is_bench, attr_sp, None); return vec![other]; } }; let ast::ItemKind::Fn(fn_) = &item.kind else { - not_testable_error(cx, attr_sp, Some(&item)); + not_testable_error(cx, is_bench, attr_sp, Some(&item)); return if is_stmt { vec![Annotatable::Stmt(Box::new(cx.stmt_item(item.span, item)))] } else { @@ -405,9 +405,10 @@ pub(crate) fn expand_test_or_bench( } } -fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) { +fn not_testable_error(cx: &ExtCtxt<'_>, is_bench: bool, attr_sp: Span, item: Option<&ast::Item>) { let dcx = cx.dcx(); - let msg = "the `#[test]` attribute may only be used on a free function"; + let name = if is_bench { "bench" } else { "test" }; + let msg = format!("the `#[{name}]` attribute may only be used on a free function"); let level = match item.map(|i| &i.kind) { // These were a warning before #92959 and need to continue being that to avoid breaking // stable user code (#94508). @@ -426,12 +427,16 @@ fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) ), ); } - err.with_span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions") - .with_span_suggestion(attr_sp, + err.span_label(attr_sp, format!("the `#[{name}]` macro causes a function to be run as a test and has no effect on non-functions")); + + if !is_bench { + err.with_span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", "#[cfg(test)]", - Applicability::MaybeIncorrect) - .emit(); + Applicability::MaybeIncorrect).emit(); + } else { + err.emit(); + } } fn get_location_info(cx: &ExtCtxt<'_>, fn_: &ast::Fn) -> (Symbol, usize, usize, usize, usize) { diff --git a/tests/ui/feature-gates/gating-of-test-attrs.rs b/tests/ui/feature-gates/gating-of-test-attrs.rs index 22b0454e1741..3b07e2ad03c9 100644 --- a/tests/ui/feature-gates/gating-of-test-attrs.rs +++ b/tests/ui/feature-gates/gating-of-test-attrs.rs @@ -3,22 +3,22 @@ // test is a built-in macro, not a built-in attribute, but it kind of acts like both. // check its target checking anyway here #[test] -//~^ ERROR the `#[test]` attribute may only be used on a non-associated function +//~^ ERROR the `#[test]` attribute may only be used on a free function mod test { mod inner { #![test] } //~^ ERROR inner macro attributes are unstable - //~| ERROR the `#[test]` attribute may only be used on a non-associated function + //~| ERROR the `#[test]` attribute may only be used on a free function #[test] - //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + //~^ ERROR the `#[test]` attribute may only be used on a free function struct S; #[test] - //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + //~^ ERROR the `#[test]` attribute may only be used on a free function type T = S; #[test] - //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + //~^ ERROR the `#[test]` attribute may only be used on a free function impl S { } } @@ -26,22 +26,22 @@ impl S { } // non-crate-level #[bench] attributes seem to be ignored. #[bench] -//~^ ERROR the `#[test]` attribute may only be used on a non-associated function +//~^ ERROR the `#[bench]` attribute may only be used on a free function mod bench { mod inner { #![bench] } //~^ ERROR inner macro attributes are unstable - //~| ERROR the `#[test]` attribute may only be used on a non-associated function + //~| ERROR the `#[bench]` attribute may only be used on a free function #[bench] - //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + //~^ ERROR the `#[bench]` attribute may only be used on a free function struct S; #[bench] - //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + //~^ ERROR the `#[bench]` attribute may only be used on a free function type T = S; #[bench] - //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + //~^ ERROR the `#[bench]` attribute may only be used on a free function impl S { } } diff --git a/tests/ui/feature-gates/gating-of-test-attrs.stderr b/tests/ui/feature-gates/gating-of-test-attrs.stderr index 339a68f5d5e4..0f47ab85dc18 100644 --- a/tests/ui/feature-gates/gating-of-test-attrs.stderr +++ b/tests/ui/feature-gates/gating-of-test-attrs.stderr @@ -1,4 +1,4 @@ -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/gating-of-test-attrs.rs:5:1 | LL | #[test] @@ -27,7 +27,7 @@ LL | mod inner { #![test] } = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/gating-of-test-attrs.rs:8:17 | LL | mod inner { #![test] } @@ -42,7 +42,7 @@ LL - mod inner { #![test] } LL + mod inner { #[cfg(test)] } | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/gating-of-test-attrs.rs:12:5 | LL | #[test] @@ -57,7 +57,7 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/gating-of-test-attrs.rs:16:5 | LL | #[test] @@ -72,7 +72,7 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/gating-of-test-attrs.rs:20:5 | LL | #[test] @@ -87,11 +87,11 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[bench]` attribute may only be used on a free function --> $DIR/gating-of-test-attrs.rs:28:1 | LL | #[bench] - | ^^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions + | ^^^^^^^^ the `#[bench]` macro causes a function to be run as a test and has no effect on non-functions LL | LL | / mod bench { LL | | mod inner { #![bench] } @@ -99,12 +99,6 @@ LL | | mod inner { #![bench] } LL | | impl S { } LL | | } | |_- expected a non-associated function, found a module - | -help: replace with conditional compilation to make the item only exist when tests are being run - | -LL - #[bench] -LL + #[cfg(test)] - | error[E0658]: inner macro attributes are unstable --> $DIR/gating-of-test-attrs.rs:31:20 @@ -116,65 +110,41 @@ LL | mod inner { #![bench] } = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[bench]` attribute may only be used on a free function --> $DIR/gating-of-test-attrs.rs:31:17 | LL | mod inner { #![bench] } | ------------^^^^^^^^^-- | | | - | | the `#[test]` macro causes a function to be run as a test and has no effect on non-functions + | | the `#[bench]` macro causes a function to be run as a test and has no effect on non-functions | expected a non-associated function, found a module - | -help: replace with conditional compilation to make the item only exist when tests are being run - | -LL - mod inner { #![bench] } -LL + mod inner { #[cfg(test)] } - | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[bench]` attribute may only be used on a free function --> $DIR/gating-of-test-attrs.rs:35:5 | LL | #[bench] - | ^^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions + | ^^^^^^^^ the `#[bench]` macro causes a function to be run as a test and has no effect on non-functions LL | LL | struct S; | --------- expected a non-associated function, found a struct - | -help: replace with conditional compilation to make the item only exist when tests are being run - | -LL - #[bench] -LL + #[cfg(test)] - | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[bench]` attribute may only be used on a free function --> $DIR/gating-of-test-attrs.rs:39:5 | LL | #[bench] - | ^^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions + | ^^^^^^^^ the `#[bench]` macro causes a function to be run as a test and has no effect on non-functions LL | LL | type T = S; | ----------- expected a non-associated function, found a type alias - | -help: replace with conditional compilation to make the item only exist when tests are being run - | -LL - #[bench] -LL + #[cfg(test)] - | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[bench]` attribute may only be used on a free function --> $DIR/gating-of-test-attrs.rs:43:5 | LL | #[bench] - | ^^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions + | ^^^^^^^^ the `#[bench]` macro causes a function to be run as a test and has no effect on non-functions LL | LL | impl S { } | ---------- expected a non-associated function, found an implementation - | -help: replace with conditional compilation to make the item only exist when tests are being run - | -LL - #[bench] -LL + #[cfg(test)] - | error: aborting due to 12 previous errors diff --git a/tests/ui/macros/issue-111749.rs b/tests/ui/macros/issue-111749.rs index 779a854ea582..e92b9e4ccff8 100644 --- a/tests/ui/macros/issue-111749.rs +++ b/tests/ui/macros/issue-111749.rs @@ -6,7 +6,7 @@ macro_rules! cbor_map { fn main() { cbor_map! { #[test(test)] 4i32}; - //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + //~^ ERROR the `#[test]` attribute may only be used on a free function //~| ERROR attribute must be of the form `#[test]` //~| WARNING this was previously accepted by the compiler but is being phased out } diff --git a/tests/ui/macros/issue-111749.stderr b/tests/ui/macros/issue-111749.stderr index 3afdd0ad4baf..ead01f87eaec 100644 --- a/tests/ui/macros/issue-111749.stderr +++ b/tests/ui/macros/issue-111749.stderr @@ -1,4 +1,4 @@ -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/issue-111749.rs:8:17 | LL | cbor_map! { #[test(test)] 4i32}; diff --git a/tests/ui/macros/test-on-crate-root.rs b/tests/ui/macros/test-on-crate-root.rs index abe08536b1d6..0e0f3ec40976 100644 --- a/tests/ui/macros/test-on-crate-root.rs +++ b/tests/ui/macros/test-on-crate-root.rs @@ -3,7 +3,7 @@ // Fixes #114920 #![core::prelude::v1::test] //~^ ERROR inner macro attributes are unstable -//~| ERROR the `#[test]` attribute may only be used on a non-associated function +//~| ERROR the `#[test]` attribute may only be used on a free function fn main() {} // not important to reproduce the issue diff --git a/tests/ui/macros/test-on-crate-root.stderr b/tests/ui/macros/test-on-crate-root.stderr index 5a5e0597284d..d706d6ae6c5f 100644 --- a/tests/ui/macros/test-on-crate-root.stderr +++ b/tests/ui/macros/test-on-crate-root.stderr @@ -1,5 +1,5 @@ error[E0658]: inner macro attributes are unstable - --> $DIR/test-on-crate-root.rs:3:4 + --> $DIR/test-on-crate-root.rs:4:4 | LL | #![core::prelude::v1::test] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,8 +8,8 @@ LL | #![core::prelude::v1::test] = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: the `#[test]` attribute may only be used on a non-associated function - --> $DIR/test-on-crate-root.rs:3:1 +error: the `#[test]` attribute may only be used on a free function + --> $DIR/test-on-crate-root.rs:4:1 | LL | #![core::prelude::v1::test] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions diff --git a/tests/ui/test-attrs/issue-109816.rs b/tests/ui/test-attrs/issue-109816.rs index 3cabf451c663..c7caae67fefa 100644 --- a/tests/ui/test-attrs/issue-109816.rs +++ b/tests/ui/test-attrs/issue-109816.rs @@ -2,6 +2,6 @@ fn align_offset_weird_strides() { #[test] - //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + //~^ ERROR the `#[test]` attribute may only be used on a free function struct A5(u32, u8); } diff --git a/tests/ui/test-attrs/issue-109816.stderr b/tests/ui/test-attrs/issue-109816.stderr index 433421fff1b5..270f4e0a6668 100644 --- a/tests/ui/test-attrs/issue-109816.stderr +++ b/tests/ui/test-attrs/issue-109816.stderr @@ -1,4 +1,4 @@ -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/issue-109816.rs:4:5 | LL | #[test] diff --git a/tests/ui/test-attrs/test-attr-non-associated-functions.rs b/tests/ui/test-attrs/test-attr-non-associated-functions.rs index 1a4dfda09097..4bf337d0f1b3 100644 --- a/tests/ui/test-attrs/test-attr-non-associated-functions.rs +++ b/tests/ui/test-attrs/test-attr-non-associated-functions.rs @@ -4,12 +4,12 @@ struct A {} impl A { #[test] - //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + //~^ ERROR the `#[test]` attribute may only be used on a free function fn new() -> A { A {} } #[test] - //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + //~^ ERROR the `#[test]` attribute may only be used on a free function fn recovery_witness() -> A { A {} } diff --git a/tests/ui/test-attrs/test-attr-non-associated-functions.stderr b/tests/ui/test-attrs/test-attr-non-associated-functions.stderr index 0ede0cbb97f3..13914971b558 100644 --- a/tests/ui/test-attrs/test-attr-non-associated-functions.stderr +++ b/tests/ui/test-attrs/test-attr-non-associated-functions.stderr @@ -1,4 +1,4 @@ -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/test-attr-non-associated-functions.rs:6:5 | LL | #[test] @@ -10,7 +10,7 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/test-attr-non-associated-functions.rs:11:5 | LL | #[test] diff --git a/tests/ui/test-attrs/test-on-not-fn.rs b/tests/ui/test-attrs/test-on-not-fn.rs index deba26f24ca7..16e9cd8d5b8d 100644 --- a/tests/ui/test-attrs/test-on-not-fn.rs +++ b/tests/ui/test-attrs/test-on-not-fn.rs @@ -1,9 +1,9 @@ //@ compile-flags: --test -#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +#[test] //~ ERROR: the `#[test]` attribute may only be used on a free function mod test {} -#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +#[test] //~ ERROR: the `#[test]` attribute may only be used on a free function mod loooooooooooooong_teeeeeeeeeest { /* this is a comment @@ -17,37 +17,37 @@ mod loooooooooooooong_teeeeeeeeeest { */ } -#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +#[test] //~ ERROR: the `#[test]` attribute may only be used on a free function extern "C" {} -#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +#[test] //~ ERROR: the `#[test]` attribute may only be used on a free function trait Foo {} -#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +#[test] //~ ERROR: the `#[test]` attribute may only be used on a free function impl Foo for i32 {} -#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +#[test] //~ ERROR: the `#[test]` attribute may only be used on a free function const FOO: i32 = -1_i32; -#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +#[test] //~ ERROR: the `#[test]` attribute may only be used on a free function static BAR: u64 = 10_000_u64; -#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +#[test] //~ ERROR: the `#[test]` attribute may only be used on a free function enum MyUnit { Unit, } -#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +#[test] //~ ERROR: the `#[test]` attribute may only be used on a free function struct NewI32(i32); -#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +#[test] //~ ERROR: the `#[test]` attribute may only be used on a free function union Spooky { x: i32, y: u32, } #[repr(C, align(64))] -#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +#[test] //~ ERROR: the `#[test]` attribute may only be used on a free function #[derive(Copy, Clone, Debug)] struct MoreAttrs { a: i32, @@ -58,7 +58,7 @@ macro_rules! foo { () => {}; } -#[test] //~ WARN: the `#[test]` attribute may only be used on a non-associated function +#[test] //~ WARN: the `#[test]` attribute may only be used on a free function foo!(); // make sure it doesn't erroneously trigger on a real test diff --git a/tests/ui/test-attrs/test-on-not-fn.stderr b/tests/ui/test-attrs/test-on-not-fn.stderr index a282db012540..db8bed100a63 100644 --- a/tests/ui/test-attrs/test-on-not-fn.stderr +++ b/tests/ui/test-attrs/test-on-not-fn.stderr @@ -1,4 +1,4 @@ -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/test-on-not-fn.rs:3:1 | LL | #[test] @@ -12,7 +12,7 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/test-on-not-fn.rs:6:1 | LL | #[test] @@ -32,7 +32,7 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/test-on-not-fn.rs:20:1 | LL | #[test] @@ -46,7 +46,7 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/test-on-not-fn.rs:23:1 | LL | #[test] @@ -60,7 +60,7 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/test-on-not-fn.rs:26:1 | LL | #[test] @@ -74,7 +74,7 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/test-on-not-fn.rs:29:1 | LL | #[test] @@ -88,7 +88,7 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/test-on-not-fn.rs:32:1 | LL | #[test] @@ -102,7 +102,7 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/test-on-not-fn.rs:35:1 | LL | #[test] @@ -118,7 +118,7 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/test-on-not-fn.rs:40:1 | LL | #[test] @@ -132,7 +132,7 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/test-on-not-fn.rs:43:1 | LL | #[test] @@ -149,7 +149,7 @@ LL - #[test] LL + #[cfg(test)] | -error: the `#[test]` attribute may only be used on a non-associated function +error: the `#[test]` attribute may only be used on a free function --> $DIR/test-on-not-fn.rs:50:1 | LL | #[test] @@ -167,7 +167,7 @@ LL - #[test] LL + #[cfg(test)] | -warning: the `#[test]` attribute may only be used on a non-associated function +warning: the `#[test]` attribute may only be used on a free function --> $DIR/test-on-not-fn.rs:61:1 | LL | #[test] From 884fb5aef235c5e5b2b817f59aa941d01d849a65 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 1 Dec 2025 20:44:18 +0100 Subject: [PATCH 269/585] Move attribute safety checking to `rustc_attr_parsing` --- .../rustc_ast_passes/src/ast_validation.rs | 2 +- .../rustc_attr_parsing/src/attributes/cfg.rs | 1 + .../src/attributes/cfg_select.rs | 1 + compiler/rustc_attr_parsing/src/interface.rs | 30 ++++- compiler/rustc_attr_parsing/src/lib.rs | 1 + compiler/rustc_attr_parsing/src/lints.rs | 12 ++ compiler/rustc_attr_parsing/src/safety.rs | 116 +++++++++++++++++ .../src/session_diagnostics.rs | 13 +- .../rustc_attr_parsing/src/validate_attr.rs | 117 ++---------------- compiler/rustc_builtin_macros/src/cfg.rs | 1 + compiler/rustc_expand/src/config.rs | 20 +-- compiler/rustc_expand/src/expand.rs | 6 +- compiler/rustc_hir/src/lints.rs | 4 + compiler/rustc_lint/messages.ftl | 4 - compiler/rustc_lint/src/early/diagnostics.rs | 10 -- compiler/rustc_lint/src/lints.rs | 21 ---- compiler/rustc_lint_defs/src/lib.rs | 4 - 17 files changed, 187 insertions(+), 176 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/safety.rs diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index e57f8da26769..94000454caaa 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1067,7 +1067,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_attribute(&mut self, attr: &Attribute) { - validate_attr::check_attr(&self.sess.psess, attr, self.lint_node_id); + validate_attr::check_attr(&self.sess.psess, attr); } fn visit_ty(&mut self, ty: &'a Ty) { diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index a8aa63bd05ee..e47fa075fbf7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -398,6 +398,7 @@ fn parse_cfg_attr_internal<'a>( .into_boxed_slice(), span: attribute.span, }, + Some(attribute.get_normal_item().unsafety), ParsedDescription::Attribute, pred_span, CRATE_NODE_ID, diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs index 8006fb963b19..0c0915558089 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs @@ -63,6 +63,7 @@ pub fn parse_cfg_select( segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(), span: cfg_span, }, + None, ParsedDescription::Macro, cfg_span, lint_node_id, diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index b7a6a1ef6d66..c6d8411e8356 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use rustc_ast as ast; -use rustc_ast::{AttrStyle, NodeId}; +use rustc_ast::{AttrStyle, NodeId, Safety}; use rustc_errors::DiagCtxtHandle; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; @@ -146,6 +146,7 @@ pub fn parse_single( normal_attr.item.span(), attr.style, path.get_attribute_path(), + Some(normal_attr.item.unsafety), ParsedDescription::Attribute, target_span, target_node_id, @@ -165,6 +166,7 @@ pub fn parse_single_args( inner_span: Span, attr_style: AttrStyle, attr_path: AttrPath, + attr_safety: Option, parsed_description: ParsedDescription, target_span: Span, target_node_id: NodeId, @@ -181,14 +183,24 @@ pub fn parse_single_args( sess, stage: Early { emit_errors }, }; + let mut emit_lint = |lint| { + crate::lints::emit_attribute_lint(&lint, sess); + }; + if let Some(safety) = attr_safety { + parser.check_attribute_safety( + &attr_path, + inner_span, + safety, + &mut emit_lint, + target_node_id, + ) + } let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext { shared: SharedContext { cx: &mut parser, target_span, target_id: target_node_id, - emit_lint: &mut |lint| { - crate::lints::emit_attribute_lint(&lint, sess); - }, + emit_lint: &mut emit_lint, }, attr_span, inner_span, @@ -289,6 +301,14 @@ pub fn parse_attribute_list( ast::AttrKind::Normal(n) => { attr_paths.push(PathParser(Cow::Borrowed(&n.item.path))); + self.check_attribute_safety( + &AttrPath::from_ast(&n.item.path), + lower_span(n.item.span()), + n.item.unsafety, + &mut emit_lint, + target_id, + ); + let parts = n.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); @@ -312,7 +332,7 @@ pub fn parse_attribute_list( emit_lint: &mut emit_lint, }, attr_span: lower_span(attr.span), - inner_span: lower_span(attr.get_normal_item().span()), + inner_span: lower_span(n.item.span()), attr_style: attr.style, parsed_description: ParsedDescription::Attribute, template: &accept.template, diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 046cca4c742b..7a7f2555287a 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -98,6 +98,7 @@ pub mod parser; mod lints; +mod safety; mod session_diagnostics; mod target_checking; pub mod validate_attr; diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index 3a2a37046696..a23884d7f71e 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -98,5 +98,17 @@ pub fn emit_attribute_lint(lint: &AttributeLint, lint_emi }, ) } + &AttributeLintKind::UnsafeAttrOutsideUnsafe { + attribute_name_span, + sugg_spans: (left, right), + } => lint_emitter.emit_node_span_lint( + rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE, + *id, + *span, + session_diagnostics::UnsafeAttrOutsideUnsafeLint { + span: attribute_name_span, + suggestion: session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion { left, right }, + }, + ), } } diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs new file mode 100644 index 000000000000..ff385bf13aaa --- /dev/null +++ b/compiler/rustc_attr_parsing/src/safety.rs @@ -0,0 +1,116 @@ +use rustc_ast::Safety; +use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP}; +use rustc_hir::AttrPath; +use rustc_hir::lints::{AttributeLint, AttributeLintKind}; +use rustc_span::{Span, sym}; + +use crate::context::Stage; +use crate::{AttributeParser, ShouldEmit}; + +impl<'sess, S: Stage> AttributeParser<'sess, S> { + pub fn check_attribute_safety( + &mut self, + attr_path: &AttrPath, + attr_span: Span, + attr_safety: Safety, + emit_lint: &mut impl FnMut(AttributeLint), + target_id: S::Id, + ) { + if matches!(self.stage.should_emit(), ShouldEmit::Nothing) { + return; + } + + let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0].name); + if let Some(name) = name + && [sym::cfg_trace, sym::cfg_attr_trace].contains(&name) + { + return; + } + + // FIXME: We should retrieve this information from the attribute parsers instead of from `BUILTIN_ATTRIBUTE_MAP` + let builtin_attr_info = name.and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)); + let builtin_attr_safety = builtin_attr_info.map(|x| x.safety); + + match (builtin_attr_safety, attr_safety) { + // - Unsafe builtin attribute + // - User wrote `#[unsafe(..)]`, which is permitted on any edition + (Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => { + // OK + } + + // - Unsafe builtin attribute + // - User did not write `#[unsafe(..)]` + (Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => { + let path_span = attr_path.span; + + // If the `attr_item`'s span is not from a macro, then just suggest + // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the + // `unsafe(`, `)` right after and right before the opening and closing + // square bracket respectively. + let diag_span = attr_span; + + // Attributes can be safe in earlier editions, and become unsafe in later ones. + // + // Use the span of the attribute's name to determine the edition: the span of the + // attribute as a whole may be inaccurate if it was emitted by a macro. + // + // See https://github.com/rust-lang/rust/issues/142182. + let emit_error = match unsafe_since { + None => true, + Some(unsafe_since) => path_span.edition() >= unsafe_since, + }; + + if emit_error { + self.stage.emit_err( + self.sess, + crate::session_diagnostics::UnsafeAttrOutsideUnsafe { + span: path_span, + suggestion: + crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion { + left: diag_span.shrink_to_lo(), + right: diag_span.shrink_to_hi(), + }, + }, + ); + } else { + emit_lint(AttributeLint { + id: target_id, + span: path_span, + kind: AttributeLintKind::UnsafeAttrOutsideUnsafe { + attribute_name_span: path_span, + sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), + }, + }) + } + } + + // - Normal builtin attribute + // - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes + (None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => { + self.stage.emit_err( + self.sess, + crate::session_diagnostics::InvalidAttrUnsafe { + span: unsafe_span, + name: attr_path.clone(), + }, + ); + } + + // - Normal builtin attribute + // - No explicit `#[unsafe(..)]` written. + (None | Some(AttributeSafety::Normal), Safety::Default) => { + // OK + } + + ( + Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None, + Safety::Safe(..), + ) => { + self.sess.dcx().span_delayed_bug( + attr_span, + "`check_attribute_safety` does not expect `Safety::Safe` on attributes", + ); + } + } + } +} diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 8d783503f7be..f94f0867451f 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -1,6 +1,6 @@ use std::num::IntErrorKind; -use rustc_ast::{self as ast, Path}; +use rustc_ast::{self as ast}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, @@ -790,7 +790,7 @@ pub(crate) struct InvalidAttrUnsafe { #[primary_span] #[label] pub span: Span, - pub name: Path, + pub name: AttrPath, } #[derive(Diagnostic)] @@ -803,6 +803,15 @@ pub(crate) struct UnsafeAttrOutsideUnsafe { pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, } +#[derive(LintDiagnostic)] +#[diag(attr_parsing_unsafe_attr_outside_unsafe)] +pub(crate) struct UnsafeAttrOutsideUnsafeLint { + #[label] + pub span: Span, + #[subdiagnostic] + pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, +} + #[derive(Subdiagnostic)] #[multipart_suggestion( attr_parsing_unsafe_attr_outside_unsafe_suggestion, diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index 4065fe7ce173..9034fe45427f 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -5,21 +5,21 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{ - self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, NodeId, - Path, Safety, + self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety, }; -use rustc_errors::{Applicability, DiagCtxtHandle, FatalError, PResult}; -use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; +use rustc_errors::{Applicability, FatalError, PResult}; +use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; +use rustc_hir::AttrPath; use rustc_parse::parse_in; use rustc_session::errors::report_lit_error; use rustc_session::lint::BuiltinLintDiag; -use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE}; +use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_session::parse::ParseSess; use rustc_span::{Span, Symbol, sym}; use crate::{AttributeParser, Late, session_diagnostics as errors}; -pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) { +pub fn check_attr(psess: &ParseSess, attr: &Attribute) { if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace) { return; @@ -27,9 +27,6 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) { let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); - let builtin_attr_safety = builtin_attr_info.map(|x| x.safety); - check_attribute_safety(psess, builtin_attr_safety, attr, id); - // Check input tokens for built-in and key-value attributes. match builtin_attr_info { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. @@ -150,101 +147,6 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte } } -pub fn check_attribute_safety( - psess: &ParseSess, - builtin_attr_safety: Option, - attr: &Attribute, - id: NodeId, -) { - let attr_item = attr.get_normal_item(); - match (builtin_attr_safety, attr_item.unsafety) { - // - Unsafe builtin attribute - // - User wrote `#[unsafe(..)]`, which is permitted on any edition - (Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => { - // OK - } - - // - Unsafe builtin attribute - // - User did not write `#[unsafe(..)]` - (Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => { - let path_span = attr_item.path.span; - - // If the `attr_item`'s span is not from a macro, then just suggest - // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the - // `unsafe(`, `)` right after and right before the opening and closing - // square bracket respectively. - let diag_span = attr_item.span(); - - // Attributes can be safe in earlier editions, and become unsafe in later ones. - // - // Use the span of the attribute's name to determine the edition: the span of the - // attribute as a whole may be inaccurate if it was emitted by a macro. - // - // See https://github.com/rust-lang/rust/issues/142182. - let emit_error = match unsafe_since { - None => true, - Some(unsafe_since) => path_span.edition() >= unsafe_since, - }; - - if emit_error { - psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe { - span: path_span, - suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion { - left: diag_span.shrink_to_lo(), - right: diag_span.shrink_to_hi(), - }, - }); - } else { - psess.buffer_lint( - UNSAFE_ATTR_OUTSIDE_UNSAFE, - path_span, - id, - BuiltinLintDiag::UnsafeAttrOutsideUnsafe { - attribute_name_span: path_span, - sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), - }, - ); - } - } - - // - Normal builtin attribute - // - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes - (None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => { - psess.dcx().emit_err(errors::InvalidAttrUnsafe { - span: unsafe_span, - name: attr_item.path.clone(), - }); - } - - // - Normal builtin attribute - // - No explicit `#[unsafe(..)]` written. - (None | Some(AttributeSafety::Normal), Safety::Default) => { - // OK - } - - ( - Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None, - Safety::Safe(..), - ) => { - psess.dcx().span_delayed_bug( - attr_item.span(), - "`check_attribute_safety` does not expect `Safety::Safe` on attributes", - ); - } - } -} - -// Called by `check_builtin_meta_item` and code that manually denies -// `unsafe(...)` in `cfg` -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) = unsafety { - diag.emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: name.clone() }); - } -} - pub fn check_builtin_meta_item( psess: &ParseSess, meta: &MetaItem, @@ -258,8 +160,11 @@ pub fn check_builtin_meta_item( emit_malformed_attribute(psess, style, meta.span, name, template); } - if deny_unsafety { - deny_builtin_meta_unsafety(psess.dcx(), meta.unsafety, &meta.path); + if deny_unsafety && let Safety::Unsafe(unsafe_span) = meta.unsafety { + psess.dcx().emit_err(errors::InvalidAttrUnsafe { + span: unsafe_span, + name: AttrPath::from_ast(&meta.path), + }); } } diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 5ca4fff94878..b24e3065622d 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -54,6 +54,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result Vec { /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec { - validate_attr::check_attribute_safety( - &self.sess.psess, - Some(AttributeSafety::Normal), - &cfg_attr, - ast::CRATE_NODE_ID, - ); - // A trace attribute left in AST in place of the original `cfg_attr` attribute. // It can later be used by lints or other diagnostics. let trace_attr = attr_into_trace(cfg_attr.clone(), sym::cfg_attr_trace); @@ -421,13 +412,6 @@ pub(crate) fn cfg_true( node: NodeId, emit_errors: ShouldEmit, ) -> EvalConfigResult { - // 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, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 6d048c120a21..20fb321307ac 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -2158,11 +2158,7 @@ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) { let mut span: Option = None; while let Some(attr) = attrs.next() { rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features); - validate_attr::check_attr( - &self.cx.sess.psess, - attr, - self.cx.current_expansion.lint_node_id, - ); + validate_attr::check_attr(&self.cx.sess.psess, attr); AttributeParser::parse_limited_all( self.cx.sess, slice::from_ref(attr), diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index 8563937f70d3..a4c60fd2cc1a 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -62,4 +62,8 @@ pub enum AttributeLintKind { target: Target, target_span: Span, }, + UnsafeAttrOutsideUnsafe { + attribute_name_span: Span, + sugg_spans: (Span, Span), + }, } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index bf721154d73b..75e7af4c1173 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -890,10 +890,6 @@ lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::` -lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe - .label = usage of unsafe attribute -lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` - lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´ lint_untranslatable_diag = diagnostics should be created using translatable messages diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index e376d7d2ab88..87ccd114ee97 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -283,16 +283,6 @@ pub fn decorate_builtin_lint( BuiltinLintDiag::UnusedQualifications { removal_span } => { lints::UnusedQualifications { removal_span }.decorate_lint(diag); } - BuiltinLintDiag::UnsafeAttrOutsideUnsafe { - attribute_name_span, - sugg_spans: (left, right), - } => { - lints::UnsafeAttrOutsideUnsafe { - span: attribute_name_span, - suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }, - } - .decorate_lint(diag); - } BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span: lt_span, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0687490645d3..6568aa6fd5aa 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2880,27 +2880,6 @@ pub(crate) struct AssociatedConstElidedLifetime { pub lifetimes_in_scope: MultiSpan, } -#[derive(LintDiagnostic)] -#[diag(lint_unsafe_attr_outside_unsafe)] -pub(crate) struct UnsafeAttrOutsideUnsafe { - #[label] - pub span: Span, - #[subdiagnostic] - pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion( - lint_unsafe_attr_outside_unsafe_suggestion, - applicability = "machine-applicable" -)] -pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { - #[suggestion_part(code = "unsafe(")] - pub left: Span, - #[suggestion_part(code = ")")] - pub right: Span, -} - #[derive(LintDiagnostic)] #[diag(lint_static_mut_refs_lint)] pub(crate) struct RefOfMutStatic<'a> { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 326fdaf9cec9..abdc41eb57c2 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -687,10 +687,6 @@ pub enum BuiltinLintDiag { /// The span of the unnecessarily-qualified path to remove. removal_span: Span, }, - UnsafeAttrOutsideUnsafe { - attribute_name_span: Span, - sugg_spans: (Span, Span), - }, AssociatedConstElidedLifetime { elided: bool, span: Span, From 6e3a0154005e24bb5de47101c845d99d22bedd76 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 1 Dec 2025 22:03:53 +0100 Subject: [PATCH 270/585] UI test changes --- .../unsafe/double-unsafe-attributes.stderr | 12 +-- .../unsafe/proc-unsafe-attributes.stderr | 80 +++++++++---------- tests/ui/ffi-attrs/ffi_const.stderr | 22 ++--- tests/ui/ffi-attrs/ffi_pure.stderr | 22 ++--- 4 files changed, 68 insertions(+), 68 deletions(-) diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr index 0825cf794083..8ab945e0f182 100644 --- a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr @@ -9,6 +9,12 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(r#unsafe(no_mangle))] | ++ +error: cannot find attribute `r#unsafe` in this scope + --> $DIR/double-unsafe-attributes.rs:1:10 + | +LL | #[unsafe(unsafe(no_mangle))] + | ^^^^^^ + error: `r#unsafe` is not an unsafe attribute --> $DIR/double-unsafe-attributes.rs:1:3 | @@ -17,11 +23,5 @@ LL | #[unsafe(unsafe(no_mangle))] | = note: extraneous unsafe is not allowed in attributes -error: cannot find attribute `r#unsafe` in this scope - --> $DIR/double-unsafe-attributes.rs:1:10 - | -LL | #[unsafe(unsafe(no_mangle))] - | ^^^^^^ - error: aborting due to 3 previous errors diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr index 94edb263a6af..4527cf676f78 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr @@ -12,46 +12,6 @@ LL | #[unsafe(allow(unsafe(dead_code)))] | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: `proc_macro` is not an unsafe attribute - --> $DIR/proc-unsafe-attributes.rs:1:3 - | -LL | #[unsafe(proc_macro)] - | ^^^^^^ this is not an unsafe attribute - | - = note: extraneous unsafe is not allowed in attributes - -error: `proc_macro_derive` is not an unsafe attribute - --> $DIR/proc-unsafe-attributes.rs:7:3 - | -LL | #[unsafe(proc_macro_derive(Foo))] - | ^^^^^^ this is not an unsafe attribute - | - = note: extraneous unsafe is not allowed in attributes - -error: `proc_macro_attribute` is not an unsafe attribute - --> $DIR/proc-unsafe-attributes.rs:18:3 - | -LL | #[unsafe(proc_macro_attribute)] - | ^^^^^^ this is not an unsafe attribute - | - = note: extraneous unsafe is not allowed in attributes - -error: `allow` is not an unsafe attribute - --> $DIR/proc-unsafe-attributes.rs:23:3 - | -LL | #[unsafe(allow(dead_code))] - | ^^^^^^ this is not an unsafe attribute - | - = note: extraneous unsafe is not allowed in attributes - -error: `allow` is not an unsafe attribute - --> $DIR/proc-unsafe-attributes.rs:27:3 - | -LL | #[unsafe(allow(unsafe(dead_code)))] - | ^^^^^^ this is not an unsafe attribute - | - = note: extraneous unsafe is not allowed in attributes - error: expected identifier, found keyword `unsafe` --> $DIR/proc-unsafe-attributes.rs:27:16 | @@ -103,6 +63,22 @@ LL | #[unsafe(allow(unsafe(dead_code)))] | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: `proc_macro` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:1:3 + | +LL | #[unsafe(proc_macro)] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `proc_macro_derive` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:7:3 + | +LL | #[unsafe(proc_macro_derive(Foo))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + error: expected identifier, found keyword `unsafe` --> $DIR/proc-unsafe-attributes.rs:12:21 | @@ -132,6 +108,30 @@ LL - #[proc_macro_derive(unsafe(Foo))] LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | +error: `proc_macro_attribute` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:18:3 + | +LL | #[unsafe(proc_macro_attribute)] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `allow` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:23:3 + | +LL | #[unsafe(allow(dead_code))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `allow` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:27:3 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + error[E0452]: malformed lint attribute input --> $DIR/proc-unsafe-attributes.rs:27:16 | diff --git a/tests/ui/ffi-attrs/ffi_const.stderr b/tests/ui/ffi-attrs/ffi_const.stderr index f3be92543183..af54486e433c 100644 --- a/tests/ui/ffi-attrs/ffi_const.stderr +++ b/tests/ui/ffi-attrs/ffi_const.stderr @@ -1,14 +1,3 @@ -error: unsafe attribute used without unsafe - --> $DIR/ffi_const.rs:16:7 - | -LL | #[ffi_const] - | ^^^^^^^^^ usage of unsafe attribute - | -help: wrap the attribute in `unsafe(...)` - | -LL | #[unsafe(ffi_const)] - | +++++++ + - error: `#[ffi_const]` attribute cannot be used on functions --> $DIR/ffi_const.rs:4:1 | @@ -33,5 +22,16 @@ LL | #[unsafe(ffi_const)] | = help: `#[ffi_const]` can only be applied to foreign functions +error: unsafe attribute used without unsafe + --> $DIR/ffi_const.rs:16:7 + | +LL | #[ffi_const] + | ^^^^^^^^^ usage of unsafe attribute + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(ffi_const)] + | +++++++ + + error: aborting due to 4 previous errors diff --git a/tests/ui/ffi-attrs/ffi_pure.stderr b/tests/ui/ffi-attrs/ffi_pure.stderr index da1eae975ac2..11e9199b40f4 100644 --- a/tests/ui/ffi-attrs/ffi_pure.stderr +++ b/tests/ui/ffi-attrs/ffi_pure.stderr @@ -1,14 +1,3 @@ -error: unsafe attribute used without unsafe - --> $DIR/ffi_pure.rs:16:7 - | -LL | #[ffi_pure] - | ^^^^^^^^ usage of unsafe attribute - | -help: wrap the attribute in `unsafe(...)` - | -LL | #[unsafe(ffi_pure)] - | +++++++ + - error: `#[ffi_pure]` attribute cannot be used on functions --> $DIR/ffi_pure.rs:4:1 | @@ -33,5 +22,16 @@ LL | #[unsafe(ffi_pure)] | = help: `#[ffi_pure]` can only be applied to foreign functions +error: unsafe attribute used without unsafe + --> $DIR/ffi_pure.rs:16:7 + | +LL | #[ffi_pure] + | ^^^^^^^^ usage of unsafe attribute + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(ffi_pure)] + | +++++++ + + error: aborting due to 4 previous errors From 892bd18ad8f33d1a3a5616ff196b50958a7ddffb Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 1 Dec 2025 22:24:33 +0100 Subject: [PATCH 271/585] Add a regression test for unsafe nonexistent attributes --- .../unsafe/unsafe-nonexistent-attribute.rs | 10 ++++++++++ .../unsafe/unsafe-nonexistent-attribute.stderr | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.rs create mode 100644 tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.stderr diff --git a/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.rs b/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.rs new file mode 100644 index 000000000000..c7d7b712925d --- /dev/null +++ b/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.rs @@ -0,0 +1,10 @@ +// This is a regression test for https://github.com/rust-lang/rust/issues/148453 +// We want the `cannot find attribute` error to appear before `is not an unsafe attribute` +//@ edition: 2024 + +#[unsafe(does_not_exist)] +//~^ ERROR cannot find attribute +//~| ERROR is not an unsafe attribute +fn aa() {} + +fn main() {} diff --git a/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.stderr b/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.stderr new file mode 100644 index 000000000000..42d9425ed31f --- /dev/null +++ b/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.stderr @@ -0,0 +1,16 @@ +error: cannot find attribute `does_not_exist` in this scope + --> $DIR/unsafe-nonexistent-attribute.rs:5:10 + | +LL | #[unsafe(does_not_exist)] + | ^^^^^^^^^^^^^^ + +error: `does_not_exist` is not an unsafe attribute + --> $DIR/unsafe-nonexistent-attribute.rs:5:3 + | +LL | #[unsafe(does_not_exist)] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: aborting due to 2 previous errors + From 31d289c9bc0bea53942cea6ccca760db53e6e3bd Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 2 Dec 2025 19:42:41 +0100 Subject: [PATCH 272/585] Lower spans in `AttrPath` correctly --- compiler/rustc_attr_parsing/src/attributes/cfg.rs | 4 +++- compiler/rustc_attr_parsing/src/interface.rs | 8 ++++---- compiler/rustc_attr_parsing/src/validate_attr.rs | 3 ++- compiler/rustc_hir/src/hir.rs | 11 ++++++++--- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index e47fa075fbf7..bd228315b2c9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -1,3 +1,5 @@ +use std::convert::identity; + use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, NodeId, ast, token}; @@ -353,7 +355,7 @@ pub fn parse_cfg_attr( span, attr_span: cfg_attr.span, template: CFG_ATTR_TEMPLATE, - path: AttrPath::from_ast(&cfg_attr.get_normal_item().path), + path: AttrPath::from_ast(&cfg_attr.get_normal_item().path, identity), description: ParsedDescription::Attribute, reason, suggestions: CFG_ATTR_TEMPLATE diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index c6d8411e8356..87e29b7b0de6 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -300,9 +300,10 @@ pub fn parse_attribute_list( // } ast::AttrKind::Normal(n) => { attr_paths.push(PathParser(Cow::Borrowed(&n.item.path))); + let attr_path = AttrPath::from_ast(&n.item.path, lower_span); self.check_attribute_safety( - &AttrPath::from_ast(&n.item.path), + &attr_path, lower_span(n.item.span()), n.item.unsafety, &mut emit_lint, @@ -321,7 +322,6 @@ pub fn parse_attribute_list( ) else { continue; }; - let path = parser.path(); let args = parser.args(); for accept in accepts { let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { @@ -336,7 +336,7 @@ pub fn parse_attribute_list( attr_style: attr.style, parsed_description: ParsedDescription::Attribute, template: &accept.template, - attr_path: path.get_attribute_path(), + attr_path: attr_path.clone(), }; (accept.accept_fn)(&mut cx, args); @@ -361,7 +361,7 @@ pub fn parse_attribute_list( // ); attributes.push(Attribute::Unparsed(Box::new(AttrItem { - path: AttrPath::from_ast(&n.item.path), + path: attr_path.clone(), args: self.lower_attr_args(&n.item.args, lower_span), id: HashIgnoredAttrId { attr_id: attr.id }, style: attr.style, diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index 9034fe45427f..c57e0baea05f 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -1,5 +1,6 @@ //! Meta-syntax validation logic of attributes for post-expansion. +use std::convert::identity; use std::slice; use rustc_ast::token::Delimiter; @@ -163,7 +164,7 @@ pub fn check_builtin_meta_item( if deny_unsafety && let Safety::Unsafe(unsafe_span) = meta.unsafety { psess.dcx().emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, - name: AttrPath::from_ast(&meta.path), + name: AttrPath::from_ast(&meta.path, identity), }); } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 8f297677ff85..94c47b06e635 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1193,10 +1193,15 @@ fn into_diag_arg(self, path: &mut Option) -> DiagArgValue { } impl AttrPath { - pub fn from_ast(path: &ast::Path) -> Self { + pub fn from_ast(path: &ast::Path, lower_span: impl Copy + Fn(Span) -> Span) -> Self { AttrPath { - segments: path.segments.iter().map(|i| i.ident).collect::>().into_boxed_slice(), - span: path.span, + segments: path + .segments + .iter() + .map(|i| Ident { name: i.ident.name, span: lower_span(i.ident.span) }) + .collect::>() + .into_boxed_slice(), + span: lower_span(path.span), } } } From 1d204fcf1da365878403b6d9725b764cbbb0ecd7 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 2 Dec 2025 20:10:40 +0100 Subject: [PATCH 273/585] Add unsafe to no_mangle incremental tests --- tests/incremental/hashes/function_interfaces.rs | 2 +- tests/incremental/hashes/inherent_impls.rs | 5 +++-- tests/incremental/hashes/statics.rs | 2 +- tests/incremental/hashes/trait_impls.rs | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/incremental/hashes/function_interfaces.rs b/tests/incremental/hashes/function_interfaces.rs index e58ee1a6d4e4..5b03f9ed6c67 100644 --- a/tests/incremental/hashes/function_interfaces.rs +++ b/tests/incremental/hashes/function_interfaces.rs @@ -279,7 +279,7 @@ pub fn no_mangle() {} #[rustc_clean(cfg = "cfail3")] #[rustc_clean(cfg = "cfail5")] #[rustc_clean(cfg = "cfail6")] -#[no_mangle] +#[unsafe(no_mangle)] pub fn no_mangle() {} // Linkage --------------------------------------------------------------------- diff --git a/tests/incremental/hashes/inherent_impls.rs b/tests/incremental/hashes/inherent_impls.rs index ebcab178f209..75c0939fbfcd 100644 --- a/tests/incremental/hashes/inherent_impls.rs +++ b/tests/incremental/hashes/inherent_impls.rs @@ -5,6 +5,7 @@ // and make sure that the hash has changed, then change nothing between rev2 and // rev3 and make sure that the hash has not changed. +//@ edition: 2024 //@ build-pass (FIXME(62277): could be check-pass?) //@ revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 //@ compile-flags: -Z query-dep-graph -O @@ -649,7 +650,7 @@ impl Foo { //-------------------------- //-------------------------- //-------------------------- - //---------- + //------------------ pub fn add_no_mangle_to_method(&self) { } } @@ -663,7 +664,7 @@ impl Foo { #[rustc_clean(cfg="cfail3")] #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] - #[no_mangle] + #[unsafe(no_mangle)] pub fn add_no_mangle_to_method(&self) { } } diff --git a/tests/incremental/hashes/statics.rs b/tests/incremental/hashes/statics.rs index cd394ed866e9..94548eeef7fd 100644 --- a/tests/incremental/hashes/statics.rs +++ b/tests/incremental/hashes/statics.rs @@ -66,7 +66,7 @@ #[rustc_clean(cfg="cfail3")] #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] -#[no_mangle] +#[unsafe(no_mangle)] static STATIC_NO_MANGLE: u8 = 0; diff --git a/tests/incremental/hashes/trait_impls.rs b/tests/incremental/hashes/trait_impls.rs index 03ca672af131..d4ac69a8b55d 100644 --- a/tests/incremental/hashes/trait_impls.rs +++ b/tests/incremental/hashes/trait_impls.rs @@ -569,7 +569,7 @@ impl AddNoMangleToMethod for Foo { // ------------------------- // ------------------------- // ------------------------- - // --------- + // ----------------- fn add_no_mangle_to_method(&self) { } } @@ -583,7 +583,7 @@ impl AddNoMangleToMethod for Foo { #[rustc_clean(cfg="cfail3")] #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] - #[no_mangle] + #[unsafe(no_mangle)] fn add_no_mangle_to_method(&self) { } } From 8f8247812e9d4ff206eb4f90f26c7e7697e50c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 3 Dec 2025 17:01:37 +0100 Subject: [PATCH 274/585] address review comments --- .../issue-43106-gating-of-builtin-attrs.rs | 1 - ...issue-43106-gating-of-builtin-attrs.stderr | 402 +++++++++--------- tests/ui/macros/test-on-crate-root.rs | 9 +- tests/ui/macros/test-on-crate-root.stderr | 4 +- 4 files changed, 208 insertions(+), 208 deletions(-) diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index 5b32c5ca0dfa..4b5420a2ff8b 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -33,7 +33,6 @@ //@ check-pass -#![feature(test)] #![warn(unused_attributes, unknown_lints)] //~^ NOTE the lint level is defined here //~| NOTE the lint level is defined here diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index d8b1dc91acc4..676372ad85e0 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -1,5 +1,5 @@ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ @@ -7,193 +7,193 @@ LL | mod inner { #![macro_escape] } = help: try an outer attribute: `#[macro_use]` warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:494:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:42:9 | LL | #![warn(x5400)] | ^^^^^ | note: the lint level is defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:28 | LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:10 | LL | #![allow(x5300)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:11 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:11 | LL | #![forbid(x5200)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:9 | LL | #![deny(x5100)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:111:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:110:8 | LL | #[warn(x5400)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:114:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:113:25 | LL | mod inner { #![warn(x5400)] } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:117:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:12 | LL | #[warn(x5400)] fn f() { } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:120:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:12 | LL | #[warn(x5400)] struct S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:123:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:12 | LL | #[warn(x5400)] type T = S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:126:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:12 | LL | #[warn(x5400)] impl S { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:130:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:129:9 | LL | #[allow(x5300)] | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:133:26 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:132:26 | LL | mod inner { #![allow(x5300)] } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:136:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:13 | LL | #[allow(x5300)] fn f() { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:139:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:13 | LL | #[allow(x5300)] struct S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:142:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:13 | LL | #[allow(x5300)] type T = S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:145:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:13 | LL | #[allow(x5300)] impl S { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:149:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:148:10 | LL | #[forbid(x5200)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:152:27 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:151:27 | LL | mod inner { #![forbid(x5200)] } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:155:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:14 | LL | #[forbid(x5200)] fn f() { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:158:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:14 | LL | #[forbid(x5200)] struct S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:161:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:14 | LL | #[forbid(x5200)] type T = S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:164:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:14 | LL | #[forbid(x5200)] impl S { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:168:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:167:8 | LL | #[deny(x5100)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:171:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:170:25 | LL | mod inner { #![deny(x5100)] } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:174:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:12 | LL | #[deny(x5100)] fn f() { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:177:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:12 | LL | #[deny(x5100)] struct S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:180:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:179:12 | LL | #[deny(x5100)] type T = S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:183:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:182:12 | LL | #[deny(x5100)] impl S { } | ^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:468:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:9 | LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^^^^^ @@ -203,7 +203,7 @@ LL | #![reexport_test_harness_main = "2900"] | + warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:1 | LL | #[link(name = "x")] | ^^^^^^^^^^^^^^^^^^^ @@ -219,7 +219,7 @@ LL | | } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:833:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:832:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -230,7 +230,7 @@ LL | #![crate_type = "0800"] | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:857:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:856:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL | #![feature(x0600)] | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:882:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:881:1 | LL | #[no_main] | ^^^^^^^^^^ @@ -252,7 +252,7 @@ LL | #![no_main] | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:906:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:905:1 | LL | #[no_builtins] | ^^^^^^^^^^^^^^ @@ -263,7 +263,7 @@ LL | #![no_builtins] | + warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:71:1 | LL | #![link(name = "x")] | ^^^^^^^^^^^^^^^^^^^^ not an `extern` block @@ -271,7 +271,7 @@ LL | #![link(name = "x")] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:100:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:99:12 | LL | #![feature(rust1)] | ^^^^^ @@ -279,13 +279,13 @@ LL | #![feature(rust1)] = note: `#[warn(stable_features)]` on by default warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:473:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:472:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -296,7 +296,7 @@ LL | #![reexport_test_harness_main = "2900"] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:480:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -307,7 +307,7 @@ LL | #![reexport_test_harness_main = "2900"] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:484:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -318,7 +318,7 @@ LL | #![reexport_test_harness_main = "2900"] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -329,7 +329,7 @@ LL | #![reexport_test_harness_main = "2900"] impl S { } | + warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:17 | LL | mod inner { #![link(name = "x")] } | ------------^^^^^^^^^^^^^^^^^^^^-- not an `extern` block @@ -337,7 +337,7 @@ LL | mod inner { #![link(name = "x")] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:5 | LL | #[link(name = "x")] fn f() { } | ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block @@ -345,7 +345,7 @@ LL | #[link(name = "x")] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:723:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5 | LL | #[link(name = "x")] struct S; | ^^^^^^^^^^^^^^^^^^^ --------- not an `extern` block @@ -353,7 +353,7 @@ LL | #[link(name = "x")] struct S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5 | LL | #[link(name = "x")] type T = S; | ^^^^^^^^^^^^^^^^^^^ ----------- not an `extern` block @@ -361,7 +361,7 @@ LL | #[link(name = "x")] type T = S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 | LL | #[link(name = "x")] impl S { } | ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block @@ -369,7 +369,7 @@ LL | #[link(name = "x")] impl S { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | LL | #[link(name = "x")] extern "Rust" {} | ^^^^^^^^^^^^^^^^^^^ @@ -377,13 +377,13 @@ LL | #[link(name = "x")] extern "Rust" {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:837:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:840:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -394,7 +394,7 @@ LL | #![crate_type = "0800"] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:844:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -405,7 +405,7 @@ LL | #![crate_type = "0800"] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:848:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -416,7 +416,7 @@ LL | #![crate_type = "0800"] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:852:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:851:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -427,13 +427,13 @@ LL | #![crate_type = "0800"] impl S { } | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:861:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:864:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:863:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ @@ -444,7 +444,7 @@ LL | #![feature(x0600)] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:868:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ @@ -455,7 +455,7 @@ LL | #![feature(x0600)] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:872:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ @@ -466,7 +466,7 @@ LL | #![feature(x0600)] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:876:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:875:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ @@ -477,13 +477,13 @@ LL | #![feature(x0600)] impl S { } | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:886:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:885:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:889:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:888:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ @@ -494,7 +494,7 @@ LL | #![no_main] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:893:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:892:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ @@ -505,7 +505,7 @@ LL | #![no_main] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:897:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:896:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ @@ -516,7 +516,7 @@ LL | #![no_main] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:901:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:900:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ @@ -527,13 +527,13 @@ LL | #![no_main] impl S { } | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:910:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:909:17 | LL | mod inner { #![no_builtins] } | ^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:913:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:912:5 | LL | #[no_builtins] fn f() { } | ^^^^^^^^^^^^^^ @@ -544,7 +544,7 @@ LL | #![no_builtins] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:917:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:916:5 | LL | #[no_builtins] struct S; | ^^^^^^^^^^^^^^ @@ -555,7 +555,7 @@ LL | #![no_builtins] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:921:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:920:5 | LL | #[no_builtins] type T = S; | ^^^^^^^^^^^^^^ @@ -566,7 +566,7 @@ LL | #![no_builtins] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:924:5 | LL | #[no_builtins] impl S { } | ^^^^^^^^^^^^^^ @@ -577,7 +577,7 @@ LL | #![no_builtins] impl S { } | + warning: `#[macro_use]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:191:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:190:5 | LL | #[macro_use] fn f() { } | ^^^^^^^^^^^^ @@ -586,7 +586,7 @@ LL | #[macro_use] fn f() { } = help: `#[macro_use]` can be applied to crates, extern crates, and modules warning: `#[macro_use]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:197:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:196:5 | LL | #[macro_use] struct S; | ^^^^^^^^^^^^ @@ -595,7 +595,7 @@ LL | #[macro_use] struct S; = help: `#[macro_use]` can be applied to crates, extern crates, and modules warning: `#[macro_use]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:203:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:202:5 | LL | #[macro_use] type T = S; | ^^^^^^^^^^^^ @@ -604,7 +604,7 @@ LL | #[macro_use] type T = S; = help: `#[macro_use]` can be applied to crates, extern crates, and modules warning: `#[macro_use]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:209:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:208:5 | LL | #[macro_use] impl S { } | ^^^^^^^^^^^^ @@ -613,7 +613,7 @@ LL | #[macro_use] impl S { } = help: `#[macro_use]` can be applied to crates, extern crates, and modules warning: `#[macro_export]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:215:1 | LL | #[macro_export] | ^^^^^^^^^^^^^^^ @@ -622,7 +622,7 @@ LL | #[macro_export] = help: `#[macro_export]` can only be applied to macro defs warning: `#[macro_export]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:222:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:17 | LL | mod inner { #![macro_export] } | ^^^^^^^^^^^^^^^^ @@ -631,7 +631,7 @@ LL | mod inner { #![macro_export] } = help: `#[macro_export]` can only be applied to macro defs warning: `#[macro_export]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5 | LL | #[macro_export] fn f() { } | ^^^^^^^^^^^^^^^ @@ -640,7 +640,7 @@ LL | #[macro_export] fn f() { } = help: `#[macro_export]` can only be applied to macro defs warning: `#[macro_export]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:234:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:233:5 | LL | #[macro_export] struct S; | ^^^^^^^^^^^^^^^ @@ -649,7 +649,7 @@ LL | #[macro_export] struct S; = help: `#[macro_export]` can only be applied to macro defs warning: `#[macro_export]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:240:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:239:5 | LL | #[macro_export] type T = S; | ^^^^^^^^^^^^^^^ @@ -658,7 +658,7 @@ LL | #[macro_export] type T = S; = help: `#[macro_export]` can only be applied to macro defs warning: `#[macro_export]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:246:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:245:5 | LL | #[macro_export] impl S { } | ^^^^^^^^^^^^^^^ @@ -667,7 +667,7 @@ LL | #[macro_export] impl S { } = help: `#[macro_export]` can only be applied to macro defs warning: `#[path]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:257:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:256:5 | LL | #[path = "3800"] fn f() { } | ^^^^^^^^^^^^^^^^ @@ -676,7 +676,7 @@ LL | #[path = "3800"] fn f() { } = help: `#[path]` can only be applied to modules warning: `#[path]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:263:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:262:5 | LL | #[path = "3800"] struct S; | ^^^^^^^^^^^^^^^^ @@ -685,7 +685,7 @@ LL | #[path = "3800"] struct S; = help: `#[path]` can only be applied to modules warning: `#[path]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:268:5 | LL | #[path = "3800"] type T = S; | ^^^^^^^^^^^^^^^^ @@ -694,7 +694,7 @@ LL | #[path = "3800"] type T = S; = help: `#[path]` can only be applied to modules warning: `#[path]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:274:5 | LL | #[path = "3800"] impl S { } | ^^^^^^^^^^^^^^^^ @@ -703,7 +703,7 @@ LL | #[path = "3800"] impl S { } = help: `#[path]` can only be applied to modules warning: `#[automatically_derived]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:282:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:281:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -712,7 +712,7 @@ LL | #[automatically_derived] = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[automatically_derived]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:288:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:287:17 | LL | mod inner { #![automatically_derived] } | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -721,7 +721,7 @@ LL | mod inner { #![automatically_derived] } = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[automatically_derived]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:294:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:293:5 | LL | #[automatically_derived] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -730,7 +730,7 @@ LL | #[automatically_derived] fn f() { } = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[automatically_derived]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:300:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:299:5 | LL | #[automatically_derived] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -739,7 +739,7 @@ LL | #[automatically_derived] struct S; = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[automatically_derived]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:306:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:305:5 | LL | #[automatically_derived] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -748,7 +748,7 @@ LL | #[automatically_derived] type T = S; = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[automatically_derived]` attribute cannot be used on traits - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:312:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:311:5 | LL | #[automatically_derived] trait W { } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -757,7 +757,7 @@ LL | #[automatically_derived] trait W { } = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[automatically_derived]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:318:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:317:5 | LL | #[automatically_derived] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -766,7 +766,7 @@ LL | #[automatically_derived] impl S { } = help: `#[automatically_derived]` can only be applied to trait impl blocks warning: `#[no_mangle]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:327:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:326:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ @@ -775,7 +775,7 @@ LL | #[no_mangle] = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:333:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:17 | LL | mod inner { #![no_mangle] } | ^^^^^^^^^^^^^ @@ -784,7 +784,7 @@ LL | mod inner { #![no_mangle] } = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:340:5 | LL | #[no_mangle] struct S; | ^^^^^^^^^^^^ @@ -793,7 +793,7 @@ LL | #[no_mangle] struct S; = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:346:5 | LL | #[no_mangle] type T = S; | ^^^^^^^^^^^^ @@ -802,7 +802,7 @@ LL | #[no_mangle] type T = S; = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:353:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:352:5 | LL | #[no_mangle] impl S { } | ^^^^^^^^^^^^ @@ -811,7 +811,7 @@ LL | #[no_mangle] impl S { } = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on required trait methods - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:360:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:359:9 | LL | #[no_mangle] fn foo(); | ^^^^^^^^^^^^ @@ -820,7 +820,7 @@ LL | #[no_mangle] fn foo(); = help: `#[no_mangle]` can be applied to functions, inherent methods, statics, and trait methods in impl blocks warning: `#[no_mangle]` attribute cannot be used on provided trait methods - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:366:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:365:9 | LL | #[no_mangle] fn bar() {} | ^^^^^^^^^^^^ @@ -829,7 +829,7 @@ LL | #[no_mangle] fn bar() {} = help: `#[no_mangle]` can be applied to functions, inherent methods, statics, and trait methods in impl blocks warning: `#[should_panic]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ @@ -838,7 +838,7 @@ LL | #[should_panic] = help: `#[should_panic]` can only be applied to functions warning: `#[should_panic]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:17 | LL | mod inner { #![should_panic] } | ^^^^^^^^^^^^^^^^ @@ -847,7 +847,7 @@ LL | mod inner { #![should_panic] } = help: `#[should_panic]` can only be applied to functions warning: `#[should_panic]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:388:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:387:5 | LL | #[should_panic] struct S; | ^^^^^^^^^^^^^^^ @@ -856,7 +856,7 @@ LL | #[should_panic] struct S; = help: `#[should_panic]` can only be applied to functions warning: `#[should_panic]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:394:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:393:5 | LL | #[should_panic] type T = S; | ^^^^^^^^^^^^^^^ @@ -865,7 +865,7 @@ LL | #[should_panic] type T = S; = help: `#[should_panic]` can only be applied to functions warning: `#[should_panic]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:400:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:399:5 | LL | #[should_panic] impl S { } | ^^^^^^^^^^^^^^^ @@ -874,7 +874,7 @@ LL | #[should_panic] impl S { } = help: `#[should_panic]` can only be applied to functions warning: `#[ignore]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:407:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:406:1 | LL | #[ignore] | ^^^^^^^^^ @@ -883,7 +883,7 @@ LL | #[ignore] = help: `#[ignore]` can only be applied to functions warning: `#[ignore]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:413:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:412:17 | LL | mod inner { #![ignore] } | ^^^^^^^^^^ @@ -892,7 +892,7 @@ LL | mod inner { #![ignore] } = help: `#[ignore]` can only be applied to functions warning: `#[ignore]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5 | LL | #[ignore] struct S; | ^^^^^^^^^ @@ -901,7 +901,7 @@ LL | #[ignore] struct S; = help: `#[ignore]` can only be applied to functions warning: `#[ignore]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5 | LL | #[ignore] type T = S; | ^^^^^^^^^ @@ -910,7 +910,7 @@ LL | #[ignore] type T = S; = help: `#[ignore]` can only be applied to functions warning: `#[ignore]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:432:5 | LL | #[ignore] impl S { } | ^^^^^^^^^ @@ -919,7 +919,7 @@ LL | #[ignore] impl S { } = help: `#[ignore]` can only be applied to functions warning: `#[no_implicit_prelude]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:444:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:443:5 | LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -928,7 +928,7 @@ LL | #[no_implicit_prelude] fn f() { } = help: `#[no_implicit_prelude]` can be applied to crates and modules warning: `#[no_implicit_prelude]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:5 | LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -937,7 +937,7 @@ LL | #[no_implicit_prelude] struct S; = help: `#[no_implicit_prelude]` can be applied to crates and modules warning: `#[no_implicit_prelude]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:456:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:5 | LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -946,7 +946,7 @@ LL | #[no_implicit_prelude] type T = S; = help: `#[no_implicit_prelude]` can be applied to crates and modules warning: `#[no_implicit_prelude]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:461:5 | LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -955,7 +955,7 @@ LL | #[no_implicit_prelude] impl S { } = help: `#[no_implicit_prelude]` can be applied to crates and modules warning: `#[macro_escape]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:500:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ @@ -964,7 +964,7 @@ LL | #[macro_escape] fn f() { } = help: `#[macro_escape]` can be applied to crates, extern crates, and modules warning: `#[macro_escape]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:506:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ @@ -973,7 +973,7 @@ LL | #[macro_escape] struct S; = help: `#[macro_escape]` can be applied to crates, extern crates, and modules warning: `#[macro_escape]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:513:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ @@ -982,7 +982,7 @@ LL | #[macro_escape] type T = S; = help: `#[macro_escape]` can be applied to crates, extern crates, and modules warning: `#[macro_escape]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:518:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ @@ -991,13 +991,13 @@ LL | #[macro_escape] impl S { } = help: `#[macro_escape]` can be applied to crates, extern crates, and modules warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:526:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:525:1 | LL | #[no_std] | ^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:528:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:527:1 | LL | / mod no_std { LL | | @@ -1007,61 +1007,61 @@ LL | | } | |_^ warning: the `#![no_std]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:530:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:529:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:533:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:533:15 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:15 | LL | #[no_std] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:537:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:5 | LL | #[no_std] struct S; | ^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:537:15 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:15 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:15 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:15 | LL | #[no_std] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:545:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:545:15 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:15 | LL | #[no_std] impl S { } | ^^^^^^^^^^ warning: `#[cold]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:567:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:566:1 | LL | #[cold] | ^^^^^^^ @@ -1070,7 +1070,7 @@ LL | #[cold] = help: `#[cold]` can only be applied to functions warning: `#[cold]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:574:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:573:17 | LL | mod inner { #![cold] } | ^^^^^^^^ @@ -1079,7 +1079,7 @@ LL | mod inner { #![cold] } = help: `#[cold]` can only be applied to functions warning: `#[cold]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:582:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:5 | LL | #[cold] struct S; | ^^^^^^^ @@ -1088,7 +1088,7 @@ LL | #[cold] struct S; = help: `#[cold]` can only be applied to functions warning: `#[cold]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:588:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:587:5 | LL | #[cold] type T = S; | ^^^^^^^ @@ -1097,7 +1097,7 @@ LL | #[cold] type T = S; = help: `#[cold]` can only be applied to functions warning: `#[cold]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:594:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:593:5 | LL | #[cold] impl S { } | ^^^^^^^ @@ -1106,7 +1106,7 @@ LL | #[cold] impl S { } = help: `#[cold]` can only be applied to functions warning: `#[link_name]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:601:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:600:1 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -1115,7 +1115,7 @@ LL | #[link_name = "1900"] = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on foreign modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:607:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:606:5 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -1124,7 +1124,7 @@ LL | #[link_name = "1900"] = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:613:17 | LL | mod inner { #![link_name="1900"] } | ^^^^^^^^^^^^^^^^^^^^ @@ -1133,7 +1133,7 @@ LL | mod inner { #![link_name="1900"] } = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:619:5 | LL | #[link_name = "1900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^ @@ -1142,7 +1142,7 @@ LL | #[link_name = "1900"] fn f() { } = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:625:5 | LL | #[link_name = "1900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^ @@ -1151,7 +1151,7 @@ LL | #[link_name = "1900"] struct S; = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:632:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:5 | LL | #[link_name = "1900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^ @@ -1160,7 +1160,7 @@ LL | #[link_name = "1900"] type T = S; = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:637:5 | LL | #[link_name = "1900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^ @@ -1169,7 +1169,7 @@ LL | #[link_name = "1900"] impl S { } = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_section]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:1 | LL | #[link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1178,7 +1178,7 @@ LL | #[link_section = "1800"] = help: `#[link_section]` can be applied to functions and statics warning: `#[link_section]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:17 | LL | mod inner { #![link_section="1800"] } | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -1187,7 +1187,7 @@ LL | mod inner { #![link_section="1800"] } = help: `#[link_section]` can be applied to functions and statics warning: `#[link_section]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:658:5 | LL | #[link_section = "1800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1196,7 +1196,7 @@ LL | #[link_section = "1800"] struct S; = help: `#[link_section]` can be applied to functions and statics warning: `#[link_section]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:664:5 | LL | #[link_section = "1800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1205,7 +1205,7 @@ LL | #[link_section = "1800"] type T = S; = help: `#[link_section]` can be applied to functions and statics warning: `#[link_section]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:670:5 | LL | #[link_section = "1800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1214,7 +1214,7 @@ LL | #[link_section = "1800"] impl S { } = help: `#[link_section]` can be applied to functions and statics warning: `#[link_section]` attribute cannot be used on traits - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:5 | LL | #[link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1223,7 +1223,7 @@ LL | #[link_section = "1800"] = help: `#[link_section]` can be applied to functions and statics warning: `#[must_use]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:1 | LL | #[must_use] | ^^^^^^^^^^^ @@ -1232,7 +1232,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to data types, functions, traits, and unions warning: `#[must_use]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:17 | LL | mod inner { #![must_use] } | ^^^^^^^^^^^^ @@ -1241,7 +1241,7 @@ LL | mod inner { #![must_use] } = help: `#[must_use]` can be applied to data types, functions, traits, and unions warning: `#[must_use]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:772:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:771:5 | LL | #[must_use] type T = S; | ^^^^^^^^^^^ @@ -1250,7 +1250,7 @@ LL | #[must_use] type T = S; = help: `#[must_use]` can be applied to data types, functions, traits, and unions warning: `#[must_use]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5 | LL | #[must_use] impl S { } | ^^^^^^^^^^^ @@ -1259,13 +1259,13 @@ LL | #[must_use] impl S { } = help: `#[must_use]` can be applied to data types, functions, traits, and unions warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:1 | LL | #[windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:1 | LL | / mod windows_subsystem { LL | | @@ -1275,67 +1275,67 @@ LL | | } | |_^ warning: the `#![windows_subsystem]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:787:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:17 | LL | mod inner { #![windows_subsystem="windows"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5 | LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:38 | LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:794:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5 | LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:794:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:38 | LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:5 | LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:38 | LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:5 | LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:38 | LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:809:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:808:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:811:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:1 | LL | / mod crate_name { LL | | @@ -1345,67 +1345,67 @@ LL | | } | |_^ warning: the `#![crate_name]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:813:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:812:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:816:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:816:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:28 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:820:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:820:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:28 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:824:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:824:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:28 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:828:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:828:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:28 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:930:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:932:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:931:1 | LL | / mod recursion_limit { LL | | @@ -1415,67 +1415,67 @@ LL | | } | |_^ warning: the `#![recursion_limit]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:934:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:936:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:936:31 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:941:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:941:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:31 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:945:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:945:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:31 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:948:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:948:31 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:954:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:956:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:955:1 | LL | / mod type_length_limit { LL | | @@ -1485,61 +1485,61 @@ LL | | } | |_^ warning: the `#![type_length_limit]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:958:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:960:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:960:33 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:965:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:965:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:33 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:969:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:968:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:969:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:968:33 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:973:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:972:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:973:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:972:33 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^ warning: `#[should_panic]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:1 | LL | #![should_panic] | ^^^^^^^^^^^^^^^^ @@ -1548,7 +1548,7 @@ LL | #![should_panic] = help: `#[should_panic]` can only be applied to functions warning: `#[ignore]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 | LL | #![ignore] | ^^^^^^^^^^ @@ -1557,7 +1557,7 @@ LL | #![ignore] = help: `#[ignore]` can only be applied to functions warning: `#[proc_macro_derive]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:63:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 | LL | #![proc_macro_derive(Test)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1566,7 +1566,7 @@ LL | #![proc_macro_derive(Test)] = help: `#[proc_macro_derive]` can only be applied to functions warning: `#[cold]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:68:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:67:1 | LL | #![cold] | ^^^^^^^^ @@ -1575,7 +1575,7 @@ LL | #![cold] = help: `#[cold]` can only be applied to functions warning: `#[link_name]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:74:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:73:1 | LL | #![link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -1584,7 +1584,7 @@ LL | #![link_name = "1900"] = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_section]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:79:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:78:1 | LL | #![link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1593,7 +1593,7 @@ LL | #![link_section = "1800"] = help: `#[link_section]` can be applied to functions and statics warning: `#[must_use]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:84:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:83:1 | LL | #![must_use] | ^^^^^^^^^^^^ diff --git a/tests/ui/macros/test-on-crate-root.rs b/tests/ui/macros/test-on-crate-root.rs index 0e0f3ec40976..88d6ec40af84 100644 --- a/tests/ui/macros/test-on-crate-root.rs +++ b/tests/ui/macros/test-on-crate-root.rs @@ -1,9 +1,10 @@ -// ICE when applying `#![test]` to the crate root, -// though only when specified with a full path. `#![test]` is not enough. -// Fixes #114920 +// Regression test for rust-lang/rust#114920 +// +// Applying `#![test]` to the crate root used to ICE, +// when referring to the attribute with full path specifically. #![core::prelude::v1::test] //~^ ERROR inner macro attributes are unstable //~| ERROR the `#[test]` attribute may only be used on a free function -fn main() {} // not important to reproduce the issue +fn main() {} diff --git a/tests/ui/macros/test-on-crate-root.stderr b/tests/ui/macros/test-on-crate-root.stderr index d706d6ae6c5f..750c510ecbca 100644 --- a/tests/ui/macros/test-on-crate-root.stderr +++ b/tests/ui/macros/test-on-crate-root.stderr @@ -1,5 +1,5 @@ error[E0658]: inner macro attributes are unstable - --> $DIR/test-on-crate-root.rs:4:4 + --> $DIR/test-on-crate-root.rs:5:4 | LL | #![core::prelude::v1::test] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | #![core::prelude::v1::test] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: the `#[test]` attribute may only be used on a free function - --> $DIR/test-on-crate-root.rs:4:1 + --> $DIR/test-on-crate-root.rs:5:1 | LL | #![core::prelude::v1::test] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions From 8d70cfecbeee900ca8f7040362dcd3532fb3b895 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 2 Dec 2025 21:18:26 +0100 Subject: [PATCH 275/585] Add a section about `rustc_clean` --- .../rustc-dev-guide/src/tests/compiletest.md | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index c2aee82bdd74..a691380234cd 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -187,8 +187,26 @@ still pass. cause an Internal Compiler Error (ICE). This is a highly specialized directive to check that the incremental cache continues to work after an ICE. -[`tests/incremental`]: https://github.com/rust-lang/rust/tree/HEAD/tests/incremental +Incremental tests may use the attribute `#[rustc_clean(...)]` attribute. This attribute compares +the fingerprint from the current compilation session with the previous one. +The first revision should never have an active `rustc_clean` attribute, since it will always be dirty. +In the default mode, it asserts that the fingerprints must be the same. +The attribute takes the following arguments: + +* `cfg=""` — checks the cfg condition ``, and only runs the check if the config condition evaluates to true. + This can be used to only run the `rustc_clean` attribute in a specific revision. +* `except=",,..."` — asserts that the query results for the listed queries must be different, + rather than the same. +* `loaded_from_disk=",,..."` — asserts that the query results for the listed queries + were actually loaded from disk (not just marked green). + This can be useful to ensure that a test is actually exercising the deserialization + logic for a particular query result. This can be combined with `except`. + +A simple example of a test using `rustc_clean` is the [hello_world test]. + +[`tests/incremental`]: https://github.com/rust-lang/rust/tree/7b42543/tests/incremental +[hello_world test]: https://github.com/rust-lang/rust/blob/646a3f8c15baefb98dc6e0c1c1ba3356db702d2a/tests/incremental/hello_world.rs ### Debuginfo tests From 876c1c9d317dfdd762a266855c2abbc0b75ae12f Mon Sep 17 00:00:00 2001 From: blyxyas Date: Tue, 2 Dec 2025 22:45:54 +0000 Subject: [PATCH 276/585] Unify my name in the mailmap --- .mailmap | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index 6bae8038c696..1118955016bd 100644 --- a/.mailmap +++ b/.mailmap @@ -43,6 +43,7 @@ Andre Bogus Andre Bogus Andre Bogus Andrea Ciliberti + Andreas Gal Andreas Jonson Andrew Gauger @@ -87,7 +88,9 @@ bjorn3 <17426603+bjorn3@users.noreply.github.com> Björn Steinbrink blake2-ppc -blyxyas Alejandra González +Alejandra González blyxyas +Alejandra González blyxyas +Alejandra González Alejandra González boolean_coercion Boris Egorov bors bors[bot] <26634292+bors[bot]@users.noreply.github.com> From 2f95ecfdd63c2ec27067d0cf3e8eb1155b872af7 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 3 Dec 2025 14:53:03 +0000 Subject: [PATCH 277/585] reviews --- compiler/rustc_hir_typeck/src/coercion.rs | 89 +++++++++++-------- .../hr_alias_normalization_leaking_vars.rs | 2 + ...hr_alias_normalization_leaking_vars.stderr | 12 +-- tests/ui/coercion/leak_check_fndef_lub.rs | 4 +- .../leak_check_fndef_lub_deadcode_breakage.rs | 4 +- ...k_check_fndef_lub_deadcode_breakage.stderr | 2 +- .../lub_closures_before_fnptr_coercion.rs | 70 --------------- 7 files changed, 61 insertions(+), 122 deletions(-) delete mode 100644 tests/ui/coercion/lub_closures_before_fnptr_coercion.rs diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6daeb917014c..99dbb1958cf6 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -113,9 +113,15 @@ fn success<'tcx>( Ok(InferOk { value: (adj, target), obligations }) } -enum LeakCheck { +/// Whether to force a leak check to occur in `Coerce::unify_raw`. +/// Note that leak checks may still occur evn with `ForceLeakCheck::No`. +/// +/// FIXME: We may want to change type relations to always leak-check +/// after exiting a binder, at which point we will always do so and +/// no longer need to handle this explicitly +enum ForceLeakCheck { Yes, - Default, + No, } impl<'f, 'tcx> Coerce<'f, 'tcx> { @@ -132,7 +138,7 @@ fn unify_raw( &self, a: Ty<'tcx>, b: Ty<'tcx>, - leak_check: LeakCheck, + leak_check: ForceLeakCheck, ) -> InferResult<'tcx, Ty<'tcx>> { debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); self.commit_if_ok(|snapshot| { @@ -176,10 +182,7 @@ fn unify_raw( // In order to actually ensure that equating the binders *does* // result in equal binders, and that the lhs is actually a supertype // of the rhs, we must perform a leak check here. - // - // FIXME: Type relations should handle leak checks - // themselves whenever a binder is entered. - if matches!(leak_check, LeakCheck::Yes) { + if matches!(leak_check, ForceLeakCheck::Yes) { self.leak_check(outer_universe, Some(snapshot))?; } @@ -188,7 +191,7 @@ fn unify_raw( } /// Unify two types (using sub or lub). - fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>, leak_check: LeakCheck) -> CoerceResult<'tcx> { + fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>, leak_check: ForceLeakCheck) -> CoerceResult<'tcx> { self.unify_raw(a, b, leak_check) .and_then(|InferOk { value: ty, obligations }| success(vec![], ty, obligations)) } @@ -200,7 +203,7 @@ fn unify_and( b: Ty<'tcx>, adjustments: impl IntoIterator>, final_adjustment: Adjust, - leak_check: LeakCheck, + leak_check: ForceLeakCheck, ) -> CoerceResult<'tcx> { self.unify_raw(a, b, leak_check).and_then(|InferOk { value: ty, obligations }| { success( @@ -231,7 +234,7 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { ); } else { // Otherwise the only coercion we can do is unification. - return self.unify(a, b, LeakCheck::Default); + return self.unify(a, b, ForceLeakCheck::No); } } @@ -265,7 +268,7 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { return self.coerce_to_raw_ptr(a, b, b_mutbl); } ty::Ref(r_b, _, mutbl_b) => { - return self.coerce_to_ref(a, b, mutbl_b, r_b); + return self.coerce_to_ref(a, b, r_b, mutbl_b); } ty::Adt(pin, _) if self.tcx.features().pin_ergonomics() @@ -301,7 +304,7 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { } _ => { // Otherwise, just use unification rules. - self.unify(a, b, LeakCheck::Default) + self.unify(a, b, ForceLeakCheck::No) } } } @@ -325,12 +328,19 @@ fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResu )); }; - let target_ty = self.use_lub.then(|| self.next_ty_var(self.cause.span)).unwrap_or(b); - - push_coerce_obligation(a, target_ty); - if self.use_lub { + let target_ty = if self.use_lub { + // When computing the lub, we create a new target + // and coerce both `a` and `b` to it. + let target_ty = self.next_ty_var(self.cause.span); + push_coerce_obligation(a, target_ty); push_coerce_obligation(b, target_ty); - } + target_ty + } else { + // When subtyping, we don't need to create a new target + // as we only coerce `a` to `b`. + push_coerce_obligation(a, b); + b + }; debug!( "coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}", @@ -340,7 +350,7 @@ fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResu } else { // One unresolved type variable: just apply subtyping, we may be able // to do something useful. - self.unify(a, b, LeakCheck::Default) + self.unify(a, b, ForceLeakCheck::No) } } @@ -355,8 +365,8 @@ fn coerce_to_ref( &self, a: Ty<'tcx>, b: Ty<'tcx>, - mutbl_b: hir::Mutability, r_b: ty::Region<'tcx>, + mutbl_b: hir::Mutability, ) -> CoerceResult<'tcx> { debug!("coerce_to_ref(a={:?}, b={:?})", a, b); debug_assert!(self.shallow_resolve(a) == a); @@ -367,7 +377,7 @@ fn coerce_to_ref( coerce_mutbls(mutbl, mutbl_b)?; (r_a, ty::TypeAndMut { ty, mutbl }) } - _ => return self.unify(a, b, LeakCheck::Default), + _ => return self.unify(a, b, ForceLeakCheck::No), }; // Look at each step in the `Deref` chain and check if @@ -418,7 +428,7 @@ fn coerce_to_ref( // the `Target` type with the pointee of `b`. This is necessary // to properly account for the differing variances of the pointees // of `&` vs `&mut` references. - match self.unify_raw(autorefd_deref_ty, b, LeakCheck::Default) { + match self.unify_raw(autorefd_deref_ty, b, ForceLeakCheck::No) { Ok(ok) => Some(ok), Err(err) => { if first_error.is_none() { @@ -473,10 +483,13 @@ fn coerce_to_ref( obligations.extend(o); obligations.extend(autoderef.into_obligations()); + assert!( + matches!(coerced_a.kind(), ty::Ref(..)), + "expected a ref type, got {:?}", + coerced_a + ); + // Now apply the autoref - let ty::Ref(..) = coerced_a.kind() else { - span_bug!(self.cause.span, "expected a ref type, got {:?}", coerced_a); - }; let mutbl = AutoBorrowMutability::new(mutbl_b, self.allow_two_phase); adjustments .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)), target: coerced_a }); @@ -615,7 +628,7 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc target, reborrow.into_iter().flat_map(|(deref, autoref)| [deref, autoref]), Adjust::Pointer(PointerCoercion::Unsize), - LeakCheck::Default, + ForceLeakCheck::No, )?; // Create an obligation for `Source: CoerceUnsized`. @@ -830,7 +843,7 @@ fn coerce_to_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { // To complete the reborrow, we need to make sure we can unify the inner types, and if so we // add the adjustments. - self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b), LeakCheck::Default) + self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b), ForceLeakCheck::No) } fn coerce_from_fn_pointer( @@ -846,9 +859,9 @@ fn coerce_from_fn_pointer( ty::FnPtr(_, b_hdr) if a_sig.safety().is_safe() && b_hdr.safety.is_unsafe() => { let a = self.tcx.safe_to_unsafe_fn_ty(a_sig); let adjust = Adjust::Pointer(PointerCoercion::UnsafeFnPointer); - self.unify_and(a, b, [], adjust, LeakCheck::Yes) + self.unify_and(a, b, [], adjust, ForceLeakCheck::Yes) } - _ => self.unify(a, b, LeakCheck::Yes), + _ => self.unify(a, b, ForceLeakCheck::Yes), } } @@ -861,20 +874,18 @@ fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { ty::FnPtr(_, b_hdr) => { let a_sig = self.sig_for_fn_def_coercion(a, Some(b_hdr.safety))?; - // FIXME: we shouldn't be normalizing here as coercion is inside of - // a probe. This can probably cause ICEs. let InferOk { value: a_sig, mut obligations } = self.at(&self.cause, self.param_env).normalize(a_sig); let a = Ty::new_fn_ptr(self.tcx, a_sig); let adjust = Adjust::Pointer(PointerCoercion::ReifyFnPointer(b_hdr.safety)); let InferOk { value, obligations: o2 } = - self.unify_and(a, b, [], adjust, LeakCheck::Yes)?; + self.unify_and(a, b, [], adjust, ForceLeakCheck::Yes)?; obligations.extend(o2); Ok(InferOk { value, obligations }) } - _ => self.unify(a, b, LeakCheck::Default), + _ => self.unify(a, b, ForceLeakCheck::No), } } @@ -893,9 +904,9 @@ fn coerce_closure_to_fn(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); let adjust = Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)); - self.unify_and(pointer_ty, b, [], adjust, LeakCheck::Default) + self.unify_and(pointer_ty, b, [], adjust, ForceLeakCheck::No) } - _ => self.unify(a, b, LeakCheck::Default), + _ => self.unify(a, b, ForceLeakCheck::No), } } @@ -912,7 +923,7 @@ fn coerce_to_raw_ptr( let (is_ref, mt_a) = match *a.kind() { ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }), ty::RawPtr(ty, mutbl) => (false, ty::TypeAndMut { ty, mutbl }), - _ => return self.unify(a, b, LeakCheck::Default), + _ => return self.unify(a, b, ForceLeakCheck::No), }; coerce_mutbls(mt_a.mutbl, mutbl_b)?; @@ -927,7 +938,7 @@ fn coerce_to_raw_ptr( b, [Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }], Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), - LeakCheck::Default, + ForceLeakCheck::No, ) } else if mt_a.mutbl != mutbl_b { self.unify_and( @@ -935,10 +946,10 @@ fn coerce_to_raw_ptr( b, [], Adjust::Pointer(PointerCoercion::MutToConstPointer), - LeakCheck::Default, + ForceLeakCheck::No, ) } else { - self.unify(a_raw, b, LeakCheck::Default) + self.unify(a_raw, b, ForceLeakCheck::No) } } } @@ -1037,7 +1048,7 @@ pub(crate) fn deref_steps_for_suggestion( // We don't ever need two-phase here since we throw out the result of the coercion. let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true); coerce.autoderef(DUMMY_SP, expr_ty).find_map(|(ty, steps)| { - self.probe(|_| coerce.unify_raw(ty, target, LeakCheck::Default)).ok().map(|_| steps) + self.probe(|_| coerce.unify_raw(ty, target, ForceLeakCheck::No)).ok().map(|_| steps) }) } diff --git a/tests/ui/coercion/hr_alias_normalization_leaking_vars.rs b/tests/ui/coercion/hr_alias_normalization_leaking_vars.rs index 43678fd876fb..71e8fdfcfa78 100644 --- a/tests/ui/coercion/hr_alias_normalization_leaking_vars.rs +++ b/tests/ui/coercion/hr_alias_normalization_leaking_vars.rs @@ -1,3 +1,5 @@ +// Regression test for #132765 +// // We have two function parameters with types: // - `&?0` // - `Box fn(>::Item)>` diff --git a/tests/ui/coercion/hr_alias_normalization_leaking_vars.stderr b/tests/ui/coercion/hr_alias_normalization_leaking_vars.stderr index 143cc6b29735..54da352c6503 100644 --- a/tests/ui/coercion/hr_alias_normalization_leaking_vars.stderr +++ b/tests/ui/coercion/hr_alias_normalization_leaking_vars.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `(): LendingIterator` is not satisfied - --> $DIR/hr_alias_normalization_leaking_vars.rs:32:31 + --> $DIR/hr_alias_normalization_leaking_vars.rs:34:31 | LL | LendingIterator::for_each(&(), f); | ------------------------- ^^^ the trait `LendingIterator` is not implemented for `()` @@ -7,13 +7,13 @@ LL | LendingIterator::for_each(&(), f); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/hr_alias_normalization_leaking_vars.rs:24:1 + --> $DIR/hr_alias_normalization_leaking_vars.rs:26:1 | LL | trait LendingIterator { | ^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/hr_alias_normalization_leaking_vars.rs:32:36 + --> $DIR/hr_alias_normalization_leaking_vars.rs:34:36 | LL | LendingIterator::for_each(&(), f); | ------------------------- ^ expected `Box`, found fn item @@ -23,19 +23,19 @@ LL | LendingIterator::for_each(&(), f); = note: expected struct `Box fn(<() as LendingIterator>::Item<'a>)>` found fn item `fn(()) {f}` note: method defined here - --> $DIR/hr_alias_normalization_leaking_vars.rs:26:8 + --> $DIR/hr_alias_normalization_leaking_vars.rs:28:8 | LL | fn for_each(&self, _f: Box)>) {} | ^^^^^^^^ --------------------------- error[E0277]: the trait bound `(): LendingIterator` is not satisfied - --> $DIR/hr_alias_normalization_leaking_vars.rs:32:36 + --> $DIR/hr_alias_normalization_leaking_vars.rs:34:36 | LL | LendingIterator::for_each(&(), f); | ^ the trait `LendingIterator` is not implemented for `()` | help: this trait has no implementations, consider adding one - --> $DIR/hr_alias_normalization_leaking_vars.rs:24:1 + --> $DIR/hr_alias_normalization_leaking_vars.rs:26:1 | LL | trait LendingIterator { | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/coercion/leak_check_fndef_lub.rs b/tests/ui/coercion/leak_check_fndef_lub.rs index b13a62db20be..2385117f5e2f 100644 --- a/tests/ui/coercion/leak_check_fndef_lub.rs +++ b/tests/ui/coercion/leak_check_fndef_lub.rs @@ -9,9 +9,7 @@ macro_rules! lub { }; } - // These don't currently lub but could in theory one day. - // If that happens this test should be adjusted to use - // fn ptrs that can't be lub'd. + // Unused parameters on FnDefs are considered invariant let lhs = foo:: fn(&'static (), &'a ())>; let rhs = foo:: fn(&'a (), &'static ())>; diff --git a/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.rs b/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.rs index e2743bf39ab6..0e79ca28654e 100644 --- a/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.rs +++ b/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.rs @@ -9,9 +9,7 @@ macro_rules! lub { }; } - // These don't currently lub but could in theory one day. - // If that happens this test should be adjusted to use - // fn ptrs that can't be lub'd. + // Unused parameters on FnDefs are considered invariant let lhs = foo:: fn(&'static (), &'a ())>; let rhs = foo:: fn(&'a (), &'static ())>; diff --git a/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.stderr b/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.stderr index 60e63ee93269..f7336d49e8ca 100644 --- a/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.stderr +++ b/tests/ui/coercion/leak_check_fndef_lub_deadcode_breakage.stderr @@ -1,5 +1,5 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/leak_check_fndef_lub_deadcode_breakage.rs:27:14 + --> $DIR/leak_check_fndef_lub_deadcode_breakage.rs:25:14 | LL | unsafe { std::mem::transmute::<_, ()>(lubbed) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/coercion/lub_closures_before_fnptr_coercion.rs b/tests/ui/coercion/lub_closures_before_fnptr_coercion.rs deleted file mode 100644 index b2c421ece570..000000000000 --- a/tests/ui/coercion/lub_closures_before_fnptr_coercion.rs +++ /dev/null @@ -1,70 +0,0 @@ -//@ check-pass -//@ compile-flags: -Znext-solver - -#![feature(type_alias_impl_trait)] - -// Test that when lubbing two equal closure tys with different -// structural identities (i.e. `PartialEq::eq` on `ty::Ty` would be false) -// we don't coerce-lub to a fnptr. -// -// Most of this test is involved jank to be able to leak the hidden type -// of an opaque with a hidden type of `Closure`. This then allows -// us to substitute `C1` and `C2` for arbitrary types in the parent scope. -// -// See: - -struct WaddupGamers(Option, U); -impl, U> Unpin for WaddupGamers {} -unsafe impl, U> Send for WaddupGamers {} -pub trait Leak { - type Unpin; - type Send; -} -impl Leak for (T,) { - type Unpin = T; - type Send = T; -} -fn define() -> impl Sized { - WaddupGamers(None::, || ()) -} - -fn require_unpin(_: T) {} -fn require_send(_: T) {} -fn mk() -> T { todo!() } - -type NameMe = impl Sized; -type NameMe2 = impl Sized; - -#[define_opaque(NameMe, NameMe2)] -fn leak() -where - T: Leak, Send = NameMe2>, -{ - require_unpin(define:: fn(&'a ())>()); - require_send(define:: fn(&'a ())>()); - - // This is the actual logic for lubbing two closures - // with syntactically different `ty::Ty`s: - - // lhs: Closure fn(&'a1 ())> - let lhs = mk::>(); - // lhs: Closure fn(&'a2 ())> - let rhs = mk::>(); - - macro_rules! lub { - ($lhs:expr, $rhs:expr) => { - if true { $lhs } else { $rhs } - }; - } - - // Lubbed to either: - // - `Closure fn(&'a ())>` - // - `fn(&())` - let lubbed = lub!(lhs, rhs); - - // Use transmute to assert the size of `lubbed` is (), i.e. - // that it is a ZST closure type not a fnptr. - unsafe { std::mem::transmute::<_, ()>(lubbed) }; -} - -fn main() {} From f9b30df1b000fd219f18a82d1fd779c35d5bae8b Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Tue, 2 Dec 2025 21:39:15 +0000 Subject: [PATCH 278/585] Add test tracking recovery for misspelled item keyword --- .../ui/parser/misspelled-keywords/recovery.rs | 23 ++++++++++++++ .../misspelled-keywords/recovery.stderr | 31 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 tests/ui/parser/misspelled-keywords/recovery.rs create mode 100644 tests/ui/parser/misspelled-keywords/recovery.stderr diff --git a/tests/ui/parser/misspelled-keywords/recovery.rs b/tests/ui/parser/misspelled-keywords/recovery.rs new file mode 100644 index 000000000000..32e6b2c049cc --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/recovery.rs @@ -0,0 +1,23 @@ +// Shows that we perform recovery on misspelled item keyword. + +#![feature(associated_type_defaults)] + +trait Animal { + Type Result = u8; + //~^ ERROR expected one of +} + +Struct Foor { + //~^ ERROR expected one of + hello: String, +} + +Const A: u8 = 10; + +Fn code() {} + +Static a: u8 = 0; + +usee a::b; + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/recovery.stderr b/tests/ui/parser/misspelled-keywords/recovery.stderr new file mode 100644 index 000000000000..cee2eed51478 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/recovery.stderr @@ -0,0 +1,31 @@ +error: expected one of `!` or `::`, found `Result` + --> $DIR/recovery.rs:6:10 + | +LL | trait Animal { + | - while parsing this item list starting here +LL | Type Result = u8; + | ^^^^^^ expected one of `!` or `::` +LL | +LL | } + | - the item list ends here + | +help: write keyword `type` in lowercase + | +LL - Type Result = u8; +LL + type Result = u8; + | + +error: expected one of `!` or `::`, found `Foor` + --> $DIR/recovery.rs:10:8 + | +LL | Struct Foor { + | ^^^^ expected one of `!` or `::` + | +help: write keyword `struct` in lowercase (notice the capitalization) + | +LL - Struct Foor { +LL + struct Foor { + | + +error: aborting due to 2 previous errors + From 9ffde14aa4c58efc359b0bfdde845bef59874ba7 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sun, 30 Nov 2025 17:37:24 +0000 Subject: [PATCH 279/585] Recover on misspelled item keyword --- compiler/rustc_parse/src/parser/item.rs | 43 ++++++----- .../parser/misspelled-keywords/assoc-type.rs | 4 +- .../misspelled-keywords/assoc-type.stderr | 13 ++-- .../ui/parser/misspelled-keywords/recovery.rs | 8 ++- .../misspelled-keywords/recovery.stderr | 71 +++++++++++++++---- tests/ui/parser/misspelled-keywords/static.rs | 5 +- .../parser/misspelled-keywords/static.stderr | 14 ++-- tests/ui/parser/misspelled-keywords/struct.rs | 4 +- .../parser/misspelled-keywords/struct.stderr | 8 +-- 9 files changed, 111 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 86991f047e46..abc0ffa87d3d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -228,8 +228,8 @@ fn parse_item_kind( body, define_opaque: None, })) - } else if self.eat_keyword(exp!(Extern)) { - if self.eat_keyword(exp!(Crate)) { + } else if self.eat_keyword_case(exp!(Extern), case) { + if self.eat_keyword_case(exp!(Crate), case) { // EXTERN CRATE self.parse_item_extern_crate()? } else { @@ -241,19 +241,17 @@ fn parse_item_kind( let safety = self.parse_safety(Case::Sensitive); self.expect_keyword(exp!(Extern))?; self.parse_item_foreign_mod(attrs, safety)? - } else if self.is_static_global() { - let safety = self.parse_safety(Case::Sensitive); + } else if let Some(safety) = self.parse_global_static_front_matter(case) { // STATIC ITEM - self.bump(); // `static` let mutability = self.parse_mutability(); self.parse_static_item(safety, mutability)? - } else if self.check_keyword(exp!(Trait)) || self.check_trait_front_matter() { + } else if self.check_keyword_case(exp!(Trait), case) || self.check_trait_front_matter() { // TRAIT ITEM self.parse_item_trait(attrs, lo)? } else if self.check_impl_frontmatter() { // IMPL ITEM self.parse_item_impl(attrs, def_())? - } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { + } else if let Const::Yes(const_span) = self.parse_constness(case) { // CONST ITEM self.recover_const_mut(const_span); self.recover_missing_kw_before_item()?; @@ -268,18 +266,18 @@ fn parse_item_kind( })) } else if self.is_reuse_path_item() { self.parse_item_delegation()? - } else if self.check_keyword(exp!(Mod)) - || self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Mod]) + } else if self.check_keyword_case(exp!(Mod), case) + || self.check_keyword_case(exp!(Unsafe), case) && self.is_keyword_ahead(1, &[kw::Mod]) { // MODULE ITEM self.parse_item_mod(attrs)? - } else if self.eat_keyword(exp!(Type)) { + } else if self.eat_keyword_case(exp!(Type), case) { // TYPE ITEM self.parse_type_alias(def_())? - } else if self.eat_keyword(exp!(Enum)) { + } else if self.eat_keyword_case(exp!(Enum), case) { // ENUM ITEM self.parse_item_enum()? - } else if self.eat_keyword(exp!(Struct)) { + } else if self.eat_keyword_case(exp!(Struct), case) { // STRUCT ITEM self.parse_item_struct()? } else if self.is_kw_followed_by_ident(kw::Union) { @@ -289,7 +287,7 @@ fn parse_item_kind( } else if self.is_builtin() { // BUILTIN# ITEM return self.parse_item_builtin(); - } else if self.eat_keyword(exp!(Macro)) { + } else if self.eat_keyword_case(exp!(Macro), case) { // MACROS 2.0 ITEM self.parse_item_decl_macro(lo)? } else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() { @@ -1324,19 +1322,28 @@ fn is_unsafe_foreign_mod(&self) -> bool { == Some(true) } - fn is_static_global(&mut self) -> bool { - if self.check_keyword(exp!(Static)) { + fn parse_global_static_front_matter(&mut self, case: Case) -> Option { + let is_global_static = if self.check_keyword_case(exp!(Static), case) { // Check if this could be a closure. !self.look_ahead(1, |token| { - if token.is_keyword(kw::Move) || token.is_keyword(kw::Use) { + if token.is_keyword_case(kw::Move, case) || token.is_keyword_case(kw::Use, case) { return true; } matches!(token.kind, token::Or | token::OrOr) }) } else { // `$qual static` - (self.check_keyword(exp!(Unsafe)) || self.check_keyword(exp!(Safe))) - && self.look_ahead(1, |t| t.is_keyword(kw::Static)) + (self.check_keyword_case(exp!(Unsafe), case) + || self.check_keyword_case(exp!(Safe), case)) + && self.look_ahead(1, |t| t.is_keyword_case(kw::Static, case)) + }; + + if is_global_static { + let safety = self.parse_safety(case); + let _ = self.eat_keyword_case(exp!(Static), case); + Some(safety) + } else { + None } } diff --git a/tests/ui/parser/misspelled-keywords/assoc-type.rs b/tests/ui/parser/misspelled-keywords/assoc-type.rs index a6b694a2abe6..31328d010ae9 100644 --- a/tests/ui/parser/misspelled-keywords/assoc-type.rs +++ b/tests/ui/parser/misspelled-keywords/assoc-type.rs @@ -1,6 +1,8 @@ +#![feature(associated_type_defaults)] + trait Animal { Type Result = u8; - //~^ ERROR expected one of + //~^ ERROR keyword `type` is written in the wrong case } fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/assoc-type.stderr b/tests/ui/parser/misspelled-keywords/assoc-type.stderr index e529b477c05b..4a777a558c72 100644 --- a/tests/ui/parser/misspelled-keywords/assoc-type.stderr +++ b/tests/ui/parser/misspelled-keywords/assoc-type.stderr @@ -1,15 +1,10 @@ -error: expected one of `!` or `::`, found `Result` - --> $DIR/assoc-type.rs:2:10 +error: keyword `type` is written in the wrong case + --> $DIR/assoc-type.rs:4:5 | -LL | trait Animal { - | - while parsing this item list starting here LL | Type Result = u8; - | ^^^^^^ expected one of `!` or `::` -LL | -LL | } - | - the item list ends here + | ^^^^ | -help: write keyword `type` in lowercase +help: write it in lowercase | LL - Type Result = u8; LL + type Result = u8; diff --git a/tests/ui/parser/misspelled-keywords/recovery.rs b/tests/ui/parser/misspelled-keywords/recovery.rs index 32e6b2c049cc..f56709c0ce97 100644 --- a/tests/ui/parser/misspelled-keywords/recovery.rs +++ b/tests/ui/parser/misspelled-keywords/recovery.rs @@ -4,20 +4,24 @@ trait Animal { Type Result = u8; - //~^ ERROR expected one of + //~^ ERROR keyword `type` is written in the wrong case } Struct Foor { - //~^ ERROR expected one of + //~^ ERROR keyword `struct` is written in the wrong case hello: String, } Const A: u8 = 10; +//~^ ERROR keyword `const` is written in the wrong case Fn code() {} +//~^ ERROR keyword `fn` is written in the wrong case Static a: u8 = 0; +//~^ ERROR keyword `static` is written in the wrong case usee a::b; +//~^ ERROR expected one of fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/recovery.stderr b/tests/ui/parser/misspelled-keywords/recovery.stderr index cee2eed51478..6c2e8261e971 100644 --- a/tests/ui/parser/misspelled-keywords/recovery.stderr +++ b/tests/ui/parser/misspelled-keywords/recovery.stderr @@ -1,31 +1,74 @@ -error: expected one of `!` or `::`, found `Result` - --> $DIR/recovery.rs:6:10 +error: keyword `type` is written in the wrong case + --> $DIR/recovery.rs:6:5 | -LL | trait Animal { - | - while parsing this item list starting here LL | Type Result = u8; - | ^^^^^^ expected one of `!` or `::` -LL | -LL | } - | - the item list ends here + | ^^^^ | -help: write keyword `type` in lowercase +help: write it in lowercase | LL - Type Result = u8; LL + type Result = u8; | -error: expected one of `!` or `::`, found `Foor` - --> $DIR/recovery.rs:10:8 +error: keyword `struct` is written in the wrong case + --> $DIR/recovery.rs:10:1 | LL | Struct Foor { - | ^^^^ expected one of `!` or `::` + | ^^^^^^ | -help: write keyword `struct` in lowercase (notice the capitalization) +help: write it in lowercase (notice the capitalization) | LL - Struct Foor { LL + struct Foor { | -error: aborting due to 2 previous errors +error: keyword `const` is written in the wrong case + --> $DIR/recovery.rs:15:1 + | +LL | Const A: u8 = 10; + | ^^^^^ + | +help: write it in lowercase (notice the capitalization) + | +LL - Const A: u8 = 10; +LL + const A: u8 = 10; + | + +error: keyword `fn` is written in the wrong case + --> $DIR/recovery.rs:18:1 + | +LL | Fn code() {} + | ^^ + | +help: write it in lowercase (notice the capitalization) + | +LL - Fn code() {} +LL + fn code() {} + | + +error: keyword `static` is written in the wrong case + --> $DIR/recovery.rs:21:1 + | +LL | Static a: u8 = 0; + | ^^^^^^ + | +help: write it in lowercase (notice the capitalization) + | +LL - Static a: u8 = 0; +LL + static a: u8 = 0; + | + +error: expected one of `!` or `::`, found `a` + --> $DIR/recovery.rs:24:6 + | +LL | usee a::b; + | ^ expected one of `!` or `::` + | +help: there is a keyword `use` with a similar name + | +LL - usee a::b; +LL + use a::b; + | + +error: aborting due to 6 previous errors diff --git a/tests/ui/parser/misspelled-keywords/static.rs b/tests/ui/parser/misspelled-keywords/static.rs index 240f4f52c8dc..29dd21b6b56c 100644 --- a/tests/ui/parser/misspelled-keywords/static.rs +++ b/tests/ui/parser/misspelled-keywords/static.rs @@ -1,4 +1,3 @@ -Static a = 0; -//~^ ERROR expected one of - +Static a: u32 = 0; +//~^ ERROR keyword `static` is written in the wrong case fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/static.stderr b/tests/ui/parser/misspelled-keywords/static.stderr index 0df40bcdc33b..75c34f483950 100644 --- a/tests/ui/parser/misspelled-keywords/static.stderr +++ b/tests/ui/parser/misspelled-keywords/static.stderr @@ -1,13 +1,13 @@ -error: expected one of `!` or `::`, found `a` - --> $DIR/static.rs:1:8 +error: keyword `static` is written in the wrong case + --> $DIR/static.rs:1:1 | -LL | Static a = 0; - | ^ expected one of `!` or `::` +LL | Static a: u32 = 0; + | ^^^^^^ | -help: write keyword `static` in lowercase (notice the capitalization) +help: write it in lowercase (notice the capitalization) | -LL - Static a = 0; -LL + static a = 0; +LL - Static a: u32 = 0; +LL + static a: u32 = 0; | error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/struct.rs b/tests/ui/parser/misspelled-keywords/struct.rs index 0f64dec6f56b..5c76ce7622f9 100644 --- a/tests/ui/parser/misspelled-keywords/struct.rs +++ b/tests/ui/parser/misspelled-keywords/struct.rs @@ -1,4 +1,6 @@ Struct Foor { -//~^ ERROR expected one of + //~^ ERROR keyword `struct` is written in the wrong case hello: String, } + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/struct.stderr b/tests/ui/parser/misspelled-keywords/struct.stderr index af8614ef14b7..a6709111d4ae 100644 --- a/tests/ui/parser/misspelled-keywords/struct.stderr +++ b/tests/ui/parser/misspelled-keywords/struct.stderr @@ -1,10 +1,10 @@ -error: expected one of `!` or `::`, found `Foor` - --> $DIR/struct.rs:1:8 +error: keyword `struct` is written in the wrong case + --> $DIR/struct.rs:1:1 | LL | Struct Foor { - | ^^^^ expected one of `!` or `::` + | ^^^^^^ | -help: write keyword `struct` in lowercase (notice the capitalization) +help: write it in lowercase (notice the capitalization) | LL - Struct Foor { LL + struct Foor { From b54b2885189c6f33b0552b85bf4248919dd79ab1 Mon Sep 17 00:00:00 2001 From: Paul Murphy Date: Wed, 3 Dec 2025 11:15:20 -0600 Subject: [PATCH 280/585] Allow PowerPC spe_acc as clobber-only register This register is only supported on the *powerpc*spe targets. It is only recognized by LLVM. gcc does not accept this as a clobber, nor does it support these targets. This is a volatile register, thus it is included with clobber_abi. --- compiler/rustc_codegen_gcc/src/asm.rs | 23 +++++++++++++------ compiler/rustc_codegen_llvm/src/asm.rs | 6 +++-- compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/asm/mod.rs | 3 +++ compiler/rustc_target/src/asm/powerpc.rs | 5 +++- .../asm-experimental-arch.md | 4 ++++ tests/codegen-llvm/asm/powerpc-clobbers.rs | 16 ++++++------- 7 files changed, 40 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index f237861b1595..ceb3dd3ffedf 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -209,10 +209,16 @@ fn codegen_inline_asm( } ("r", dummy_output_type(self.cx, reg.reg_class())) } else { - // `clobber_abi` can add lots of clobbers that are not supported by the target, - // such as AVX-512 registers, so we just ignore unsupported registers - let is_target_supported = - reg.reg_class().supported_types(asm_arch, true).iter().any( + let is_target_supported = match reg.reg_class() { + // `clobber_abi` clobbers spe_acc on all PowerPC targets. This + // register is unique to the powerpc*spe target, and the target + // is not supported by gcc. Ignore it. + InlineAsmRegClass::PowerPC( + PowerPCInlineAsmRegClass::spe_acc, + ) => false, + // `clobber_abi` can add lots of clobbers that are not supported by the target, + // such as AVX-512 registers, so we just ignore unsupported registers + x => x.supported_types(asm_arch, true).iter().any( |&(_, feature)| { if let Some(feature) = feature { self.tcx @@ -222,7 +228,8 @@ fn codegen_inline_asm( true // Register class is unconditionally supported } }, - ); + ), + }; if is_target_supported && !clobbers.contains(®_name) { clobbers.push(reg_name); @@ -710,7 +717,8 @@ fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str { PowerPCInlineAsmRegClass::cr | PowerPCInlineAsmRegClass::ctr | PowerPCInlineAsmRegClass::lr - | PowerPCInlineAsmRegClass::xer, + | PowerPCInlineAsmRegClass::xer + | PowerPCInlineAsmRegClass::spe_acc, ) => { unreachable!("clobber-only") } @@ -793,7 +801,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl PowerPCInlineAsmRegClass::cr | PowerPCInlineAsmRegClass::ctr | PowerPCInlineAsmRegClass::lr - | PowerPCInlineAsmRegClass::xer, + | PowerPCInlineAsmRegClass::xer + | PowerPCInlineAsmRegClass::spe_acc, ) => { unreachable!("clobber-only") } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 8cd4bdc37278..ee1b6d45e149 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -663,7 +663,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> PowerPCInlineAsmRegClass::cr | PowerPCInlineAsmRegClass::ctr | PowerPCInlineAsmRegClass::lr - | PowerPCInlineAsmRegClass::xer, + | PowerPCInlineAsmRegClass::xer + | PowerPCInlineAsmRegClass::spe_acc, ) => { unreachable!("clobber-only") } @@ -843,7 +844,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' PowerPCInlineAsmRegClass::cr | PowerPCInlineAsmRegClass::ctr | PowerPCInlineAsmRegClass::lr - | PowerPCInlineAsmRegClass::xer, + | PowerPCInlineAsmRegClass::xer + | PowerPCInlineAsmRegClass::spe_acc, ) => { unreachable!("clobber-only") } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f2b13dad1fd9..7e513160de0c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2143,6 +2143,7 @@ sparc, sparc64, sparc_target_feature, + spe_acc, specialization, speed, spirv, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 57d9cdad454a..c6d22a51774c 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -1271,6 +1271,9 @@ macro_rules! clobbered_regs { ctr, lr, xer, + + // These are only supported on PowerPC SPE targets. + spe_acc, } }, InlineAsmClobberAbi::S390x => clobbered_regs! { diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index e72984057a82..4fbe8adcbc61 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -17,6 +17,7 @@ ctr, lr, xer, + spe_acc, } } @@ -63,7 +64,7 @@ pub fn supported_types( Self::vsreg => types! { vsx: F32, F64, VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); }, - Self::cr | Self::ctr | Self::lr | Self::xer => &[], + Self::cr | Self::ctr | Self::lr | Self::xer | Self::spe_acc => &[], } } } @@ -285,6 +286,7 @@ fn reserved_v20to31( ctr: ctr = ["ctr"], lr: lr = ["lr"], xer: xer = ["xer"], + spe_acc: spe_acc = ["spe_acc"], #error = ["r1", "1", "sp"] => "the stack pointer cannot be used as an operand for inline asm", #error = ["r2", "2"] => @@ -342,6 +344,7 @@ macro_rules! do_emit { (ctr, "ctr"); (lr, "lr"); (xer, "xer"); + (spe_acc, "spe_acc"); } } diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index c96605fb7944..77d43315a6d4 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -40,6 +40,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | PowerPC | `ctr` | `ctr` | Only clobbers | | PowerPC | `lr` | `lr` | Only clobbers | | PowerPC | `xer` | `xer` | Only clobbers | +| PowerPC | `spe_acc` | `spe_acc` | Only clobbers | | wasm32 | `local` | None\* | `r` | | BPF | `reg` | `r[0-10]` | `r` | | BPF | `wreg` | `w[0-10]` | `w` | @@ -63,6 +64,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect > - WebAssembly doesn't have registers, so named registers are not supported. > > - r29 is reserved only on 32 bit PowerPC targets. +> +> - spe_acc is only available on PowerPC SPE targets. # Register class supported types @@ -87,6 +90,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | PowerPC | `ctr` | N/A | Only clobbers | | PowerPC | `lr` | N/A | Only clobbers | | PowerPC | `xer` | N/A | Only clobbers | +| PowerPC | `spe_acc` | N/A | Only clobbers | | wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` | | BPF | `reg` | None | `i8` `i16` `i32` `i64` | | BPF | `wreg` | `alu32` | `i8` `i16` `i32` | diff --git a/tests/codegen-llvm/asm/powerpc-clobbers.rs b/tests/codegen-llvm/asm/powerpc-clobbers.rs index ee52727e3c03..6abf82cb0f4b 100644 --- a/tests/codegen-llvm/asm/powerpc-clobbers.rs +++ b/tests/codegen-llvm/asm/powerpc-clobbers.rs @@ -69,10 +69,10 @@ pub unsafe fn vs32_clobber() { // Output format depends on the availability of altivec and vsx // CHECK-LABEL: @clobber_abi -// powerpc: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() -// powerpc64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() -// powerpc64le: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() -// aix64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() +// powerpc: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() +// powerpc64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() +// powerpc64le: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() +// aix64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() #[no_mangle] pub unsafe fn clobber_abi() { asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); @@ -104,10 +104,10 @@ pub unsafe fn clobber_preservesflags() { // Output format depends on the availability of altivec and vsx // CHECK-LABEL: @clobber_abi_no_preserves_flags #[no_mangle] -// powerpc: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() -// powerpc64: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() -// powerpc64le: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() -// aix64: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() +// powerpc: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() +// powerpc64: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() +// powerpc64le: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() +// aix64: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() pub unsafe fn clobber_abi_no_preserves_flags() { // Use a nop to prevent aliasing of identical functions here. asm!("nop", clobber_abi("C"), options(nostack, nomem)); From 7e7d72437368996f7f4cc93fb7eec64174ff9e16 Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Wed, 3 Dec 2025 20:22:54 +0200 Subject: [PATCH 281/585] Implement benchmarks for uN::{gather,scatter}_bits --- library/coretests/benches/lib.rs | 1 + library/coretests/benches/num/int_bits/mod.rs | 62 +++++++++++++++++++ library/coretests/benches/num/mod.rs | 1 + 3 files changed, 64 insertions(+) create mode 100644 library/coretests/benches/num/int_bits/mod.rs diff --git a/library/coretests/benches/lib.rs b/library/coretests/benches/lib.rs index 32d15c386cb1..150b9b33f457 100644 --- a/library/coretests/benches/lib.rs +++ b/library/coretests/benches/lib.rs @@ -8,6 +8,7 @@ #![feature(iter_array_chunks)] #![feature(iter_next_chunk)] #![feature(iter_advance_by)] +#![feature(uint_gather_scatter_bits)] extern crate test; diff --git a/library/coretests/benches/num/int_bits/mod.rs b/library/coretests/benches/num/int_bits/mod.rs new file mode 100644 index 000000000000..43531b0b5de9 --- /dev/null +++ b/library/coretests/benches/num/int_bits/mod.rs @@ -0,0 +1,62 @@ +const BYTES: usize = 1 << 10; + +macro_rules! bench_template { + ($op:path, $name:ident, $mask:expr) => { + #[bench] + fn $name(bench: &mut ::test::Bencher) { + use ::rand::Rng; + let mut rng = crate::bench_rng(); + let mut dst = vec![0; ITERATIONS]; + let src1: Vec = (0..ITERATIONS).map(|_| rng.random_range(0..=U::MAX)).collect(); + let mut src2: Vec = (0..ITERATIONS).map(|_| rng.random_range(0..=U::MAX)).collect(); + // Fix the loop invariant mask + src2[0] = U::MAX / 3; + let dst = dst.first_chunk_mut().unwrap(); + let src1 = src1.first_chunk().unwrap(); + let src2 = src2.first_chunk().unwrap(); + + #[allow(unused)] + fn vectored(dst: &mut Data, src1: &Data, src2: &Data) { + let mask = $mask; + for k in 0..ITERATIONS { + dst[k] = $op(src1[k], mask(src2, k)); + } + } + let f: fn(&mut Data, &Data, &Data) = vectored; + let f = ::test::black_box(f); + + bench.iter(|| { + f(dst, src1, src2); + }); + } + }; +} + +macro_rules! bench_type { + ($U:ident) => { + mod $U { + type U = $U; + const ITERATIONS: usize = super::BYTES / size_of::(); + type Data = [U; ITERATIONS]; + bench_mask_kind!(constant, |_, _| const { U::MAX / 3 }); + bench_mask_kind!(invariant, |src: &Data, _| src[0]); + bench_mask_kind!(variable, |src: &Data, k| src[k]); + } + }; +} + +macro_rules! bench_mask_kind { + ($mask_kind:ident, $mask:expr) => { + mod $mask_kind { + use super::{Data, ITERATIONS, U}; + bench_template!(U::gather_bits, gather_bits, $mask); + bench_template!(U::scatter_bits, scatter_bits, $mask); + } + }; +} + +bench_type!(u8); +bench_type!(u16); +bench_type!(u32); +bench_type!(u64); +bench_type!(u128); diff --git a/library/coretests/benches/num/mod.rs b/library/coretests/benches/num/mod.rs index b36100e59a97..a131b3454f0c 100644 --- a/library/coretests/benches/num/mod.rs +++ b/library/coretests/benches/num/mod.rs @@ -1,5 +1,6 @@ mod dec2flt; mod flt2dec; +mod int_bits; mod int_log; mod int_pow; mod int_sqrt; From fce8552f820f79c2ebd1f9d09c6d6b459bddc22a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 3 Dec 2025 18:44:09 +0100 Subject: [PATCH 282/585] Use branch name instead of HEAD when unshallowing --- src/ci/scripts/checkout-submodules.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/scripts/checkout-submodules.sh b/src/ci/scripts/checkout-submodules.sh index 5a422afc42b4..e38e20d47c3d 100755 --- a/src/ci/scripts/checkout-submodules.sh +++ b/src/ci/scripts/checkout-submodules.sh @@ -17,7 +17,7 @@ ci_dir=$(cd $(dirname $0) && pwd)/.. # On the beta channel we'll be automatically calculating the prerelease version # via the git history, so unshallow our shallow clone from CI. if [ "$(releaseChannel)" = "beta" ]; then - git fetch origin --unshallow beta HEAD + git fetch origin --unshallow beta main fi function fetch_github_commit_archive { From d633b668a042aec78f9dd1097ae9dc749475ed16 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Dec 2025 19:44:34 +0100 Subject: [PATCH 283/585] update miri comments regarding pow non-determinism --- src/tools/miri/src/math.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index 50472ed3638e..f9ff4c84c129 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -272,8 +272,9 @@ pub(crate) fn fixed_float_value( ("pow", [base, exp]) if *base == one => { let rng = this.machine.rng.get_mut(); // SNaN exponents get special treatment: they might return 1, or a NaN. + // This is non-deterministic because LLVM can treat SNaN as QNaN, and because + // implementation behavior differs between glibc and musl. let return_nan = exp.is_signaling() && this.machine.float_nondet && rng.random(); - // Handle both the musl and glibc cases non-deterministically. if return_nan { this.generate_nan(args) } else { one } } @@ -281,8 +282,9 @@ pub(crate) fn fixed_float_value( ("pow", [base, exp]) if exp.is_zero() => { let rng = this.machine.rng.get_mut(); // SNaN bases get special treatment: they might return 1, or a NaN. + // This is non-deterministic because LLVM can treat SNaN as QNaN, and because + // implementation behavior differs between glibc and musl. let return_nan = base.is_signaling() && this.machine.float_nondet && rng.random(); - // Handle both the musl and glibc cases non-deterministically. if return_nan { this.generate_nan(args) } else { one } } @@ -306,10 +308,9 @@ pub(crate) fn fixed_powi_value( 0 => { let one = IeeeFloat::::one(); let rng = ecx.machine.rng.get_mut(); - let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling(); - // For SNaN treatment, we are consistent with `powf`above. - // (We wouldn't have two, unlike powf all implementations seem to agree for powi, - // but for now we are maximally conservative.) + // SNaN bases get special treatment: they might return 1, or a NaN. + // This is non-deterministic because LLVM can treat SNaN as QNaN. + let return_nan = base.is_signaling() && ecx.machine.float_nondet && rng.random(); Some(if return_nan { ecx.generate_nan(&[base]) } else { one }) } From c1155985065bf816b50f299bca874497957839b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 3 Dec 2025 20:44:33 +0100 Subject: [PATCH 284/585] Apply the `bors` environment also to the `outcome` job To fix passing the toolstate token to `publish_toolstate.sh`. --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e683758d6df..05aa600e649e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -313,6 +313,7 @@ jobs: needs: [ calculate_matrix, job ] # !cancelled() executes the job regardless of whether the previous jobs passed or failed if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }} + environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto')) && 'bors') || '' }} steps: - name: checkout the source code uses: actions/checkout@v5 From 00f3a35caa63bf9b698f871174498543152df004 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 1 Dec 2025 18:28:41 +0100 Subject: [PATCH 285/585] add a tidy test --- src/tools/tidy/src/alphabetical/tests.rs | 59 ++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/tools/tidy/src/alphabetical/tests.rs b/src/tools/tidy/src/alphabetical/tests.rs index 3e0dd798ab9d..5bfb37a098fc 100644 --- a/src/tools/tidy/src/alphabetical/tests.rs +++ b/src/tools/tidy/src/alphabetical/tests.rs @@ -337,3 +337,62 @@ fn test_numeric_bad() { "; bad(lines, "bad:3: line not in alphabetical order"); } + +#[test] +fn multiline() { + let lines = "\ + tidy-alphabetical-start + (b, + a); + ( + b, + a + ) + tidy-alphabetical-end + "; + good(lines); + + let lines = "\ + tidy-alphabetical-start + ( + b, + a + ) + (b, + a); + tidy-alphabetical-end + "; + good(lines); + + let lines = "\ + tidy-alphabetical-start + (c, + a); + ( + b, + a + ) + tidy-alphabetical-end + "; + bad(lines, "bad:5: line not in alphabetical order"); + + let lines = "\ + tidy-alphabetical-start + ( + c, + a + ) + (b, + a); + tidy-alphabetical-end + "; + bad(lines, "bad:6: line not in alphabetical order"); + + let lines = "\ + force_unwind_tables: Option = (None, parse_opt_bool, [TRACKED], + 'force use of unwind tables'), + incremental: Option = (None, parse_opt_string, [UNTRACKED], + 'enable incremental compilation'), + "; + good(lines); +} From cdc977d6ec8ced80199b562bc5443eba2af5cbaa Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sat, 16 Aug 2025 14:26:34 +0200 Subject: [PATCH 286/585] refactor tidy alphabetical lint This slightly changes alphabetical lint semantics... specifically if an "item" is multiline (when the next line does not have the same indentation) we now consider all lines (ignoring starting whitespace) for ordering, not just the first one. --- src/tools/tidy/src/alphabetical.rs | 315 ++++++++++++++++++++--------- 1 file changed, 220 insertions(+), 95 deletions(-) diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs index 3845e2269e9b..6a1e777d9f2a 100644 --- a/src/tools/tidy/src/alphabetical.rs +++ b/src/tools/tidy/src/alphabetical.rs @@ -9,19 +9,33 @@ //! // tidy-alphabetical-end //! ``` //! -//! The following lines are ignored: -//! - Empty lines -//! - Lines that are indented with more or less spaces than the first line -//! - Lines starting with `//`, `#` (except those starting with `#!`), `)`, `]`, `}` if the comment -//! has the same indentation as the first line -//! - Lines starting with a closing delimiter (`)`, `[`, `}`) are ignored. +//! Empty lines and lines starting (ignoring spaces) with `//` or `#` (except those starting with +//! `#!`) are considered comments are are sorted together with the next line (but do not affect +//! sorting). //! -//! If a line ends with an opening delimiter, we effectively join the following line to it before -//! checking it. E.g. `foo(\nbar)` is treated like `foo(bar)`. +//! If the following lines have higher indentation we effectively join them with the current line +//! before comparing it. If the next line with the same indentation starts (ignoring spaces) with +//! a closing delimiter (`)`, `[`, `}`) it is joined as well. +//! +//! E.g. +//! +//! ```rust,ignore ilustrative example for sorting mentioning non-existent functions +//! foo(a, +//! b); +//! bar( +//! a, +//! b +//! ); +//! // are treated for sorting purposes as +//! foo(a, b); +//! bar(a, b); +//! ``` use std::cmp::Ordering; -use std::fmt::Display; +use std::fs; +use std::io::{Seek, Write}; use std::iter::Peekable; +use std::ops::{Range, RangeBounds}; use std::path::Path; use crate::diagnostics::{CheckId, RunningCheck, TidyCtx}; @@ -38,94 +52,190 @@ fn is_close_bracket(c: char) -> bool { matches!(c, ')' | ']' | '}') } +fn is_empty_or_comment(line: &&str) -> bool { + let trimmed_line = line.trim_start_matches(' ').trim_end_matches('\n'); + + trimmed_line.is_empty() + || trimmed_line.starts_with("//") + || (trimmed_line.starts_with('#') && !trimmed_line.starts_with("#!")) +} + const START_MARKER: &str = "tidy-alphabetical-start"; const END_MARKER: &str = "tidy-alphabetical-end"; -fn check_section<'a>( - file: impl Display, - lines: impl Iterator, - check: &mut RunningCheck, -) { - let mut prev_line = String::new(); - let mut first_indent = None; - let mut in_split_line = None; - - for (idx, line) in lines { - if line.is_empty() { - continue; - } - - if line.contains(START_MARKER) { - check.error(format!( - "{file}:{} found `{START_MARKER}` expecting `{END_MARKER}`", - idx + 1 - )); - return; - } - - if line.contains(END_MARKER) { - return; - } - - let indent = first_indent.unwrap_or_else(|| { - let indent = indentation(line); - first_indent = Some(indent); - indent - }); - - let line = if let Some(prev_split_line) = in_split_line { - // Join the split lines. - in_split_line = None; - format!("{prev_split_line}{}", line.trim_start()) - } else { - line.to_string() - }; - - if indentation(&line) != indent { - continue; - } - - let trimmed_line = line.trim_start_matches(' '); - - if trimmed_line.starts_with("//") - || (trimmed_line.starts_with('#') && !trimmed_line.starts_with("#!")) - || trimmed_line.starts_with(is_close_bracket) - { - continue; - } - - if line.trim_end().ends_with('(') { - in_split_line = Some(line); - continue; - } - - let prev_line_trimmed_lowercase = prev_line.trim_start_matches(' '); - - if version_sort(trimmed_line, prev_line_trimmed_lowercase).is_lt() { - check.error(format!("{file}:{}: line not in alphabetical order", idx + 1)); - } - - prev_line = line; +/// Given contents of a section that is enclosed between [`START_MARKER`] and [`END_MARKER`], sorts +/// them according to the rules described at the top of the module. +fn sort_section(section: &str) -> String { + /// A sortable item + struct Item { + /// Full contents including comments and whitespace + full: String, + /// Trimmed contents for sorting + trimmed: String, } - check.error(format!("{file}: reached end of file expecting `{END_MARKER}`")); -} + let mut items = Vec::new(); + let mut lines = section.split_inclusive('\n').peekable(); -fn check_lines<'a>( - file: &impl Display, - mut lines: impl Iterator, - check: &mut RunningCheck, -) { - while let Some((idx, line)) = lines.next() { - if line.contains(END_MARKER) { - check.error(format!( - "{file}:{} found `{END_MARKER}` expecting `{START_MARKER}`", - idx + 1 - )); + let end_comments = loop { + let mut full = String::new(); + let mut trimmed = String::new(); + + while let Some(comment) = lines.next_if(is_empty_or_comment) { + full.push_str(comment); } - if line.contains(START_MARKER) { - check_section(file, &mut lines, check); + let Some(line) = lines.next() else { + // remember comments at the end of a block + break full; + }; + + let mut push = |line| { + full.push_str(line); + trimmed.push_str(line.trim_start_matches(' ').trim_end_matches('\n')) + }; + + push(line); + + let indent = indentation(line); + let mut multiline = false; + + // If the item is split between multiple lines... + while let Some(more_indented) = + lines.next_if(|&line: &&_| indent < indentation(line) || line == "\n") + { + multiline = true; + push(more_indented); + } + + if multiline + && let Some(indented) = + // Only append next indented line if it looks like a closing bracket. + // Otherwise we incorrectly merge code like this (can be seen in + // compiler/rustc_session/src/options.rs): + // + // force_unwind_tables: Option = (None, parse_opt_bool, [TRACKED], + // "force use of unwind tables"), + // incremental: Option = (None, parse_opt_string, [UNTRACKED], + // "enable incremental compilation"), + lines.next_if(|l| { + indentation(l) == indent + && l.trim_start_matches(' ').starts_with(is_close_bracket) + }) + { + push(indented); + } + + items.push(Item { full, trimmed }); + }; + + items.sort_by(|a, b| version_sort(&a.trimmed, &b.trimmed)); + items.into_iter().map(|l| l.full).chain([end_comments]).collect() +} + +fn check_lines<'a>(path: &Path, content: &'a str, tidy_ctx: &TidyCtx, check: &mut RunningCheck) { + let mut offset = 0; + + loop { + let rest = &content[offset..]; + let start = rest.find(START_MARKER); + let end = rest.find(END_MARKER); + + match (start, end) { + // error handling + + // end before start + (Some(start), Some(end)) if end < start => { + check.error(format!( + "{path}:{line_number} found `{END_MARKER}` expecting `{START_MARKER}`", + path = path.display(), + line_number = content[..offset + end].lines().count(), + )); + break; + } + + // end without a start + (None, Some(end)) => { + check.error(format!( + "{path}:{line_number} found `{END_MARKER}` expecting `{START_MARKER}`", + path = path.display(), + line_number = content[..offset + end].lines().count(), + )); + break; + } + + // start without an end + (Some(start), None) => { + check.error(format!( + "{path}:{line_number} `{START_MARKER}` without a matching `{END_MARKER}`", + path = path.display(), + line_number = content[..offset + start].lines().count(), + )); + break; + } + + // a second start in between start/end pair + (Some(start), Some(end)) + if rest[start + START_MARKER.len()..end].contains(START_MARKER) => + { + check.error(format!( + "{path}:{line_number} found `{START_MARKER}` expecting `{END_MARKER}`", + path = path.display(), + line_number = content[..offset + + sub_find(rest, start + START_MARKER.len()..end, START_MARKER) + .unwrap() + .start] + .lines() + .count() + )); + break; + } + + // happy happy path :3 + (Some(start), Some(end)) => { + assert!(start <= end); + + // "...␤// tidy-alphabetical-start␤...␤// tidy-alphabetical-end␤..." + // start_nl_end --^ ^-- end_nl_start ^-- end_nl_end + + // Position after the newline after start marker + let start_nl_end = sub_find(rest, start + START_MARKER.len().., "\n").unwrap().end; + + // Position before the new line before the end marker + let end_nl_start = rest[..end].rfind('\n').unwrap(); + + // Position after the newline after end marker + let end_nl_end = sub_find(rest, end + END_MARKER.len().., "\n") + .map(|r| r.end) + .unwrap_or(content.len() - offset); + + let section = &rest[start_nl_end..=end_nl_start]; + let sorted = sort_section(section); + + // oh nyooo :( + if sorted != section { + let base_line_number = content[..offset + start_nl_end].lines().count(); + let line_offset = sorted + .lines() + .zip(section.lines()) + .enumerate() + .find(|(_, (a, b))| a != b) + .unwrap() + .0; + let line_number = base_line_number + line_offset; + + check.error(format!( + "{path}:{line_number}: line not in alphabetical order (tip: use --bless to sort this list)", + path = path.display(), + )); + } + + // Start the next search after the end section + offset += end_nl_end; + } + + // No more alphabetical lists, yay :3 + (None, None) => break, } } } @@ -133,13 +243,14 @@ fn check_lines<'a>( pub fn check(path: &Path, tidy_ctx: TidyCtx) { let mut check = tidy_ctx.start_check(CheckId::new("alphabetical").path(path)); - let skip = - |path: &_, _is_dir| filter_dirs(path) || path.ends_with("tidy/src/alphabetical/tests.rs"); + let skip = |path: &_, _is_dir| { + filter_dirs(path) + || path.ends_with("tidy/src/alphabetical.rs") + || path.ends_with("tidy/src/alphabetical/tests.rs") + }; - walk(path, skip, &mut |entry, contents| { - let file = &entry.path().display(); - let lines = contents.lines().enumerate(); - check_lines(file, lines, &mut check) + walk(path, skip, &mut |entry, content| { + check_lines(entry.path(), content, &tidy_ctx, &mut check) }); } @@ -195,3 +306,17 @@ fn version_sort(a: &str, b: &str) -> Ordering { it1.next().cmp(&it2.next()) } + +/// Finds `pat` in `s[range]` and returns a range such that `s[ret] == pat`. +fn sub_find(s: &str, range: impl RangeBounds, pat: &str) -> Option> { + s[(range.start_bound().cloned(), range.end_bound().cloned())] + .find(pat) + .map(|pos| { + pos + match range.start_bound().cloned() { + std::ops::Bound::Included(x) => x, + std::ops::Bound::Excluded(x) => x + 1, + std::ops::Bound::Unbounded => 0, + } + }) + .map(|pos| pos..pos + pat.len()) +} From 4e9c504cbff017030b4df356f619c1ad2a50154c Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sat, 16 Aug 2025 14:26:34 +0200 Subject: [PATCH 287/585] implement tidy bless for alphabetical blocks --- Cargo.lock | 1 + src/tools/tidy/Cargo.toml | 1 + src/tools/tidy/src/alphabetical.rs | 42 +++++++++++++++++++++--------- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2cc2e094e9f9..46de7c331258 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5615,6 +5615,7 @@ dependencies = [ "semver", "serde", "similar", + "tempfile", "termcolor", "toml 0.7.8", "walkdir", diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index c1f27de7ed4a..47b59543c59c 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -18,6 +18,7 @@ rustc-hash = "2.0.0" fluent-syntax = "0.12" similar = "2.5.0" toml = "0.7.8" +tempfile = "3.15.0" [features] build-metrics = ["dep:serde"] diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs index 6a1e777d9f2a..4ef1775d4bed 100644 --- a/src/tools/tidy/src/alphabetical.rs +++ b/src/tools/tidy/src/alphabetical.rs @@ -214,20 +214,36 @@ fn check_lines<'a>(path: &Path, content: &'a str, tidy_ctx: &TidyCtx, check: &mu // oh nyooo :( if sorted != section { - let base_line_number = content[..offset + start_nl_end].lines().count(); - let line_offset = sorted - .lines() - .zip(section.lines()) - .enumerate() - .find(|(_, (a, b))| a != b) - .unwrap() - .0; - let line_number = base_line_number + line_offset; + if !tidy_ctx.is_bless_enabled() { + let base_line_number = content[..offset + start_nl_end].lines().count(); + let line_offset = sorted + .lines() + .zip(section.lines()) + .enumerate() + .find(|(_, (a, b))| a != b) + .unwrap() + .0; + let line_number = base_line_number + line_offset; - check.error(format!( - "{path}:{line_number}: line not in alphabetical order (tip: use --bless to sort this list)", - path = path.display(), - )); + check.error(format!( + "{path}:{line_number}: line not in alphabetical order (tip: use --bless to sort this list)", + path = path.display(), + )); + } else { + // Use atomic rename as to not corrupt the file upon crashes/ctrl+c + let mut tempfile = + tempfile::Builder::new().tempfile_in(path.parent().unwrap()).unwrap(); + + fs::copy(path, tempfile.path()).unwrap(); + + tempfile + .as_file_mut() + .seek(std::io::SeekFrom::Start((offset + start_nl_end) as u64)) + .unwrap(); + tempfile.as_file_mut().write_all(sorted.as_bytes()).unwrap(); + + tempfile.persist(path).unwrap(); + } } // Start the next search after the end section From 53f64405a86cc5e5fe63c27bb24734548045a71a Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sat, 16 Aug 2025 14:26:34 +0200 Subject: [PATCH 288/585] bless tidy tests --- src/tools/tidy/src/alphabetical/tests.rs | 34 ++++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/tools/tidy/src/alphabetical/tests.rs b/src/tools/tidy/src/alphabetical/tests.rs index 5bfb37a098fc..6a756a84cf99 100644 --- a/src/tools/tidy/src/alphabetical/tests.rs +++ b/src/tools/tidy/src/alphabetical/tests.rs @@ -7,7 +7,7 @@ fn test(lines: &str, name: &str, expected_msg: &str, expected_bad: bool) { let tidy_ctx = TidyCtx::new(Path::new("/"), false, TidyFlags::default()); let mut check = tidy_ctx.start_check("alphabetical-test"); - check_lines(&name, lines.lines().enumerate(), &mut check); + check_lines(Path::new(name), lines, &tidy_ctx, &mut check); assert_eq!(expected_bad, check.is_bad()); let errors = check.get_errors(); @@ -95,7 +95,7 @@ fn test_rust_bad() { def // tidy-alphabetical-end "; - bad(lines, "bad:4: line not in alphabetical order"); + bad(lines, "bad:2: line not in alphabetical order (tip: use --bless to sort this list)"); } #[test] @@ -107,7 +107,7 @@ fn test_toml_bad() { def # tidy-alphabetical-end "; - bad(lines, "bad:4: line not in alphabetical order"); + bad(lines, "bad:2: line not in alphabetical order (tip: use --bless to sort this list)"); } #[test] @@ -121,7 +121,7 @@ fn test_features_bad() { #![feature(def)] tidy-alphabetical-end "; - bad(lines, "bad:4: line not in alphabetical order"); + bad(lines, "bad:2: line not in alphabetical order (tip: use --bless to sort this list)"); } #[test] @@ -134,7 +134,7 @@ fn test_indent_bad() { def $ tidy-alphabetical-end "; - bad(lines, "bad:4: line not in alphabetical order"); + bad(lines, "bad:2: line not in alphabetical order (tip: use --bless to sort this list)"); } #[test] @@ -150,7 +150,7 @@ fn test_split_bad() { ) && tidy-alphabetical-end "; - bad(lines, "bad:7: line not in alphabetical order"); + bad(lines, "bad:3: line not in alphabetical order (tip: use --bless to sort this list)"); } #[test] @@ -160,7 +160,7 @@ fn test_double_start() { abc tidy-alphabetical-start "; - bad(lines, "bad:3 found `tidy-alphabetical-start` expecting `tidy-alphabetical-end`"); + bad(lines, "bad:0 `tidy-alphabetical-start` without a matching `tidy-alphabetical-end`"); } #[test] @@ -179,7 +179,7 @@ fn test_missing_end() { tidy-alphabetical-start abc "; - bad(lines, "bad: reached end of file expecting `tidy-alphabetical-end`"); + bad(lines, "bad:0 `tidy-alphabetical-start` without a matching `tidy-alphabetical-end`"); } #[test] @@ -319,7 +319,7 @@ fn test_numeric_bad() { item2 # tidy-alphabetical-end "; - bad(lines, "bad:4: line not in alphabetical order"); + bad(lines, "bad:2: line not in alphabetical order (tip: use --bless to sort this list)"); let lines = "\ # tidy-alphabetical-start @@ -327,7 +327,7 @@ fn test_numeric_bad() { zve64d # tidy-alphabetical-end "; - bad(lines, "bad:3: line not in alphabetical order"); + bad(lines, "bad:1: line not in alphabetical order (tip: use --bless to sort this list)"); let lines = "\ # tidy-alphabetical-start @@ -335,7 +335,7 @@ fn test_numeric_bad() { 00 # tidy-alphabetical-end "; - bad(lines, "bad:3: line not in alphabetical order"); + bad(lines, "bad:1: line not in alphabetical order (tip: use --bless to sort this list)"); } #[test] @@ -347,7 +347,7 @@ fn multiline() { ( b, a - ) + ); tidy-alphabetical-end "; good(lines); @@ -357,7 +357,7 @@ fn multiline() { ( b, a - ) + ); (b, a); tidy-alphabetical-end @@ -371,22 +371,22 @@ fn multiline() { ( b, a - ) + ); tidy-alphabetical-end "; - bad(lines, "bad:5: line not in alphabetical order"); + bad(lines, "bad:1: line not in alphabetical order (tip: use --bless to sort this list)"); let lines = "\ tidy-alphabetical-start ( c, a - ) + ); (b, a); tidy-alphabetical-end "; - bad(lines, "bad:6: line not in alphabetical order"); + bad(lines, "bad:1: line not in alphabetical order (tip: use --bless to sort this list)"); let lines = "\ force_unwind_tables: Option = (None, parse_opt_bool, [TRACKED], From d318d3d6562b5b88d5bcbdf3cde5d015a7541b8d Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 1 Dec 2025 17:28:58 +0100 Subject: [PATCH 289/585] drive-by: tidy: fixup style --- src/tools/tidy/src/diagnostics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/diagnostics.rs b/src/tools/tidy/src/diagnostics.rs index 159500751aa5..88816b5abeff 100644 --- a/src/tools/tidy/src/diagnostics.rs +++ b/src/tools/tidy/src/diagnostics.rs @@ -6,10 +6,10 @@ use termcolor::Color; +/// CLI flags used by tidy. #[derive(Clone, Default)] -///CLI flags used by tidy. pub struct TidyFlags { - ///Applies style and formatting changes during a tidy run. + /// Applies style and formatting changes during a tidy run. bless: bool, } From ed1b831906b5ff3c00ee0372811cb801baaa15e0 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 18 Aug 2025 17:42:43 +0200 Subject: [PATCH 290/585] bless tidy --- compiler/rustc_type_ir/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index c1e301961267..8065db1e05dd 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -4,11 +4,11 @@ #![allow(rustc::usage_of_ty_tykind)] #![allow(rustc::usage_of_type_ir_inherent)] #![allow(rustc::usage_of_type_ir_traits)] +#![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr( feature = "nightly", feature(associated_type_defaults, never_type, rustc_attrs, negative_impls) )] -#![cfg_attr(feature = "nightly", allow(internal_features))] // tidy-alphabetical-end extern crate self as rustc_type_ir; From fdea885b800375fb4e9a21e919c6afd84ae0728b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Wed, 3 Dec 2025 17:55:40 +0100 Subject: [PATCH 291/585] Revert #149516 to fix i686-pc-windows-gnu host Revert #149516 because it caused dist to pick up x86_64 `libwinpthreads.dll` dependency, resulting in broken toolchain. This reverts commit 5afd8ff8df0e0850b4b5671676f4bb057b33dada, reversing changes made to 7cb02f975248447461a95110eb466c76cb3ac7cf. --- src/ci/scripts/install-mingw.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index da8e1d55f3ae..17bedaa7b826 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -47,6 +47,12 @@ if isWindows && isKnownToBeMingwBuild; then ;; esac + # Stop /msys64/bin from being prepended to PATH by adding the bin directory manually. + # Note that this intentionally uses a Windows style path instead of the msys2 path to + # avoid being auto-translated into `/usr/bin`, which will not have the desired effect. + msys2Path="c:/msys64" + ciCommandAddPath "${msys2Path}/usr/bin" + case "${mingw_archive}" in *.7z) curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" @@ -67,4 +73,12 @@ if isWindows && isKnownToBeMingwBuild; then esac ciCommandAddPath "$(cygpath -m "$(pwd)/${mingw_dir}/bin")" + + # MSYS2 is not installed on AArch64 runners + if [[ "${CI_JOB_NAME}" != *aarch64-llvm* ]]; then + # Initialize mingw for the user. + # This should be done by github but isn't for some reason. + # (see https://github.com/actions/runner-images/issues/12600) + /c/msys64/usr/bin/bash -lc ' ' + fi fi From 29f31f16621f2402d92918896bf3b77d9e2a2683 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Tue, 2 Dec 2025 16:53:12 -0500 Subject: [PATCH 292/585] rustdoc: Add unstable `--merge-doctests=yes/no/auto` flag This is useful for changing the *default* for whether doctests are merged or not. Currently, that default is solely controlled by `edition = 2024`, which adds a high switching cost to get doctest merging. This flag allows opt-ing in even on earlier additions. Unlike the `edition = 2024` default, `--merge-doctests=yes` gives a hard error if merging fails instead of falling back to running standalone tests. The user has explicitly said they want merging, so we shouldn't silently do something else. `--merge-doctests=auto` is equivalent to the current 2024 edition behavior, but available on earlier editions. --- src/librustdoc/config.rs | 31 ++++++++++++++++ src/librustdoc/doctest.rs | 34 +++++++++++------ src/librustdoc/doctest/make.rs | 37 ++++++++++++------- src/librustdoc/doctest/markdown.rs | 4 +- src/librustdoc/lib.rs | 10 ++++- .../output-default.stdout | 4 ++ tests/rustdoc-ui/doctest/force-merge-fail.rs | 18 +++++++++ .../doctest/force-merge-fail.stderr | 6 +++ tests/rustdoc-ui/doctest/force-merge.rs | 25 +++++++++++++ tests/rustdoc-ui/doctest/force-merge.stdout | 8 ++++ tests/rustdoc-ui/doctest/force-no-merge.rs | 24 ++++++++++++ .../rustdoc-ui/doctest/force-no-merge.stdout | 7 ++++ .../rustdoc-ui/doctest/merge-doctests-auto.rs | 28 ++++++++++++++ .../doctest/merge-doctests-auto.stdout | 8 ++++ .../doctest/merge-doctests-invalid.rs | 2 + .../doctest/merge-doctests-invalid.stderr | 2 + .../doctest/merge-doctests-unstable.rs | 2 + .../doctest/merge-doctests-unstable.stderr | 2 + 18 files changed, 224 insertions(+), 28 deletions(-) create mode 100644 tests/rustdoc-ui/doctest/force-merge-fail.rs create mode 100644 tests/rustdoc-ui/doctest/force-merge-fail.stderr create mode 100644 tests/rustdoc-ui/doctest/force-merge.rs create mode 100644 tests/rustdoc-ui/doctest/force-merge.stdout create mode 100644 tests/rustdoc-ui/doctest/force-no-merge.rs create mode 100644 tests/rustdoc-ui/doctest/force-no-merge.stdout create mode 100644 tests/rustdoc-ui/doctest/merge-doctests-auto.rs create mode 100644 tests/rustdoc-ui/doctest/merge-doctests-auto.stdout create mode 100644 tests/rustdoc-ui/doctest/merge-doctests-invalid.rs create mode 100644 tests/rustdoc-ui/doctest/merge-doctests-invalid.stderr create mode 100644 tests/rustdoc-ui/doctest/merge-doctests-unstable.rs create mode 100644 tests/rustdoc-ui/doctest/merge-doctests-unstable.stderr diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 5d16dff24c69..e5a4593260a4 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -63,6 +63,15 @@ pub(crate) enum InputMode { HasFile(Input), } +/// Whether to run multiple doctests in the same binary. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] +pub(crate) enum MergeDoctests { + #[default] + Never, + Always, + Auto, +} + /// Configuration options for rustdoc. #[derive(Clone)] pub(crate) struct Options { @@ -121,6 +130,8 @@ pub(crate) struct Options { /// Optional path to persist the doctest executables to, defaults to a /// temporary directory if not set. pub(crate) persist_doctests: Option, + /// Whether to merge + pub(crate) merge_doctests: MergeDoctests, /// Runtool to run doctests with pub(crate) test_runtool: Option, /// Arguments to pass to the runtool @@ -801,6 +812,8 @@ fn println_condition(condition: Condition) { Ok(result) => result, Err(e) => dcx.fatal(format!("--merge option error: {e}")), }; + let merge_doctests = parse_merge_doctests(matches, edition, dcx); + tracing::debug!("merge_doctests: {merge_doctests:?}"); if generate_link_to_definition && (show_coverage || output_format != OutputFormat::Html) { dcx.struct_warn( @@ -852,6 +865,7 @@ fn println_condition(condition: Condition) { crate_version, test_run_directory, persist_doctests, + merge_doctests, test_runtool, test_runtool_args, test_builder, @@ -1048,3 +1062,20 @@ fn parse_merge(m: &getopts::Matches) -> Result { Some(_) => Err("argument to --merge must be `none`, `shared`, or `finalize`"), } } + +fn parse_merge_doctests( + m: &getopts::Matches, + edition: Edition, + dcx: DiagCtxtHandle<'_>, +) -> MergeDoctests { + match m.opt_str("merge-doctests").as_deref() { + Some("y") | Some("yes") | Some("on") | Some("true") => MergeDoctests::Always, + Some("n") | Some("no") | Some("off") | Some("false") => MergeDoctests::Never, + Some("auto") => MergeDoctests::Auto, + None if edition < Edition::Edition2024 => MergeDoctests::Never, + None => MergeDoctests::Auto, + Some(_) => { + dcx.fatal("argument to --merge-doctests must be a boolean (true/false) or 'auto'") + } + } +} diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 481aa392007c..cab65181c940 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -33,7 +33,7 @@ use tracing::debug; use self::rust::HirCollector; -use crate::config::{Options as RustdocOptions, OutputFormat}; +use crate::config::{MergeDoctests, Options as RustdocOptions, OutputFormat}; use crate::html::markdown::{ErrorCodes, Ignore, LangString, MdRelLine}; use crate::lint::init_lints; @@ -265,6 +265,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions }; run_tests( + dcx, opts, &rustdoc_options, &unused_extern_reports, @@ -316,6 +317,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions } pub(crate) fn run_tests( + dcx: DiagCtxtHandle<'_>, opts: GlobalTestOptions, rustdoc_options: &Arc, unused_extern_reports: &Arc>>, @@ -368,6 +370,13 @@ pub(crate) fn run_tests( } continue; } + + if rustdoc_options.merge_doctests == MergeDoctests::Always { + let mut diag = dcx.struct_fatal("failed to merge doctests"); + diag.note("requested explicitly on the command line with `--merge-doctests=yes`"); + diag.emit(); + } + // We failed to compile all compatible tests as one so we push them into the // `standalone_tests` doctests. debug!("Failed to compile compatible doctests for edition {} all at once", edition); @@ -645,9 +654,9 @@ fn run_test( // tested as standalone tests. return (Duration::default(), Err(TestFailure::CompileError)); } - if !rustdoc_options.no_capture { - // If `no_capture` is disabled, then we don't display rustc's output when compiling - // the merged doctests. + if !rustdoc_options.no_capture && rustdoc_options.merge_doctests == MergeDoctests::Auto { + // If `no_capture` is disabled, and we might fallback to standalone tests, then we don't + // display rustc's output when compiling the merged doctests. compiler.stderr(Stdio::null()); } // bundled tests are an rlib, loaded by a separate runner executable @@ -728,10 +737,12 @@ fn run_test( // tested as standalone tests. return (instant.elapsed(), Err(TestFailure::CompileError)); } - if !rustdoc_options.no_capture { - // If `no_capture` is disabled, then we don't display rustc's output when compiling - // the merged doctests. + if !rustdoc_options.no_capture && rustdoc_options.merge_doctests == MergeDoctests::Auto { + // If `no_capture` is disabled and we're autodetecting whether to merge, + // we don't display rustc's output when compiling the merged doctests. runner_compiler.stderr(Stdio::null()); + } else { + runner_compiler.stderr(Stdio::inherit()); } runner_compiler.arg("--error-format=short"); debug!("compiler invocation for doctest runner: {runner_compiler:?}"); @@ -888,7 +899,7 @@ fn new(options: &RustdocOptions, test_id: &Option, test_path: PathBuf) - DirState::Perm(path) } else { - DirState::Temp(get_doctest_dir().expect("rustdoc needs a tempdir")) + DirState::Temp(get_doctest_dir(options).expect("rustdoc needs a tempdir")) }; Self { outdir, path: test_path } @@ -977,21 +988,20 @@ struct CreateRunnableDocTests { visited_tests: FxHashMap<(String, usize), usize>, unused_extern_reports: Arc>>, compiling_test_count: AtomicUsize, - can_merge_doctests: bool, + can_merge_doctests: MergeDoctests, } impl CreateRunnableDocTests { fn new(rustdoc_options: RustdocOptions, opts: GlobalTestOptions) -> CreateRunnableDocTests { - let can_merge_doctests = rustdoc_options.edition >= Edition::Edition2024; CreateRunnableDocTests { standalone_tests: Vec::new(), mergeable_tests: FxIndexMap::default(), - rustdoc_options: Arc::new(rustdoc_options), opts, visited_tests: FxHashMap::default(), unused_extern_reports: Default::default(), compiling_test_count: AtomicUsize::new(0), - can_merge_doctests, + can_merge_doctests: rustdoc_options.merge_doctests, + rustdoc_options: Arc::new(rustdoc_options), } } diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index e9f5024e494d..1f5956168d7e 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -20,6 +20,7 @@ use tracing::debug; use super::GlobalTestOptions; +use crate::config::MergeDoctests; use crate::display::Joined as _; use crate::html::markdown::LangString; @@ -41,7 +42,7 @@ pub(crate) struct BuildDocTestBuilder<'a> { source: &'a str, crate_name: Option<&'a str>, edition: Edition, - can_merge_doctests: bool, + can_merge_doctests: MergeDoctests, // If `test_id` is `None`, it means we're generating code for a code example "run" link. test_id: Option, lang_str: Option<&'a LangString>, @@ -55,7 +56,7 @@ pub(crate) fn new(source: &'a str) -> Self { source, crate_name: None, edition: DEFAULT_EDITION, - can_merge_doctests: false, + can_merge_doctests: MergeDoctests::Never, test_id: None, lang_str: None, span: DUMMY_SP, @@ -70,7 +71,7 @@ pub(crate) fn crate_name(mut self, crate_name: &'a str) -> Self { } #[inline] - pub(crate) fn can_merge_doctests(mut self, can_merge_doctests: bool) -> Self { + pub(crate) fn can_merge_doctests(mut self, can_merge_doctests: MergeDoctests) -> Self { self.can_merge_doctests = can_merge_doctests; self } @@ -117,10 +118,6 @@ pub(crate) fn build(self, dcx: Option>) -> DocTestBuilder { span, global_crate_attrs, } = self; - let can_merge_doctests = can_merge_doctests - && lang_str.is_some_and(|lang_str| { - !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate - }); let result = rustc_driver::catch_fatal_errors(|| { rustc_span::create_session_if_not_set_then(edition, |_| { @@ -155,14 +152,26 @@ pub(crate) fn build(self, dcx: Option>) -> DocTestBuilder { debug!("crate_attrs:\n{crate_attrs}{maybe_crate_attrs}"); debug!("crates:\n{crates}"); debug!("after:\n{everything_else}"); + debug!("merge-doctests: {can_merge_doctests:?}"); - // If it contains `#[feature]` or `#[no_std]`, we don't want it to be merged either. - let can_be_merged = can_merge_doctests - && !has_global_allocator - && crate_attrs.is_empty() - // If this is a merged doctest and a defined macro uses `$crate`, then the path will - // not work, so better not put it into merged doctests. - && !(has_macro_def && everything_else.contains("$crate")); + // Up until now, we've been dealing with settings for the whole crate. + // Now, infer settings for this particular test. + let can_be_merged = if can_merge_doctests == MergeDoctests::Auto { + let mut can_merge = false; + // Avoid tests with incompatible attributes. + can_merge |= lang_str.is_some_and(|lang_str| { + !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate + }); + // If it contains `#[feature]` or `#[no_std]`, we don't want it to be merged either. + can_merge &= !has_global_allocator + && crate_attrs.is_empty() + // If this is a merged doctest and a defined macro uses `$crate`, then the path will + // not work, so better not put it into merged doctests. + && !(has_macro_def && everything_else.contains("$crate")); + can_merge + } else { + can_merge_doctests != MergeDoctests::Never + }; DocTestBuilder { supports_color, has_main_fn, diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs index 7f26605f2562..45f1e8a7fb98 100644 --- a/src/librustdoc/doctest/markdown.rs +++ b/src/librustdoc/doctest/markdown.rs @@ -3,6 +3,7 @@ use std::fs::read_to_string; use std::sync::{Arc, Mutex}; +use rustc_errors::DiagCtxtHandle; use rustc_session::config::Input; use rustc_span::{DUMMY_SP, FileName}; use tempfile::tempdir; @@ -78,7 +79,7 @@ fn visit_header(&mut self, name: &str, level: u32) { } /// Runs any tests/code examples in the markdown file `options.input`. -pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> { +pub(crate) fn test(input: &Input, options: Options, dcx: DiagCtxtHandle<'_>) -> Result<(), String> { let input_str = match input { Input::File(path) => { read_to_string(path).map_err(|err| format!("{}: {err}", path.display()))? @@ -118,6 +119,7 @@ pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> { let CreateRunnableDocTests { opts, rustdoc_options, standalone_tests, mergeable_tests, .. } = collector; crate::doctest::run_tests( + dcx, opts, &rustdoc_options, &Arc::new(Mutex::new(Vec::new())), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index e4601bfb20d7..be46c85311a0 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -544,6 +544,14 @@ fn opts() -> Vec { "[toolchain-shared-resources,invocation-specific,dep-info]", ), opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""), + opt( + Unstable, + Opt, + "", + "merge-doctests", + "Force all doctests to be compiled as a single binary, instead of one binary per test. If merging fails, rustdoc will emit a hard error.", + "yes|no|auto", + ), opt( Unstable, Multi, @@ -822,7 +830,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { options.should_test || output_format == config::OutputFormat::Doctest, config::markdown_input(&input), ) { - (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options)), + (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options, dcx)), (true, None) => return doctest::run(dcx, input, options), (false, Some(md_input)) => { let md_input = md_input.to_owned(); diff --git a/tests/run-make/rustdoc-default-output/output-default.stdout b/tests/run-make/rustdoc-default-output/output-default.stdout index 49eaf7e2e1e0..4e28be347cbb 100644 --- a/tests/run-make/rustdoc-default-output/output-default.stdout +++ b/tests/run-make/rustdoc-default-output/output-default.stdout @@ -154,6 +154,10 @@ Options: Comma separated list of types of output for rustdoc to emit --no-run Compile doctests without running them + --merge-doctests yes|no|auto + Force all doctests to be compiled as a single binary, + instead of one binary per test. If merging fails, + rustdoc will emit a hard error. --remap-path-prefix FROM=TO Remap source names in compiler messages --show-type-layout diff --git a/tests/rustdoc-ui/doctest/force-merge-fail.rs b/tests/rustdoc-ui/doctest/force-merge-fail.rs new file mode 100644 index 000000000000..88c36268d072 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-merge-fail.rs @@ -0,0 +1,18 @@ +//@ edition: 2018 +//@ compile-flags: --test --test-args=--test-threads=1 --merge-doctests=yes -Z unstable-options +//@ normalize-stderr: ".*doctest_bundle_2018.rs:\d+:\d+" -> "doctest_bundle_2018.rs:$$LINE:$$COL" + +//~? ERROR failed to merge doctests + +/// These two doctests will fail to force-merge, and should give a hard error as a result. +/// +/// ``` +/// #![deny(clashing_extern_declarations)] +/// unsafe extern "C" { fn unmangled_name() -> u8; } +/// ``` +/// +/// ``` +/// #![deny(clashing_extern_declarations)] +/// unsafe extern "C" { fn unmangled_name(); } +/// ``` +pub struct Foo; diff --git a/tests/rustdoc-ui/doctest/force-merge-fail.stderr b/tests/rustdoc-ui/doctest/force-merge-fail.stderr new file mode 100644 index 000000000000..b87807dc5ed7 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-merge-fail.stderr @@ -0,0 +1,6 @@ +doctest_bundle_2018.rs:$LINE:$COL: error: `unmangled_name` redeclared with a different signature: this signature doesn't match the previous declaration +error: aborting due to 1 previous error +error: failed to merge doctests + | + = note: requested explicitly on the command line with `--merge-doctests=yes` + diff --git a/tests/rustdoc-ui/doctest/force-merge.rs b/tests/rustdoc-ui/doctest/force-merge.rs new file mode 100644 index 000000000000..bd2f474f8a56 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-merge.rs @@ -0,0 +1,25 @@ +//@ check-pass +//@ edition: 2018 +//@ compile-flags: --test --test-args=--test-threads=1 --merge-doctests=yes -Z unstable-options +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME" +//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME" +//@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL" + +// FIXME: compiletest doesn't support `// RAW` for doctests because the progress messages aren't +// emitted as JSON. Instead the .stderr file tests that this contains a +// "merged compilation took ..." message. + +/// ``` +/// let x = 12; +/// ``` +/// +/// These two doctests should be force-merged, even though this uses edition 2018. +/// +/// ``` +/// fn main() { +/// println!("owo"); +/// } +/// ``` +pub struct Foo; diff --git a/tests/rustdoc-ui/doctest/force-merge.stdout b/tests/rustdoc-ui/doctest/force-merge.stdout new file mode 100644 index 000000000000..94c7909ae0a6 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-merge.stdout @@ -0,0 +1,8 @@ + +running 2 tests +test $DIR/force-merge.rs - Foo (line 14) ... ok +test $DIR/force-merge.rs - Foo (line 20) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + +all doctests ran in $TIME; merged doctests compilation took $TIME diff --git a/tests/rustdoc-ui/doctest/force-no-merge.rs b/tests/rustdoc-ui/doctest/force-no-merge.rs new file mode 100644 index 000000000000..9ddea5fc2e55 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-no-merge.rs @@ -0,0 +1,24 @@ +//@ edition: 2024 +//@ check-pass +//@ compile-flags: --test --test-args=--test-threads=1 --merge-doctests=no -Z unstable-options +//@ normalize-stderr: ".*doctest_bundle_2018.rs:\d+:\d+" -> "doctest_bundle_2018.rs:$$LINE:$$COL" + +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME" +//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME" +//@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL" + +/// These two doctests should not force-merge, even though this crate has edition 2024 and the +/// individual doctests are not annotated. +/// +/// ``` +/// #![deny(clashing_extern_declarations)] +/// unsafe extern "C" { fn unmangled_name() -> u8; } +/// ``` +/// +/// ``` +/// #![deny(clashing_extern_declarations)] +/// unsafe extern "C" { fn unmangled_name(); } +/// ``` +pub struct Foo; diff --git a/tests/rustdoc-ui/doctest/force-no-merge.stdout b/tests/rustdoc-ui/doctest/force-no-merge.stdout new file mode 100644 index 000000000000..513ff7705497 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-no-merge.stdout @@ -0,0 +1,7 @@ + +running 2 tests +test $DIR/force-no-merge.rs - Foo (line 15) ... ok +test $DIR/force-no-merge.rs - Foo (line 20) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/merge-doctests-auto.rs b/tests/rustdoc-ui/doctest/merge-doctests-auto.rs new file mode 100644 index 000000000000..2e7d0db7a346 --- /dev/null +++ b/tests/rustdoc-ui/doctest/merge-doctests-auto.rs @@ -0,0 +1,28 @@ +//! `--merge-doctests=auto` should override the edition. + +//@ check-pass +//@ edition: 2018 +//@ compile-flags: --test --test-args=--test-threads=1 --merge-doctests=auto -Z unstable-options + +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME" +//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME" +//@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL" + +// FIXME: compiletest doesn't support `// RAW` for doctests because the progress messages aren't +// emitted as JSON. Instead the .stderr file tests that this contains a +// "merged compilation took ..." message. + +/// ``` +/// let x = 12; +/// ``` +/// +/// These two doctests should be auto-merged, even though this uses edition 2018. +/// +/// ``` +/// fn main() { +/// println!("owo"); +/// } +/// ``` +pub struct Foo; diff --git a/tests/rustdoc-ui/doctest/merge-doctests-auto.stdout b/tests/rustdoc-ui/doctest/merge-doctests-auto.stdout new file mode 100644 index 000000000000..a051ffd60636 --- /dev/null +++ b/tests/rustdoc-ui/doctest/merge-doctests-auto.stdout @@ -0,0 +1,8 @@ + +running 2 tests +test $DIR/merge-doctests-auto.rs - Foo (line 17) ... ok +test $DIR/merge-doctests-auto.rs - Foo (line 23) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + +all doctests ran in $TIME; merged doctests compilation took $TIME diff --git a/tests/rustdoc-ui/doctest/merge-doctests-invalid.rs b/tests/rustdoc-ui/doctest/merge-doctests-invalid.rs new file mode 100644 index 000000000000..cf3a03a901ce --- /dev/null +++ b/tests/rustdoc-ui/doctest/merge-doctests-invalid.rs @@ -0,0 +1,2 @@ +//@ compile-flags: --merge-doctests=bad-opt -Zunstable-options +//~? ERROR must be a boolean diff --git a/tests/rustdoc-ui/doctest/merge-doctests-invalid.stderr b/tests/rustdoc-ui/doctest/merge-doctests-invalid.stderr new file mode 100644 index 000000000000..d232c1b59edb --- /dev/null +++ b/tests/rustdoc-ui/doctest/merge-doctests-invalid.stderr @@ -0,0 +1,2 @@ +error: argument to --merge-doctests must be a boolean (true/false) or 'auto' + diff --git a/tests/rustdoc-ui/doctest/merge-doctests-unstable.rs b/tests/rustdoc-ui/doctest/merge-doctests-unstable.rs new file mode 100644 index 000000000000..496e531659a3 --- /dev/null +++ b/tests/rustdoc-ui/doctest/merge-doctests-unstable.rs @@ -0,0 +1,2 @@ +//@ compile-flags: --merge-doctests=no +//~? RAW `-Z unstable-options` flag must also be passed diff --git a/tests/rustdoc-ui/doctest/merge-doctests-unstable.stderr b/tests/rustdoc-ui/doctest/merge-doctests-unstable.stderr new file mode 100644 index 000000000000..e8d75342bc8e --- /dev/null +++ b/tests/rustdoc-ui/doctest/merge-doctests-unstable.stderr @@ -0,0 +1,2 @@ +error: the `-Z unstable-options` flag must also be passed to enable the flag `merge-doctests` + From 3aa4ece95d6ad46ced3ea895fcc634371ff32039 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Wed, 3 Dec 2025 15:48:16 -0500 Subject: [PATCH 293/585] Support `-C save-temps` in rustdoc This allows viewing failed merged doctests. --- src/librustdoc/doctest.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index cab65181c940..6e0025fe7064 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -123,8 +123,13 @@ pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> Ok(()) } -fn get_doctest_dir() -> io::Result { - TempFileBuilder::new().prefix("rustdoctest").tempdir() +fn get_doctest_dir(opts: &RustdocOptions) -> io::Result { + let mut builder = TempFileBuilder::new(); + builder.prefix("rustdoctest"); + if opts.codegen_options.save_temps { + builder.disable_cleanup(true); + } + builder.tempdir() } pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions) { @@ -197,7 +202,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions let externs = options.externs.clone(); let json_unused_externs = options.json_unused_externs; - let temp_dir = match get_doctest_dir() + let temp_dir = match get_doctest_dir(&options) .map_err(|error| format!("failed to create temporary directory: {error:?}")) { Ok(temp_dir) => temp_dir, @@ -207,6 +212,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions crate::wrap_return(dcx, generate_args_file(&args_path, &options)); let extract_doctests = options.output_format == OutputFormat::Doctest; + let save_temps = options.codegen_options.save_temps; let result = interface::run_compiler(config, |compiler| { let krate = rustc_interface::passes::parse(&compiler.sess); @@ -259,7 +265,9 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions eprintln!("{error}"); // Since some files in the temporary folder are still owned and alive, we need // to manually remove the folder. - let _ = std::fs::remove_dir_all(temp_dir.path()); + if !save_temps { + let _ = std::fs::remove_dir_all(temp_dir.path()); + } std::process::exit(1); } }; From 680a336fe53ee10ae28b6b9cd9c0669c6d5ca0f6 Mon Sep 17 00:00:00 2001 From: Alejandra Gonzalez Date: Wed, 3 Dec 2025 23:17:39 +0100 Subject: [PATCH 294/585] Remove myself from rotation Turns out that I'm still in burnout, the two RFCs that I'm working on, the Rust-For-Linux support, some conferences, my blog, I got a new job that is also quite time consuming. I don't have the time to do reviews right now, I'm sorry to everyone on the team. I'll try to scale down as much as possible and then I'll come back to rotation. r? ghost --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 3bf62b6b3bba..6633b87f04e8 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -65,6 +65,7 @@ users_on_vacation = [ "Manishearth", "Alexendoo", "y21", + "blyxyas", ] [assign.owners] @@ -77,7 +78,6 @@ users_on_vacation = [ "@Alexendoo", "@dswij", "@Jarcho", - "@blyxyas", "@y21", "@samueltardieu", ] From f07a84fde887a775260c2e11bc21af4195141d5d Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Wed, 1 Oct 2025 15:13:38 +0200 Subject: [PATCH 295/585] Emscripten: Turn wasm-eh on by default As specified by MCP: https://github.com/rust-lang/compiler-team/issues/920 Resolves https://github.com/rust-lang/rust/issues/148309 --- compiler/rustc_interface/src/tests.rs | 2 +- compiler/rustc_session/src/options.rs | 2 +- .../platform-support/wasm32-unknown-emscripten.md | 15 ++++++++------- .../codegen-llvm/emscripten-catch-unwind-js-eh.rs | 2 +- .../feature-gate-cfg-emscripten-wasm-eh.rs | 2 +- .../feature-gate-cfg-emscripten-wasm-eh.stderr | 6 +++--- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 8bf9f8420c05..6752ddbc5706 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -798,7 +798,7 @@ macro_rules! tracked { tracked!(embed_metadata, false); tracked!(embed_source, true); tracked!(emit_thin_lto, false); - tracked!(emscripten_wasm_eh, true); + tracked!(emscripten_wasm_eh, false); tracked!(export_executable_symbols, true); tracked!(fewer_names, Some(true)); tracked!(fixed_x18, true); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 7c7e9118d590..872a48efa366 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2338,7 +2338,7 @@ pub(crate) fn parse_align(slot: &mut Option, v: Option<&str>) -> bool { "emit a section containing stack size metadata (default: no)"), emit_thin_lto: bool = (true, parse_bool, [TRACKED], "emit the bc module with thin LTO info (default: yes)"), - emscripten_wasm_eh: bool = (false, parse_bool, [TRACKED], + emscripten_wasm_eh: bool = (true, parse_bool, [TRACKED], "Use WebAssembly error handling for wasm32-unknown-emscripten"), enforce_type_length_limit: bool = (false, parse_bool, [TRACKED], "enforce the type length limit when monomorphizing instances in codegen"), diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md b/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md index a9ff1ebd1048..d5e3125fd3c7 100644 --- a/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md +++ b/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md @@ -95,10 +95,11 @@ This target can be cross-compiled from any host. ## Emscripten ABI Compatibility The Emscripten compiler toolchain does not follow a semantic versioning scheme -that clearly indicates when breaking changes to the ABI can be made. Additionally, -Emscripten offers many different ABIs even for a single version of Emscripten -depending on the linker flags used, e.g. `-fexceptions` and `-sWASM_BIGINT`. If -the ABIs mismatch, your code may exhibit undefined behaviour. +that clearly indicates when breaking changes to the ABI can be made. +Additionally, Emscripten offers many different ABIs even for a single version of +Emscripten depending on the linker flags used, e.g. `-fwasm-exceptions` and +`-sWASM_BIGINT`. If the ABIs do not match, your code may exhibit undefined +behaviour. To ensure that the ABIs of your Rust code, of the Rust standard library, and of other code compiled for Emscripten all match, you should rebuild the Rust standard @@ -158,9 +159,9 @@ features can be disabled, and how Rust code can be conditionally compiled based which features are enabled. Note that Rust code compiled for `wasm32-unknown-emscripten` currently enables -`-fexceptions` (JS exceptions) by default unless the Rust code is compiled with -`-Cpanic=abort`. `-fwasm-exceptions` (WASM exceptions) is not yet currently supported, -see . +`-fwasm-exceptions` (legacy WASM exceptions) by default unless the Rust code is +compiled with `-Cpanic=abort`. It is possible to use JS exceptions by passing +the flag ``-Z emscripten-wasm-eh=false`` but this will be removed in the future. Please refer to the [Emscripten ABI compatibility](#emscripten-abi-compatibility) section to ensure that the features that are enabled do not cause an ABI mismatch diff --git a/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs b/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs index dfe154c1c831..c641c0a63d54 100644 --- a/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs +++ b/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Copt-level=3 --target wasm32-unknown-emscripten +//@ compile-flags: -Copt-level=3 --target wasm32-unknown-emscripten -Z emscripten-wasm-eh=false //@ needs-llvm-components: webassembly // Emscripten has its own unique implementation of catch_unwind (in `codegen_emcc_try`), diff --git a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs index 232061e239c9..a13e7fa317f5 100644 --- a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs +++ b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs @@ -1,4 +1,4 @@ //@ compile-flags: --check-cfg=cfg(emscripten_wasm_eh) -#[cfg(not(emscripten_wasm_eh))] +#[cfg(emscripten_wasm_eh)] //~^ ERROR `cfg(emscripten_wasm_eh)` is experimental fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr index 67769e3c7586..a829c9b93a56 100644 --- a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr +++ b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr @@ -1,8 +1,8 @@ error[E0658]: `cfg(emscripten_wasm_eh)` is experimental and subject to change - --> $DIR/feature-gate-cfg-emscripten-wasm-eh.rs:2:11 + --> $DIR/feature-gate-cfg-emscripten-wasm-eh.rs:2:7 | -LL | #[cfg(not(emscripten_wasm_eh))] - | ^^^^^^^^^^^^^^^^^^ +LL | #[cfg(emscripten_wasm_eh)] + | ^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(cfg_emscripten_wasm_eh)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date From 415953a317f04b0b5ad26b1ded3671a3e2a01532 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Wed, 3 Dec 2025 17:40:10 -0500 Subject: [PATCH 296/585] `--merge-doctests` is a default, not an override --- src/librustdoc/doctest/make.rs | 23 +++++++++-------- .../force-merge-default-not-override.rs | 25 +++++++++++++++++++ .../force-merge-default-not-override.stdout | 7 ++++++ 3 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 tests/rustdoc-ui/doctest/force-merge-default-not-override.rs create mode 100644 tests/rustdoc-ui/doctest/force-merge-default-not-override.stdout diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 1f5956168d7e..569206d6ec88 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -156,21 +156,22 @@ pub(crate) fn build(self, dcx: Option>) -> DocTestBuilder { // Up until now, we've been dealing with settings for the whole crate. // Now, infer settings for this particular test. + // + // Avoid tests with incompatible attributes. + let opt_out = lang_str.is_some_and(|lang_str| { + lang_str.compile_fail || lang_str.test_harness || lang_str.standalone_crate + }); let can_be_merged = if can_merge_doctests == MergeDoctests::Auto { - let mut can_merge = false; - // Avoid tests with incompatible attributes. - can_merge |= lang_str.is_some_and(|lang_str| { - !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate - }); - // If it contains `#[feature]` or `#[no_std]`, we don't want it to be merged either. - can_merge &= !has_global_allocator - && crate_attrs.is_empty() + // We try to look at the contents of the test to detect whether it should be merged. + // This is not a complete list of possible failures, but it catches many cases. + let will_probably_fail = has_global_allocator + || !crate_attrs.is_empty() // If this is a merged doctest and a defined macro uses `$crate`, then the path will // not work, so better not put it into merged doctests. - && !(has_macro_def && everything_else.contains("$crate")); - can_merge + || (has_macro_def && everything_else.contains("$crate")); + !opt_out && !will_probably_fail } else { - can_merge_doctests != MergeDoctests::Never + can_merge_doctests != MergeDoctests::Never && !opt_out }; DocTestBuilder { supports_color, diff --git a/tests/rustdoc-ui/doctest/force-merge-default-not-override.rs b/tests/rustdoc-ui/doctest/force-merge-default-not-override.rs new file mode 100644 index 000000000000..9a1e86ade67f --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-merge-default-not-override.rs @@ -0,0 +1,25 @@ +//@ check-pass +//@ edition: 2024 +//@ compile-flags: --test --test-args=--test-threads=1 --merge-doctests=yes -Z unstable-options +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME" +//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME" +//@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL" + +// FIXME: compiletest doesn't support `// RAW` for doctests because the progress messages aren't +// emitted as JSON. Instead the .stderr file tests that this doesn't contains a +// "merged compilation took ..." message. + +/// ```standalone_crate +/// let x = 12; +/// ``` +/// +/// These two doctests should be not be merged, even though this passes `--merge-doctests=yes`. +/// +/// ```standalone_crate +/// fn main() { +/// println!("owo"); +/// } +/// ``` +pub struct Foo; diff --git a/tests/rustdoc-ui/doctest/force-merge-default-not-override.stdout b/tests/rustdoc-ui/doctest/force-merge-default-not-override.stdout new file mode 100644 index 000000000000..24b16ec82f45 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-merge-default-not-override.stdout @@ -0,0 +1,7 @@ + +running 2 tests +test $DIR/force-merge-default-not-override.rs - Foo (line 14) ... ok +test $DIR/force-merge-default-not-override.rs - Foo (line 20) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + From f04ad994d5e47173c4afc25bacf5fa4ed3bd7078 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Dec 2025 23:44:38 +0100 Subject: [PATCH 297/585] rust-analyzer settings: use --compile-time-deps --- src/tools/miri/etc/rust_analyzer_helix.toml | 2 ++ src/tools/miri/etc/rust_analyzer_vscode.json | 2 ++ src/tools/miri/etc/rust_analyzer_zed.json | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/tools/miri/etc/rust_analyzer_helix.toml b/src/tools/miri/etc/rust_analyzer_helix.toml index c46b246049ff..dd222c50431a 100644 --- a/src/tools/miri/etc/rust_analyzer_helix.toml +++ b/src/tools/miri/etc/rust_analyzer_helix.toml @@ -28,5 +28,7 @@ overrideCommand = [ "./miri", "check", "--no-default-features", + "-Zunstable-options", + "--compile-time-deps", "--message-format=json", ] diff --git a/src/tools/miri/etc/rust_analyzer_vscode.json b/src/tools/miri/etc/rust_analyzer_vscode.json index 8e647f5331f0..97ba212f8ef9 100644 --- a/src/tools/miri/etc/rust_analyzer_vscode.json +++ b/src/tools/miri/etc/rust_analyzer_vscode.json @@ -22,6 +22,8 @@ "./miri", "check", "--no-default-features", + "-Zunstable-options", + "--compile-time-deps", "--message-format=json", ], } diff --git a/src/tools/miri/etc/rust_analyzer_zed.json b/src/tools/miri/etc/rust_analyzer_zed.json index 839914c8b68e..7f60a931c46f 100644 --- a/src/tools/miri/etc/rust_analyzer_zed.json +++ b/src/tools/miri/etc/rust_analyzer_zed.json @@ -31,6 +31,8 @@ "./miri", "check", "--no-default-features", + "-Zunstable-options", + "--compile-time-deps", "--message-format=json" ] } From 4d21e768f14bccea9cb269394f8f853d52964e5b Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 4 Dec 2025 09:15:05 +0800 Subject: [PATCH 298/585] Don't require a normal tool build of clippy/rustfmt when running their test steps This is redundant and wasteful. --- src/bootstrap/src/core/build_steps/test.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index d888e63275cd..7e46b85ff9af 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -524,8 +524,7 @@ fn make_run(run: RunConfig<'_>) { /// Runs `cargo test` for rustfmt. fn run(self, builder: &Builder<'_>) { - let tool_result = builder.ensure(tool::Rustfmt::from_compilers(self.compilers)); - let build_compiler = tool_result.build_compiler; + let build_compiler = self.compilers.build_compiler(); let target = self.compilers.target(); let mut cargo = tool::prepare_tool_cargo( @@ -869,11 +868,9 @@ fn run(self, builder: &Builder<'_>) { // We need to carefully distinguish the compiler that builds clippy, and the compiler // that is linked into the clippy being tested. `target_compiler` is the latter, // and it must also be used by clippy's test runner to build tests and their dependencies. - let compilers = self.compilers; - let target_compiler = compilers.target_compiler(); + let target_compiler = self.compilers.target_compiler(); + let build_compiler = self.compilers.build_compiler(); - let tool_result = builder.ensure(tool::Clippy::from_compilers(compilers)); - let build_compiler = tool_result.build_compiler; let mut cargo = tool::prepare_tool_cargo( builder, build_compiler, From 6ce0f0ff91b6ed95326b7e14dc6f449d75aff92c Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 2 Dec 2025 20:43:43 +0900 Subject: [PATCH 299/585] Only apply `no_mangle_const_items`'s suggestion to plain const items --- compiler/rustc_lint/src/builtin.rs | 27 +++++++++++-------- compiler/rustc_lint/src/lints.rs | 2 +- ...gle-generic-const-suggestion-suppressed.rs | 24 +++++++++++++++++ ...generic-const-suggestion-suppressed.stderr | 26 ++++++++++++++++++ 4 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 tests/ui/lint/no-mangle-generic-const-suggestion-suppressed.rs create mode 100644 tests/ui/lint/no-mangle-generic-const-suggestion-suppressed.stderr diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 36f4ad64a42b..b9b7e0fe6ddf 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -997,18 +997,23 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { self.check_no_mangle_on_generic_fn(cx, attr_span, it.owner_id.def_id); } } - hir::ItemKind::Const(..) => { + hir::ItemKind::Const(_, generics, ..) => { if find_attr!(attrs, AttributeKind::NoMangle(..)) { - // account for "pub const" (#45562) - let start = cx - .tcx - .sess - .source_map() - .span_to_snippet(it.span) - .map(|snippet| snippet.find("const").unwrap_or(0)) - .unwrap_or(0) as u32; - // `const` is 5 chars - let suggestion = it.span.with_hi(BytePos(it.span.lo().0 + start + 5)); + let suggestion = + if generics.params.is_empty() && generics.where_clause_span.is_empty() { + // account for "pub const" (#45562) + let start = cx + .tcx + .sess + .source_map() + .span_to_snippet(it.span) + .map(|snippet| snippet.find("const").unwrap_or(0)) + .unwrap_or(0) as u32; + // `const` is 5 chars + Some(it.span.with_hi(BytePos(it.span.lo().0 + start + 5))) + } else { + None + }; // Const items do not refer to a particular location in memory, and therefore // don't have anything to attach a symbol to diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 096299c16e0f..9aced66bdccd 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -230,7 +230,7 @@ pub(crate) struct BuiltinNoMangleGeneric { #[diag(lint_builtin_const_no_mangle)] pub(crate) struct BuiltinConstNoMangle { #[suggestion(code = "pub static", applicability = "machine-applicable")] - pub suggestion: Span, + pub suggestion: Option, } #[derive(LintDiagnostic)] diff --git a/tests/ui/lint/no-mangle-generic-const-suggestion-suppressed.rs b/tests/ui/lint/no-mangle-generic-const-suggestion-suppressed.rs new file mode 100644 index 000000000000..8dcc741b71b1 --- /dev/null +++ b/tests/ui/lint/no-mangle-generic-const-suggestion-suppressed.rs @@ -0,0 +1,24 @@ +//! Ensure the `no_mangle_const_items` lint triggers but does not offer a `pub static` +//! suggestion for consts that have generics or a where-clause. +//! regression test for + +#![feature(generic_const_items)] +#![allow(incomplete_features)] +#![deny(no_mangle_const_items)] +trait Trait { + const ASSOC: u32; +} + +#[unsafe(no_mangle)] +const WHERE_BOUND: u32 = <&'static ()>::ASSOC where for<'a> &'a (): Trait; +//~^ ERROR: const items should never be `#[no_mangle]` + +#[no_mangle] +const _: () = () where; +//~^ ERROR: const items should never be `#[no_mangle]` + +#[unsafe(no_mangle)] +pub const GENERIC: usize = N; +//~^ ERROR: const items should never be `#[no_mangle]` + +fn main() {} diff --git a/tests/ui/lint/no-mangle-generic-const-suggestion-suppressed.stderr b/tests/ui/lint/no-mangle-generic-const-suggestion-suppressed.stderr new file mode 100644 index 000000000000..a131015fd969 --- /dev/null +++ b/tests/ui/lint/no-mangle-generic-const-suggestion-suppressed.stderr @@ -0,0 +1,26 @@ +error: const items should never be `#[no_mangle]` + --> $DIR/no-mangle-generic-const-suggestion-suppressed.rs:13:1 + | +LL | const WHERE_BOUND: u32 = <&'static ()>::ASSOC where for<'a> &'a (): Trait; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/no-mangle-generic-const-suggestion-suppressed.rs:7:9 + | +LL | #![deny(no_mangle_const_items)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: const items should never be `#[no_mangle]` + --> $DIR/no-mangle-generic-const-suggestion-suppressed.rs:17:1 + | +LL | const _: () = () where; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: const items should never be `#[no_mangle]` + --> $DIR/no-mangle-generic-const-suggestion-suppressed.rs:21:1 + | +LL | pub const GENERIC: usize = N; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + From 2951d72219b56af04063bb975d581b5337c6482f Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 3 Dec 2025 10:06:16 +0900 Subject: [PATCH 300/585] Simplify and robustly compute suggestion span using `vis_span.to(ident.span.shrink_to_lo())` --- compiler/rustc_lint/src/builtin.rs | 14 +++----------- compiler/rustc_lint/src/lints.rs | 2 +- tests/ui/issues/issue-45562.stderr | 2 +- tests/ui/lint/lint-unexported-no-mangle.stderr | 4 ++-- tests/ui/lint/suggestions.stderr | 6 +++--- 5 files changed, 10 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index b9b7e0fe6ddf..dd0aa848ed2c 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -41,7 +41,7 @@ use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; -use rustc_span::{BytePos, DUMMY_SP, Ident, InnerSpan, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, InnerSpan, Span, Symbol, kw, sym}; use rustc_target::asm::InlineAsmArch; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; @@ -997,20 +997,12 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { self.check_no_mangle_on_generic_fn(cx, attr_span, it.owner_id.def_id); } } - hir::ItemKind::Const(_, generics, ..) => { + hir::ItemKind::Const(ident, generics, ..) => { if find_attr!(attrs, AttributeKind::NoMangle(..)) { let suggestion = if generics.params.is_empty() && generics.where_clause_span.is_empty() { // account for "pub const" (#45562) - let start = cx - .tcx - .sess - .source_map() - .span_to_snippet(it.span) - .map(|snippet| snippet.find("const").unwrap_or(0)) - .unwrap_or(0) as u32; - // `const` is 5 chars - Some(it.span.with_hi(BytePos(it.span.lo().0 + start + 5))) + Some(it.span.until(ident.span)) } else { None }; diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 9aced66bdccd..130c0762eb40 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -229,7 +229,7 @@ pub(crate) struct BuiltinNoMangleGeneric { #[derive(LintDiagnostic)] #[diag(lint_builtin_const_no_mangle)] pub(crate) struct BuiltinConstNoMangle { - #[suggestion(code = "pub static", applicability = "machine-applicable")] + #[suggestion(code = "pub static ", applicability = "machine-applicable")] pub suggestion: Option, } diff --git a/tests/ui/issues/issue-45562.stderr b/tests/ui/issues/issue-45562.stderr index 55d35f76a019..3372986af937 100644 --- a/tests/ui/issues/issue-45562.stderr +++ b/tests/ui/issues/issue-45562.stderr @@ -2,7 +2,7 @@ error: const items should never be `#[no_mangle]` --> $DIR/issue-45562.rs:5:14 | LL | #[no_mangle] pub const RAH: usize = 5; - | ---------^^^^^^^^^^^^^^^^ + | ----------^^^^^^^^^^^^^^^ | | | help: try a static value: `pub static` | diff --git a/tests/ui/lint/lint-unexported-no-mangle.stderr b/tests/ui/lint/lint-unexported-no-mangle.stderr index 0efec51abaf6..cb9477cfe16f 100644 --- a/tests/ui/lint/lint-unexported-no-mangle.stderr +++ b/tests/ui/lint/lint-unexported-no-mangle.stderr @@ -31,7 +31,7 @@ error: const items should never be `#[no_mangle]` --> $DIR/lint-unexported-no-mangle.rs:9:1 | LL | const FOO: u64 = 1; - | -----^^^^^^^^^^^^^^ + | ------^^^^^^^^^^^^^ | | | help: try a static value: `pub static` | @@ -41,7 +41,7 @@ error: const items should never be `#[no_mangle]` --> $DIR/lint-unexported-no-mangle.rs:12:1 | LL | pub const PUB_FOO: u64 = 1; - | ---------^^^^^^^^^^^^^^^^^^ + | ----------^^^^^^^^^^^^^^^^^ | | | help: try a static value: `pub static` diff --git a/tests/ui/lint/suggestions.stderr b/tests/ui/lint/suggestions.stderr index c35e92f59809..c6a7de51da2e 100644 --- a/tests/ui/lint/suggestions.stderr +++ b/tests/ui/lint/suggestions.stderr @@ -52,7 +52,7 @@ error: const items should never be `#[no_mangle]` --> $DIR/suggestions.rs:6:14 | LL | #[no_mangle] const DISCOVERY: usize = 1; - | -----^^^^^^^^^^^^^^^^^^^^^^ + | ------^^^^^^^^^^^^^^^^^^^^^ | | | help: try a static value: `pub static` | @@ -81,7 +81,7 @@ error: const items should never be `#[no_mangle]` --> $DIR/suggestions.rs:22:18 | LL | #[no_mangle] pub const DAUNTLESS: bool = true; - | ---------^^^^^^^^^^^^^^^^^^^^^^^^ + | ----------^^^^^^^^^^^^^^^^^^^^^^^ | | | help: try a static value: `pub static` @@ -97,7 +97,7 @@ error: const items should never be `#[no_mangle]` --> $DIR/suggestions.rs:31:18 | LL | #[no_mangle] pub(crate) const VETAR: bool = true; - | ----------------^^^^^^^^^^^^^^^^^^^^ + | -----------------^^^^^^^^^^^^^^^^^^^ | | | help: try a static value: `pub static` From 2db3c95f7220b2930c7aa615c134faf76c045630 Mon Sep 17 00:00:00 2001 From: lapla Date: Thu, 4 Dec 2025 11:56:38 +0900 Subject: [PATCH 301/585] Point to the item that is incorrectly annotated with `#[diagnostic::on_const]` --- compiler/rustc_passes/messages.ftl | 1 + compiler/rustc_passes/src/check_attr.rs | 8 ++++++-- .../on_const/misplaced_attr.stderr | 12 ++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 91a20a12b633..09ac3ae1c3a9 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -98,6 +98,7 @@ passes_deprecated_attribute = passes_diagnostic_diagnostic_on_const_only_for_trait_impls = `#[diagnostic::on_const]` can only be applied to trait impls + .label = not a trait impl passes_diagnostic_diagnostic_on_unimplemented_only_for_traits = `#[diagnostic::on_unimplemented]` can only be applied to trait definitions diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index e3b2a922c9af..128986798715 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -57,7 +57,10 @@ #[derive(LintDiagnostic)] #[diag(passes_diagnostic_diagnostic_on_const_only_for_trait_impls)] -struct DiagnosticOnConstOnlyForTraitImpls; +struct DiagnosticOnConstOnlyForTraitImpls { + #[label] + item_span: Span, +} fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target { match impl_item.kind { @@ -541,11 +544,12 @@ fn check_diagnostic_on_const( ItemLike::ForeignItem => {} } } + let item_span = self.tcx.hir_span(hir_id); self.tcx.emit_node_span_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, hir_id, attr_span, - DiagnosticOnConstOnlyForTraitImpls, + DiagnosticOnConstOnlyForTraitImpls { item_span }, ); } diff --git a/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr b/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr index a12c00c74d05..baa0b11f798b 100644 --- a/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr +++ b/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr @@ -3,6 +3,9 @@ error: `#[diagnostic::on_const]` can only be applied to trait impls | LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | pub struct Foo; + | -------------- not a trait impl | note: the lint level is defined here --> $DIR/misplaced_attr.rs:2:9 @@ -15,18 +18,27 @@ error: `#[diagnostic::on_const]` can only be applied to trait impls | LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | impl const PartialEq for Foo { + | ---------------------------- not a trait impl error: `#[diagnostic::on_const]` can only be applied to trait impls --> $DIR/misplaced_attr.rs:16:1 | LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | impl Foo { + | -------- not a trait impl error: `#[diagnostic::on_const]` can only be applied to trait impls --> $DIR/misplaced_attr.rs:25:5 | LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn partial_cmp(&self, other: &Foo) -> Option { + | ---------------------------------------------------------------- not a trait impl error: aborting due to 4 previous errors From f30eced2e3910139108f5751ea1f6a22829358c6 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 20 Nov 2025 02:06:38 +0900 Subject: [PATCH 302/585] Wrap binding name in parentheses in for-loop mut suggestion --- .../src/diagnostics/conflict_errors.rs | 16 ++++++++++++++- ...rowck-for-loop-deref-pattern-assignment.rs | 10 ++++++++++ ...k-for-loop-deref-pattern-assignment.stderr | 20 +++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 tests/ui/borrowck/borrowck-for-loop-deref-pattern-assignment.rs create mode 100644 tests/ui/borrowck/borrowck-for-loop-deref-pattern-assignment.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 9a8927c10297..7bb50a3ec4d5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3940,12 +3940,26 @@ pub(crate) fn report_illegal_reassignment( if let Some(decl) = local_decl && decl.can_be_made_mutable() { + let message = if matches!( + decl.local_info(), + LocalInfo::User(BindingForm::Var(VarBindingForm { + opt_match_place: Some((_, match_span)), + .. + })) if matches!(match_span.desugaring_kind(), Some(DesugaringKind::ForLoop)) + ) && let Ok(binding_name) = + self.infcx.tcx.sess.source_map().span_to_snippet(decl.source_info.span) + { + format!("(mut {}) ", binding_name) + } else { + "mut ".to_string() + }; err.span_suggestion_verbose( decl.source_info.span.shrink_to_lo(), "consider making this binding mutable", - "mut ".to_string(), + message, Applicability::MachineApplicable, ); + if !from_arg && matches!( decl.local_info(), diff --git a/tests/ui/borrowck/borrowck-for-loop-deref-pattern-assignment.rs b/tests/ui/borrowck/borrowck-for-loop-deref-pattern-assignment.rs new file mode 100644 index 000000000000..fc4f1e4eacb9 --- /dev/null +++ b/tests/ui/borrowck/borrowck-for-loop-deref-pattern-assignment.rs @@ -0,0 +1,10 @@ +//! regression test for +//! Ensure the diagnostic suggests `for &(mut x) ...` (parenthesized) instead of `&mut x`. + +fn main() { + let nums: &[u32] = &[1, 2, 3]; + for &num in nums { + num *= 2; //~ ERROR cannot assign twice to immutable variable `num` + println!("{num}"); + } +} diff --git a/tests/ui/borrowck/borrowck-for-loop-deref-pattern-assignment.stderr b/tests/ui/borrowck/borrowck-for-loop-deref-pattern-assignment.stderr new file mode 100644 index 000000000000..cd53e297e348 --- /dev/null +++ b/tests/ui/borrowck/borrowck-for-loop-deref-pattern-assignment.stderr @@ -0,0 +1,20 @@ +error[E0384]: cannot assign twice to immutable variable `num` + --> $DIR/borrowck-for-loop-deref-pattern-assignment.rs:7:9 + | +LL | for &num in nums { + | --- first assignment to `num` +LL | num *= 2; + | ^^^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | for &(mut num) num in nums { + | +++++++++ +help: to modify the original value, take a borrow instead + | +LL | for &ref mut num in nums { + | +++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0384`. From d49075f083d39c1ab91256c6945cc5c854ecee84 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 4 Dec 2025 15:13:40 +0900 Subject: [PATCH 303/585] Suppress `ref mut` suggestion for for-loop bindings --- .../src/diagnostics/conflict_errors.rs | 19 +++++++++++-------- ...k-for-loop-deref-pattern-assignment.stderr | 4 ---- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 7bb50a3ec4d5..f8a6fafbe78a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3940,14 +3940,16 @@ pub(crate) fn report_illegal_reassignment( if let Some(decl) = local_decl && decl.can_be_made_mutable() { - let message = if matches!( - decl.local_info(), - LocalInfo::User(BindingForm::Var(VarBindingForm { - opt_match_place: Some((_, match_span)), - .. - })) if matches!(match_span.desugaring_kind(), Some(DesugaringKind::ForLoop)) - ) && let Ok(binding_name) = - self.infcx.tcx.sess.source_map().span_to_snippet(decl.source_info.span) + let is_for_loop = matches!( + decl.local_info(), + LocalInfo::User(BindingForm::Var(VarBindingForm { + opt_match_place: Some((_, match_span)), + .. + })) if matches!(match_span.desugaring_kind(), Some(DesugaringKind::ForLoop)) + ); + let message = if is_for_loop + && let Ok(binding_name) = + self.infcx.tcx.sess.source_map().span_to_snippet(decl.source_info.span) { format!("(mut {}) ", binding_name) } else { @@ -3961,6 +3963,7 @@ pub(crate) fn report_illegal_reassignment( ); if !from_arg + && !is_for_loop && matches!( decl.local_info(), LocalInfo::User(BindingForm::Var(VarBindingForm { diff --git a/tests/ui/borrowck/borrowck-for-loop-deref-pattern-assignment.stderr b/tests/ui/borrowck/borrowck-for-loop-deref-pattern-assignment.stderr index cd53e297e348..fa230134df55 100644 --- a/tests/ui/borrowck/borrowck-for-loop-deref-pattern-assignment.stderr +++ b/tests/ui/borrowck/borrowck-for-loop-deref-pattern-assignment.stderr @@ -10,10 +10,6 @@ help: consider making this binding mutable | LL | for &(mut num) num in nums { | +++++++++ -help: to modify the original value, take a borrow instead - | -LL | for &ref mut num in nums { - | +++++++ error: aborting due to 1 previous error From e513ce3fb47b6dd89f37edf64f11720f6d1e7dfe Mon Sep 17 00:00:00 2001 From: Wafarm Date: Thu, 4 Dec 2025 14:58:30 +0800 Subject: [PATCH 304/585] Check identifiers defined in macros when suggesting identifiers hidden by hygiene --- .../rustc_resolve/src/late/diagnostics.rs | 14 +++++++ tests/ui/hygiene/pattern-macro.stderr | 10 +++++ .../macros/macro-hygiene-help-issue-149604.rs | 9 +++++ .../macro-hygiene-help-issue-149604.stderr | 38 +++++++++++++++++++ .../proc-macro/gen-macro-rules-hygiene.stderr | 10 +++++ tests/ui/proc-macro/mixed-site-span.stderr | 7 ++++ 6 files changed, 88 insertions(+) create mode 100644 tests/ui/macros/macro-hygiene-help-issue-149604.rs create mode 100644 tests/ui/macros/macro-hygiene-help-issue-149604.stderr diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 2b85639376d9..3ab6c7dcc006 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1155,6 +1155,7 @@ fn suggest_ident_hidden_by_hygiene(&self, err: &mut Diag<'_>, path: &[Segment], let callsite_span = span.source_callsite(); for rib in self.ribs[ValueNS].iter().rev() { for (binding_ident, _) in &rib.bindings { + // Case 1: the identifier is defined in the same scope as the macro is called if binding_ident.name == ident.name && !binding_ident.span.eq_ctxt(span) && !binding_ident.span.from_expansion() @@ -1166,6 +1167,19 @@ fn suggest_ident_hidden_by_hygiene(&self, err: &mut Diag<'_>, path: &[Segment], ); return; } + + // Case 2: the identifier is defined in a macro call in the same scope + if binding_ident.name == ident.name + && binding_ident.span.from_expansion() + && binding_ident.span.source_callsite().eq_ctxt(callsite_span) + && binding_ident.span.source_callsite().lo() < callsite_span.lo() + { + err.span_help( + binding_ident.span, + "an identifier with the same name is defined here, but is not accessible due to macro hygiene", + ); + return; + } } } } diff --git a/tests/ui/hygiene/pattern-macro.stderr b/tests/ui/hygiene/pattern-macro.stderr index a9764cea49e5..047244ba9ede 100644 --- a/tests/ui/hygiene/pattern-macro.stderr +++ b/tests/ui/hygiene/pattern-macro.stderr @@ -3,6 +3,16 @@ error[E0425]: cannot find value `x` in this scope | LL | x + 1; | ^ not found in this scope + | +help: an identifier with the same name is defined here, but is not accessible due to macro hygiene + --> $DIR/pattern-macro.rs:1:28 + | +LL | macro_rules! foo { () => ( x ) } + | ^ +... +LL | let foo!() = 2; + | ------ in this macro invocation + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/macros/macro-hygiene-help-issue-149604.rs b/tests/ui/macros/macro-hygiene-help-issue-149604.rs new file mode 100644 index 000000000000..5700218cc867 --- /dev/null +++ b/tests/ui/macros/macro-hygiene-help-issue-149604.rs @@ -0,0 +1,9 @@ +macro_rules! let_it { {} => { let it = (); } } +macro_rules! print_it { {} => { println!("{:?}", it); } } +//~^ ERROR cannot find value `it` in this scope + +fn main() { + let_it!(); + let () = it; //~ ERROR cannot find value `it` in this scope + print_it!(); +} diff --git a/tests/ui/macros/macro-hygiene-help-issue-149604.stderr b/tests/ui/macros/macro-hygiene-help-issue-149604.stderr new file mode 100644 index 000000000000..dc95cb7a43f0 --- /dev/null +++ b/tests/ui/macros/macro-hygiene-help-issue-149604.stderr @@ -0,0 +1,38 @@ +error[E0425]: cannot find value `it` in this scope + --> $DIR/macro-hygiene-help-issue-149604.rs:7:14 + | +LL | let () = it; + | ^^ not found in this scope + | +help: an identifier with the same name is defined here, but is not accessible due to macro hygiene + --> $DIR/macro-hygiene-help-issue-149604.rs:1:35 + | +LL | macro_rules! let_it { {} => { let it = (); } } + | ^^ +... +LL | let_it!(); + | --------- in this macro invocation + = note: this error originates in the macro `let_it` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find value `it` in this scope + --> $DIR/macro-hygiene-help-issue-149604.rs:2:50 + | +LL | macro_rules! print_it { {} => { println!("{:?}", it); } } + | ^^ not found in this scope +... +LL | print_it!(); + | ----------- in this macro invocation + | +help: an identifier with the same name is defined here, but is not accessible due to macro hygiene + --> $DIR/macro-hygiene-help-issue-149604.rs:1:35 + | +LL | macro_rules! let_it { {} => { let it = (); } } + | ^^ +... +LL | let_it!(); + | --------- in this macro invocation + = note: this error originates in the macro `print_it` which comes from the expansion of the macro `let_it` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr b/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr index 17171ad5c5cc..ed8ee4dc52cb 100644 --- a/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr +++ b/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr @@ -30,6 +30,16 @@ error[E0425]: cannot find value `local_def` in this scope | LL | local_def; | ^^^^^^^^^ help: a local variable with a similar name exists: `local_use` + | +help: an identifier with the same name is defined here, but is not accessible due to macro hygiene + --> $DIR/gen-macro-rules-hygiene.rs:13:1 + | +LL | gen_macro_rules!(); + | ^^^^^^^^^^^^^^^^^^ +... +LL | generated!(); + | ------------ in this macro invocation + = note: this error originates in the macro `generated` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/proc-macro/mixed-site-span.stderr b/tests/ui/proc-macro/mixed-site-span.stderr index d5cf484f6dd0..97e3f3e3dea8 100644 --- a/tests/ui/proc-macro/mixed-site-span.stderr +++ b/tests/ui/proc-macro/mixed-site-span.stderr @@ -606,6 +606,13 @@ error[E0425]: cannot find value `local_def` in this scope | LL | local_def; | ^^^^^^^^^ help: a local variable with a similar name exists: `local_use` + | +help: an identifier with the same name is defined here, but is not accessible due to macro hygiene + --> $DIR/mixed-site-span.rs:23:9 + | +LL | proc_macro_rules!(); + | ^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 52 previous errors From 0030e8ab1864d53d98de1e90ab3cf999b62ddcf1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 4 Aug 2025 21:55:18 -0400 Subject: [PATCH 305/585] compiler-builtins: Change gating for outline atomic symbols Build outline atomic symbols on all targets that have `outline-atomics` enabled, rather than only on Linux. Since this is no longer OS-specific, also rename the module. --- .../src/{aarch64_linux.rs => aarch64_outline_atomics.rs} | 8 ++++---- library/compiler-builtins/compiler-builtins/src/lib.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) rename library/compiler-builtins/compiler-builtins/src/{aarch64_linux.rs => aarch64_outline_atomics.rs} (97%) diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs b/library/compiler-builtins/compiler-builtins/src/aarch64_outline_atomics.rs similarity index 97% rename from library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs rename to library/compiler-builtins/compiler-builtins/src/aarch64_outline_atomics.rs index 01d7fb473291..df0cf7650222 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64_outline_atomics.rs @@ -196,7 +196,7 @@ macro_rules! compare_and_swap { "cbnz w17, 0b", "1:", "ret", - have_lse = sym crate::aarch64_linux::HAVE_LSE_ATOMICS, + have_lse = sym crate::aarch64_outline_atomics::HAVE_LSE_ATOMICS, } } } @@ -228,7 +228,7 @@ macro_rules! compare_and_swap_i128 { "cbnz w15, 0b", "1:", "ret", - have_lse = sym crate::aarch64_linux::HAVE_LSE_ATOMICS, + have_lse = sym crate::aarch64_outline_atomics::HAVE_LSE_ATOMICS, } } } @@ -256,7 +256,7 @@ macro_rules! swap { concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 16), ", [x1]"), "cbnz w17, 0b", "ret", - have_lse = sym crate::aarch64_linux::HAVE_LSE_ATOMICS, + have_lse = sym crate::aarch64_outline_atomics::HAVE_LSE_ATOMICS, } } } @@ -286,7 +286,7 @@ macro_rules! fetch_op { concat!(stxr!($ordering, $bytes), " w15, ", reg!($bytes, 17), ", [x1]"), "cbnz w15, 0b", "ret", - have_lse = sym crate::aarch64_linux::HAVE_LSE_ATOMICS, + have_lse = sym crate::aarch64_outline_atomics::HAVE_LSE_ATOMICS, } } } diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index a9dd6e531c5d..c993209699be 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -55,8 +55,8 @@ #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] pub mod aarch64; -#[cfg(all(target_arch = "aarch64", target_os = "linux"))] -pub mod aarch64_linux; +#[cfg(all(target_arch = "aarch64", target_feature = "outline-atomics"))] +pub mod aarch64_outline_atomics; #[cfg(all( kernel_user_helpers, From 2105a2579b22a45fcaa8f4037dffc084c7cd0764 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 4 Aug 2025 21:55:18 -0400 Subject: [PATCH 306/585] Make the `RUST_LSE_INIT` constructor cross-platform Change the gating and link sections to enable this for any platforms that enable `outline-atomics`, rather than only Linux. Additionally, no longer run this if LSE is available, since in this case the outline versions will never be called. --- library/std/src/sys/configure_builtins.rs | 46 ++++++++++++++++++++--- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/configure_builtins.rs b/library/std/src/sys/configure_builtins.rs index 9d776b778dcb..f569ec0f5129 100644 --- a/library/std/src/sys/configure_builtins.rs +++ b/library/std/src/sys/configure_builtins.rs @@ -1,13 +1,49 @@ -/// Hook into .init_array to enable LSE atomic operations at startup, if -/// supported. -#[cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "compiler-builtins-c")))] +/// Enable LSE atomic operations at startup, if supported. +/// +/// Linker sections are based on what [`ctor`] does, with priorities to run slightly before user +/// code: +/// +/// - Apple uses the section `__mod_init_func`, `mod_init_funcs` is needed to set +/// `S_MOD_INIT_FUNC_POINTERS`. There doesn't seem to be a way to indicate priorities. +/// - Windows uses `.CRT$XCT`, which is run before user constructors (these should use `.CRT$XCU`). +/// - ELF uses `.init_array` with a priority of 90, which runs before our `ARGV_INIT_ARRAY` +/// initializer (priority 99). Both are within the 0-100 implementation-reserved range, per docs +/// for the [`prio-ctor-dtor`] warning, and this matches compiler-rt's `CONSTRUCTOR_PRIORITY`. +/// +/// To save startup time, the initializer is only run if outline atomic routines from +/// compiler-builtins may be used. If LSE is known to be available then the calls are never +/// emitted, and if we build the C intrinsics then it has its own initializer using the symbol +/// `__aarch64_have_lse_atomics`. +/// +/// Initialization is done in a global constructor to so we get the same behavior regardless of +/// whether Rust's `init` is used, or if we are in a `dylib` or `no_main` situation (as opposed +/// to doing it as part of pre-main startup). This also matches C implementations. +/// +/// Ideally `core` would have something similar, but detecting the CPU features requires the +/// auxiliary vector from the OS. We do the initialization in `std` rather than as part of +/// `compiler-builtins` because a builtins->std dependency isn't possible, and inlining parts of +/// `std-detect` would be much messier. +/// +/// [`ctor`]: https://github.com/mmastrac/rust-ctor/blob/63382b833ddcbfb8b064f4e86bfa1ed4026ff356/shared/src/macros/mod.rs#L522-L534 +/// [`prio-ctor-dtor`]: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html +#[cfg(all( + target_arch = "aarch64", + target_feature = "outline-atomics", + not(target_feature = "lse"), + not(feature = "compiler-builtins-c"), +))] #[used] -#[unsafe(link_section = ".init_array.90")] +#[cfg_attr(target_vendor = "apple", unsafe(link_section = "__DATA,__mod_init_func,mod_init_funcs"))] +#[cfg_attr(target_os = "windows", unsafe(link_section = ".CRT$XCT"))] +#[cfg_attr( + not(any(target_vendor = "apple", target_os = "windows")), + unsafe(link_section = ".init_array.90") +)] static RUST_LSE_INIT: extern "C" fn() = { extern "C" fn init_lse() { use crate::arch; - // This is provided by compiler-builtins::aarch64_linux. + // This is provided by compiler-builtins::aarch64_outline_atomics. unsafe extern "C" { fn __rust_enable_lse(); } From 1ed1b6e2674e0884479042ae1b6aac431f1c217c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 5 Sep 2025 15:20:59 -0400 Subject: [PATCH 307/585] Enable `outline-atomics` by default on AArch64 Windows platforms Windows has a similar flag `/forceInterlockedFunctions`, which uses names such as `_InterlockedAdd64_rel`. --- .../rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs | 2 +- .../rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs index ce17280b153d..db3cf83ddc99 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs @@ -3,7 +3,7 @@ pub(crate) fn target() -> Target { let mut base = base::windows_gnullvm::opts(); base.max_atomic_width = Some(128); - base.features = "+v8a,+neon".into(); + base.features = "+v8a,+neon,+outline-atomics".into(); base.linker = Some("aarch64-w64-mingw32-clang".into()); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), &["-m", "arm64pe"]); diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs index 0d06bec21f4a..e9f7f51a7a35 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs @@ -3,7 +3,7 @@ pub(crate) fn target() -> Target { let mut base = base::windows_msvc::opts(); base.max_atomic_width = Some(128); - base.features = "+v8a,+neon".into(); + base.features = "+v8a,+neon,+outline-atomics".into(); // Microsoft recommends enabling frame pointers on Arm64 Windows. // From https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#integer-registers From c45590397843909a1f36d4fd9d89cfc1e7551652 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 5 Sep 2025 15:23:00 -0400 Subject: [PATCH 308/585] Enable `outline-atomics` by default on AArch64 Android Per LLVM commit c5e7e649d537 ("[AArch64][Clang][Linux] Enable out-of-line atomics by default.") [1], Clang enables these on Android. Thus, do the same in Rust. [1]: https://github.com/llvm/llvm-project/commit/c5e7e649d537067de --- compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs index 3b158c13521e..d1810b6fa486 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs @@ -21,7 +21,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(128), // As documented in https://developer.android.com/ndk/guides/cpu-features.html // the neon (ASIMD) and FP must exist on all android aarch64 targets. - features: "+v8a,+neon".into(), + features: "+v8a,+neon,+outline-atomics".into(), // the AAPCS64 expects use of non-leaf frame pointers per // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not From 21525f862d621bbeb9a131f3631111c402e1a447 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 5 Sep 2025 15:34:47 -0400 Subject: [PATCH 309/585] Enable `outline-atomics` by default on AArch64 Fuchsia Clang has done this by default since LLVM commit 1a963d3278c2 ("[Driver] Make -moutline-atomics default for aarch64-fuchsia targets"), [1], so do the same here. [1]: https://github.com/llvm/llvm-project/commit/1a963d3278c2daab7e12125371442cd129c09954 --- .../rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs index 6489e2bda809..8a07f98075a8 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs @@ -5,7 +5,7 @@ pub(crate) fn target() -> Target { let mut base = base::fuchsia::opts(); base.cpu = "generic".into(); - base.features = "+v8a,+crc,+aes,+sha2,+neon".into(); + base.features = "+v8a,+crc,+aes,+sha2,+neon,+outline-atomics".into(); base.max_atomic_width = Some(128); base.stack_probes = StackProbeType::Inline; base.supported_sanitizers = SanitizerSet::ADDRESS From 66c150c1fa29d15e1c5c06dfe708c8443faf42c3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 5 Sep 2025 15:34:57 -0400 Subject: [PATCH 310/585] Enable `outline-atomics` by default on AArch64 OpenBSD Clang has recently started doing this, as of LLVM commit 5d774ec8d183 ("[Driver] Enable outline atomics for OpenBSD/aarch64") [1]. Thus, do the same here. [1]: https://github.com/llvm/llvm-project/commit/5d774ec8d183cbbb243c57f50d891822211d3ec2 --- .../rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs index e5e40cb38b91..14a2f007f1e8 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: Arch::AArch64, options: TargetOptions { - features: "+v8a".into(), + features: "+v8a,+outline-atomics".into(), max_atomic_width: Some(128), stack_probes: StackProbeType::Inline, ..base::openbsd::opts() From f7b3c1d3c05c683ea22aca5db0726036786745ba Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 4 Jul 2025 17:44:15 +0100 Subject: [PATCH 311/585] Rework `c_variadic` --- .../rustc_codegen_ssa/src/traits/intrinsic.rs | 4 +- library/core/src/ffi/mod.rs | 2 +- library/core/src/ffi/va_list.rs | 183 ++++--------- library/core/src/intrinsics/mod.rs | 8 +- library/std/src/ffi/mod.rs | 2 +- .../src/directives/directive_names.rs | 1 + tests/auxiliary/rust_test_helpers.c | 4 + tests/codegen-llvm/cffi/c-variadic-copy.rs | 4 +- tests/codegen-llvm/cffi/c-variadic-opt.rs | 8 +- tests/codegen-llvm/cffi/c-variadic.rs | 12 +- .../c-link-to-rust-va-list-fn/checkrust.rs | 15 +- tests/ui/abi/variadic-ffi.rs | 32 ++- .../pass-by-value-abi.aarch64.stderr | 80 ++++++ tests/ui/c-variadic/pass-by-value-abi.rs | 46 ++++ .../c-variadic/pass-by-value-abi.win.stderr | 83 ++++++ .../pass-by-value-abi.x86_64.stderr | 240 ++++++++++++++++++ tests/ui/c-variadic/variadic-ffi-4.rs | 19 +- tests/ui/c-variadic/variadic-ffi-4.stderr | 121 ++------- .../macro-dotdotdot-may-not-begin-a-type.rs | 2 +- .../variadic-ffi-semantic-restrictions.rs | 6 +- .../variadic-ffi-semantic-restrictions.stderr | 6 +- tests/ui/thir-print/c-variadic.stdout | 4 +- 22 files changed, 591 insertions(+), 291 deletions(-) create mode 100644 tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr create mode 100644 tests/ui/c-variadic/pass-by-value-abi.rs create mode 100644 tests/ui/c-variadic/pass-by-value-abi.win.stderr create mode 100644 tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index c5ecf43046c7..187e4b90656a 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -36,10 +36,10 @@ fn type_checked_load( vtable_byte_offset: u64, typeid: Self::Metadata, ) -> Self::Value; - /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in + /// Trait method used to inject `va_start` on the "spoofed" `VaList` in /// Rust defined C-variadic functions. fn va_start(&mut self, val: Self::Value) -> Self::Value; - /// Trait method used to inject `va_end` on the "spoofed" `VaListImpl` before + /// Trait method used to inject `va_end` on the "spoofed" `VaList` before /// Rust defined C-variadic functions return. fn va_end(&mut self, val: Self::Value) -> Self::Value; } diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 1356ca217c9a..f1b928da7ef3 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -28,7 +28,7 @@ issue = "44930", reason = "the `c_variadic` feature has not been properly tested on all supported platforms" )] -pub use self::va_list::{VaArgSafe, VaList, VaListImpl}; +pub use self::va_list::{VaArgSafe, VaList}; #[unstable( feature = "c_variadic", diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 233a2ee3e484..449e62ac00d3 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -4,15 +4,15 @@ #[cfg(not(target_arch = "xtensa"))] use crate::ffi::c_void; -#[allow(unused_imports)] use crate::fmt; -use crate::intrinsics::{va_arg, va_copy, va_end}; -use crate::marker::{PhantomData, PhantomInvariantLifetime}; -use crate::ops::{Deref, DerefMut}; +use crate::intrinsics::{va_arg, va_copy}; +use crate::marker::PhantomCovariantLifetime; -// The name is WIP, using `VaListImpl` for now. -// // Most targets explicitly specify the layout of `va_list`, this layout is matched here. +// For `va_list`s which are single-element array in C (and therefore experience array-to-pointer +// decay when passed as arguments in C), the `VaList` struct is annotated with +// `#[rustc_pass_indirectly_in_non_rustic_abis]`. This ensures that the compiler uses the correct +// ABI for functions like `extern "C" fn takes_va_list(va: VaList<'_>)` by passing `va` indirectly. crate::cfg_select! { all( target_arch = "aarch64", @@ -27,66 +27,60 @@ /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf #[repr(C)] #[derive(Debug)] - #[lang = "va_list"] - pub struct VaListImpl<'f> { - stack: *mut c_void, - gr_top: *mut c_void, - vr_top: *mut c_void, + struct VaListInner { + stack: *const c_void, + gr_top: *const c_void, + vr_top: *const c_void, gr_offs: i32, vr_offs: i32, - _marker: PhantomInvariantLifetime<'f>, } } all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)) => { /// PowerPC ABI implementation of a `va_list`. #[repr(C)] #[derive(Debug)] - #[lang = "va_list"] - pub struct VaListImpl<'f> { + #[rustc_pass_indirectly_in_non_rustic_abis] + struct VaListInner { gpr: u8, fpr: u8, reserved: u16, - overflow_arg_area: *mut c_void, - reg_save_area: *mut c_void, - _marker: PhantomInvariantLifetime<'f>, + overflow_arg_area: *const c_void, + reg_save_area: *const c_void, } } target_arch = "s390x" => { /// s390x ABI implementation of a `va_list`. #[repr(C)] #[derive(Debug)] - #[lang = "va_list"] - pub struct VaListImpl<'f> { + #[rustc_pass_indirectly_in_non_rustic_abis] + struct VaListInner { gpr: i64, fpr: i64, - overflow_arg_area: *mut c_void, - reg_save_area: *mut c_void, - _marker: PhantomInvariantLifetime<'f>, + overflow_arg_area: *const c_void, + reg_save_area: *const c_void, } } all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)) => { /// x86_64 ABI implementation of a `va_list`. #[repr(C)] #[derive(Debug)] - #[lang = "va_list"] - pub struct VaListImpl<'f> { + #[rustc_pass_indirectly_in_non_rustic_abis] + struct VaListInner { gp_offset: i32, fp_offset: i32, - overflow_arg_area: *mut c_void, - reg_save_area: *mut c_void, - _marker: PhantomInvariantLifetime<'f>, + overflow_arg_area: *const c_void, + reg_save_area: *const c_void, } } target_arch = "xtensa" => { /// Xtensa ABI implementation of a `va_list`. #[repr(C)] #[derive(Debug)] - #[lang = "va_list"] - pub struct VaListImpl<'f> { - stk: *mut i32, - reg: *mut i32, + #[rustc_pass_indirectly_in_non_rustic_abis] + struct VaListInner { + stk: *const i32, + reg: *const i32, ndx: i32, - _marker: PhantomInvariantLifetime<'f>, } } @@ -95,94 +89,32 @@ pub struct VaListImpl<'f> { // - apple aarch64 (see https://github.com/rust-lang/rust/pull/56599) // - windows // - uefi - // - any other target for which we don't specify the `VaListImpl` above + // - any other target for which we don't specify the `VaListInner` above // // In this implementation the `va_list` type is just an alias for an opaque pointer. // That pointer is probably just the next variadic argument on the caller's stack. _ => { /// Basic implementation of a `va_list`. #[repr(transparent)] - #[lang = "va_list"] - pub struct VaListImpl<'f> { - ptr: *mut c_void, - - // Invariant over `'f`, so each `VaListImpl<'f>` object is tied to - // the region of the function it's defined in - _marker: PhantomInvariantLifetime<'f>, - } - - impl<'f> fmt::Debug for VaListImpl<'f> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "va_list* {:p}", self.ptr) - } - } - } -} - -crate::cfg_select! { - all( - any( - target_arch = "aarch64", - target_arch = "powerpc", - target_arch = "s390x", - target_arch = "x86_64" - ), - not(target_arch = "xtensa"), - any(not(target_arch = "aarch64"), not(target_vendor = "apple")), - not(target_family = "wasm"), - not(target_os = "uefi"), - not(windows), - ) => { - /// A wrapper for a `va_list` - #[repr(transparent)] #[derive(Debug)] - pub struct VaList<'a, 'f: 'a> { - inner: &'a mut VaListImpl<'f>, - _marker: PhantomData<&'a mut VaListImpl<'f>>, - } - - - impl<'f> VaListImpl<'f> { - /// Converts a [`VaListImpl`] into a [`VaList`] that is binary-compatible with C's `va_list`. - #[inline] - pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { - VaList { inner: self, _marker: PhantomData } - } - } - } - - _ => { - /// A wrapper for a `va_list` - #[repr(transparent)] - #[derive(Debug)] - pub struct VaList<'a, 'f: 'a> { - inner: VaListImpl<'f>, - _marker: PhantomData<&'a mut VaListImpl<'f>>, - } - - impl<'f> VaListImpl<'f> { - /// Converts a [`VaListImpl`] into a [`VaList`] that is binary-compatible with C's `va_list`. - #[inline] - pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { - VaList { inner: VaListImpl { ..*self }, _marker: PhantomData } - } + struct VaListInner { + ptr: *const c_void, } } } -impl<'a, 'f: 'a> Deref for VaList<'a, 'f> { - type Target = VaListImpl<'f>; - - #[inline] - fn deref(&self) -> &VaListImpl<'f> { - &self.inner - } +/// A variable argument list, equivalent to `va_list` in C. +#[repr(transparent)] +#[lang = "va_list"] +pub struct VaList<'a> { + inner: VaListInner, + _marker: PhantomCovariantLifetime<'a>, } -impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> { - #[inline] - fn deref_mut(&mut self) -> &mut VaListImpl<'f> { - &mut self.inner +impl fmt::Debug for VaList<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // No need to include `_marker` in debug output. + f.debug_tuple("VaList").field(&self.inner).finish() } } @@ -203,7 +135,7 @@ impl Sealed for *mut T {} impl Sealed for *const T {} } -/// Types that are valid to read using [`VaListImpl::arg`]. +/// Types that are valid to read using [`VaList::arg`]. /// /// # Safety /// @@ -238,7 +170,7 @@ unsafe impl VaArgSafe for f64 {} unsafe impl VaArgSafe for *mut T {} unsafe impl VaArgSafe for *const T {} -impl<'f> VaListImpl<'f> { +impl<'f> VaList<'f> { /// Advance to and read the next variable argument. /// /// # Safety @@ -258,27 +190,13 @@ pub unsafe fn arg(&mut self) -> T { // SAFETY: the caller must uphold the safety contract for `va_arg`. unsafe { va_arg(self) } } - - /// Copies the `va_list` at the current location. - pub unsafe fn with_copy(&self, f: F) -> R - where - F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R, - { - let mut ap = self.clone(); - let ret = f(ap.as_va_list()); - // SAFETY: the caller must uphold the safety contract for `va_end`. - unsafe { - va_end(&mut ap); - } - ret - } } -impl<'f> Clone for VaListImpl<'f> { +impl<'f> Clone for VaList<'f> { #[inline] fn clone(&self) -> Self { let mut dest = crate::mem::MaybeUninit::uninit(); - // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal + // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal. unsafe { va_copy(dest.as_mut_ptr(), self); dest.assume_init() @@ -286,18 +204,11 @@ fn clone(&self) -> Self { } } -impl<'f> Drop for VaListImpl<'f> { +impl<'f> Drop for VaList<'f> { fn drop(&mut self) { - // FIXME: this should call `va_end`, but there's no clean way to - // guarantee that `drop` always gets inlined into its caller, - // so the `va_end` would get directly called from the same function as - // the corresponding `va_copy`. `man va_end` states that C requires this, - // and LLVM basically follows the C semantics, so we need to make sure - // that `va_end` is always called from the same function as `va_copy`. - // For more details, see https://github.com/rust-lang/rust/pull/59625 - // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic. - // - // This works for now, since `va_end` is a no-op on all current LLVM targets. + // Rust requires that not calling `va_end` on a `va_list` does not cause undefined behaviour + // (as it is safe to leak values). As `va_end` is a no-op on all current LLVM targets, this + // destructor is empty. } } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 2115c5c9a85d..7571f4a1fc12 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -54,7 +54,7 @@ )] #![allow(missing_docs)] -use crate::ffi::va_list::{VaArgSafe, VaListImpl}; +use crate::ffi::va_list::{VaArgSafe, VaList}; use crate::marker::{ConstParamTy, Destruct, DiscriminantKind, PointeeSized, Tuple}; use crate::{mem, ptr}; @@ -3447,7 +3447,7 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize /// #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); +pub unsafe fn va_copy<'f>(dest: *mut VaList<'f>, src: &VaList<'f>); /// Loads an argument of type `T` from the `va_list` `ap` and increment the /// argument `ap` points to. @@ -3465,7 +3465,7 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize /// #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn va_arg(ap: &mut VaListImpl<'_>) -> T; +pub unsafe fn va_arg(ap: &mut VaList<'_>) -> T; /// Destroy the arglist `ap` after initialization with `va_start` or `va_copy`. /// @@ -3475,4 +3475,4 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize /// #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn va_end(ap: &mut VaListImpl<'_>); +pub unsafe fn va_end(ap: &mut VaList<'_>); diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index f44e12d48add..999bd5e63dc4 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -172,7 +172,7 @@ all supported platforms", issue = "44930" )] -pub use core::ffi::{VaArgSafe, VaList, VaListImpl}; +pub use core::ffi::{VaArgSafe, VaList}; #[stable(feature = "core_ffi_c", since = "1.64.0")] pub use core::ffi::{ c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index 7b1c0a18670d..e9824edfef60 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -121,6 +121,7 @@ "ignore-thumbv8m.base-none-eabi", "ignore-thumbv8m.main-none-eabi", "ignore-tvos", + "ignore-uefi", "ignore-unix", "ignore-unknown", "ignore-uwp", diff --git a/tests/auxiliary/rust_test_helpers.c b/tests/auxiliary/rust_test_helpers.c index 34cc7fd5dfbe..cd10d6b98ca7 100644 --- a/tests/auxiliary/rust_test_helpers.c +++ b/tests/auxiliary/rust_test_helpers.c @@ -314,6 +314,10 @@ double rust_interesting_average(uint64_t n, ...) { return sum; } +int32_t rust_va_list_next_i32(va_list* ap) { + return va_arg(*ap, int32_t); +} + int32_t rust_int8_to_int32(int8_t x) { return (int32_t)x; } diff --git a/tests/codegen-llvm/cffi/c-variadic-copy.rs b/tests/codegen-llvm/cffi/c-variadic-copy.rs index 4c61c4fcf68d..0cbdcb4bbb85 100644 --- a/tests/codegen-llvm/cffi/c-variadic-copy.rs +++ b/tests/codegen-llvm/cffi/c-variadic-copy.rs @@ -1,4 +1,4 @@ -// Tests that `VaListImpl::clone` gets inlined into a call to `llvm.va_copy` +// Tests that `VaList::clone` gets inlined into a call to `llvm.va_copy` #![crate_type = "lib"] #![feature(c_variadic)] @@ -12,5 +12,5 @@ pub unsafe extern "C" fn clone_variadic(ap: VaList) { let mut ap2 = ap.clone(); // CHECK: call void @llvm.va_copy - foreign_c_variadic_1(ap2.as_va_list(), 42i32); + foreign_c_variadic_1(ap2, 42i32); } diff --git a/tests/codegen-llvm/cffi/c-variadic-opt.rs b/tests/codegen-llvm/cffi/c-variadic-opt.rs index 7e544ee7f37d..3cc0c3e9f9bd 100644 --- a/tests/codegen-llvm/cffi/c-variadic-opt.rs +++ b/tests/codegen-llvm/cffi/c-variadic-opt.rs @@ -10,21 +10,21 @@ } // Ensure that `va_start` and `va_end` are properly injected even -// when the "spoofed" `VaListImpl` is not used. +// when the "spoofed" `VaList` is not used. #[no_mangle] pub unsafe extern "C" fn c_variadic_no_use(fmt: *const i8, mut ap: ...) -> i32 { // CHECK: call void @llvm.va_start - vprintf(fmt, ap.as_va_list()) + vprintf(fmt, ap) // CHECK: call void @llvm.va_end } -// Check that `VaListImpl::clone` gets inlined into a direct call to `llvm.va_copy` +// Check that `VaList::clone` gets inlined into a direct call to `llvm.va_copy` #[no_mangle] pub unsafe extern "C" fn c_variadic_clone(fmt: *const i8, mut ap: ...) -> i32 { // CHECK: call void @llvm.va_start let mut ap2 = ap.clone(); // CHECK: call void @llvm.va_copy - let res = vprintf(fmt, ap2.as_va_list()); + let res = vprintf(fmt, ap2); res // CHECK: call void @llvm.va_end } diff --git a/tests/codegen-llvm/cffi/c-variadic.rs b/tests/codegen-llvm/cffi/c-variadic.rs index 140d2f37f469..3ce421eb4a5c 100644 --- a/tests/codegen-llvm/cffi/c-variadic.rs +++ b/tests/codegen-llvm/cffi/c-variadic.rs @@ -1,6 +1,6 @@ //@ needs-unwind //@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -// +//@ min-llvm-version: 21 #![crate_type = "lib"] #![feature(c_variadic)] @@ -25,23 +25,23 @@ } // Ensure that we do not remove the `va_list` passed to the foreign function when -// removing the "spoofed" `VaListImpl` that is used by Rust defined C-variadics. +// removing the "spoofed" `VaList` that is used by Rust defined C-variadics. pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap) + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %0) foreign_c_variadic_1(ap); } pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 42) + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %0, [[PARAM]] 42) foreign_c_variadic_1(ap, 42i32); } pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42) + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %0, [[PARAM]] 2, [[PARAM]] 42) foreign_c_variadic_1(ap, 2i32, 42i32); } pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42, [[PARAM]] 0) + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %0, [[PARAM]] 2, [[PARAM]] 42, [[PARAM]] 0) foreign_c_variadic_1(ap, 2i32, 42i32, 0i32); } diff --git a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs index 63d8d713d622..dd2d09470994 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs +++ b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs @@ -2,7 +2,7 @@ #![feature(c_variadic)] #![feature(cfg_select)] -use std::ffi::{CStr, CString, VaList, VaListImpl, c_char, c_double, c_int, c_long, c_longlong}; +use std::ffi::{CStr, CString, VaList, c_char, c_double, c_int, c_long, c_longlong}; macro_rules! continue_if { ($cond:expr) => { @@ -58,11 +58,8 @@ unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool { continue_if!(ap.arg::() == 16); continue_if!(ap.arg::() == 'A' as c_int); continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Skip Me!")); - ap.with_copy( - |mut ap| { - if compare_c_str(ap.arg::<*const c_char>(), "Correct") { 0 } else { 0xff } - }, - ) + let mut ap = ap.clone(); + if compare_c_str(ap.arg::<*const c_char>(), "Correct") { 0 } else { 0xff } } #[unsafe(no_mangle)] @@ -153,8 +150,8 @@ unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool { unsafe extern "C" { fn test_variadic(_: c_int, ...) -> usize; fn test_va_list_by_value(_: VaList) -> usize; - fn test_va_list_by_pointer(_: *mut VaListImpl) -> usize; - fn test_va_list_by_pointer_pointer(_: *mut *mut VaListImpl) -> usize; + fn test_va_list_by_pointer(_: *mut VaList) -> usize; + fn test_va_list_by_pointer_pointer(_: *mut *mut VaList) -> usize; } #[unsafe(no_mangle)] @@ -165,7 +162,7 @@ extern "C" fn run_test_variadic() -> usize { #[unsafe(no_mangle)] extern "C" fn run_test_va_list_by_value() -> usize { unsafe extern "C" fn helper(mut ap: ...) -> usize { - unsafe { test_va_list_by_value(ap.as_va_list()) } + unsafe { test_va_list_by_value(ap) } } unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) } diff --git a/tests/ui/abi/variadic-ffi.rs b/tests/ui/abi/variadic-ffi.rs index dfdbff33264b..3ffa0bea0ecf 100644 --- a/tests/ui/abi/variadic-ffi.rs +++ b/tests/ui/abi/variadic-ffi.rs @@ -10,37 +10,45 @@ fn rust_interesting_average(_: u64, ...) -> f64; fn rust_valist_interesting_average(_: u64, _: VaList) -> f64; + + fn rust_va_list_next_i32(_: *mut VaList<'_>) -> i32; } -pub unsafe extern "C" fn test_valist_forward(n: u64, mut ap: ...) -> f64 { - rust_valist_interesting_average(n, ap.as_va_list()) +pub unsafe extern "C" fn test_valist_forward(n: u64, ap: ...) -> f64 { + rust_valist_interesting_average(n, ap) } -pub unsafe extern "C-unwind" fn c_unwind_can_forward(n: u64, mut ap: ...) -> f64 { - rust_valist_interesting_average(n, ap.as_va_list()) +pub unsafe extern "C-unwind" fn c_unwind_can_forward(n: u64, ap: ...) -> f64 { + rust_valist_interesting_average(n, ap) } pub unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) { - let mut ap2 = ap.clone(); - assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 30); + let ap2 = ap.clone(); + assert_eq!(rust_valist_interesting_average(2, ap2) as i64, 30); // Advance one pair in the copy before checking let mut ap2 = ap.clone(); let _ = ap2.arg::(); let _ = ap2.arg::(); - assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 50); + assert_eq!(rust_valist_interesting_average(2, ap2) as i64, 50); // Advance one pair in the original let _ = ap.arg::(); let _ = ap.arg::(); - let mut ap2 = ap.clone(); - assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 50); + let ap2 = ap.clone(); + assert_eq!(rust_valist_interesting_average(2, ap2) as i64, 50); let mut ap2 = ap.clone(); let _ = ap2.arg::(); let _ = ap2.arg::(); - assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 70); + assert_eq!(rust_valist_interesting_average(2, ap2) as i64, 70); +} + +pub unsafe extern "C" fn test_ref(mut ap: ...) { + assert_eq!(rust_va_list_next_i32(&mut ap), 2); + assert_eq!(rust_va_list_next_i32(&mut ap), 4); + assert_eq!(rust_va_list_next_i32(&mut ap), 8); } pub fn main() { @@ -85,4 +93,8 @@ unsafe fn call(fp: unsafe extern "C" fn(u64, ...) -> f64) { unsafe { test_va_copy(4, 10i64, 10f64, 20i64, 20f64, 30i64, 30f64, 40i64, 40f64); } + + unsafe { + test_ref(2, 4, 8); + } } diff --git a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr new file mode 100644 index 000000000000..fe11c4288618 --- /dev/null +++ b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr @@ -0,0 +1,80 @@ +error: fn_abi_of(take_va_list) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: VaList<'_>, + layout: Layout { + size: Size(32 bytes), + align: AbiAlign { + abi: Align(8 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: $OFFSETS, + memory_index: $MEMORY_INDEX, + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, + }, + }, + mode: Indirect { + attrs: ArgAttributes { + regular: CapturesAddress | NoAlias | NonNull | NoUndef, + arg_ext: None, + pointee_size: Size(32 bytes), + pointee_align: Some( + Align(8 bytes), + ), + }, + meta_attrs: None, + on_stack: false, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: C, + can_unwind: false, + } + --> $DIR/pass-by-value-abi.rs:26:1 + | +LL | pub extern "C" fn take_va_list(_: VaList<'_>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/c-variadic/pass-by-value-abi.rs b/tests/ui/c-variadic/pass-by-value-abi.rs new file mode 100644 index 000000000000..b65442af2472 --- /dev/null +++ b/tests/ui/c-variadic/pass-by-value-abi.rs @@ -0,0 +1,46 @@ +//@ check-fail +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" +//@ normalize-stderr: "valid_range: 0\.\.=\d+" -> "valid_range: 0..=$$MAX" +//@ normalize-stderr: "memory_index: \[[^\]]+\]" -> "memory_index: $$MEMORY_INDEX" +//@ normalize-stderr: "offsets: \[[^\]]+\]" -> "offsets: $$OFFSETS" +//@ revisions: x86_64 aarch64 win +//@ compile-flags: -O +//@ [x86_64] only-x86_64 +//@ [x86_64] ignore-windows +//@ [x86_64] ignore-uefi +//@ [aarch64] only-aarch64 +//@ [aarch64] ignore-windows +//@ [aarch64] ignore-apple +//@ [aarch64] ignore-uefi +// Windows dosen't use `#[rustc_pass_indirectly_in_non_rustic_abis]` and is tested in CI, so is here +// for comparison. +//@ [win] only-windows + +#![feature(rustc_attrs, c_variadic)] +#![crate_type = "lib"] + +// Can't use `minicore` here as this is testing the implementation in `core::ffi` specifically. +use std::ffi::VaList; + +#[rustc_abi(debug)] +pub extern "C" fn take_va_list(_: VaList<'_>) {} +//~^ ERROR fn_abi_of(take_va_list) = FnAbi { +//[x86_64]~^^ ERROR mode: Indirect { +//[x86_64]~^^^ ERROR on_stack: false, +//[aarch64]~^^^^ ERROR mode: Indirect { +//[aarch64]~^^^^^ ERROR on_stack: false, +//[win]~^^^^^^ ERROR mode: Direct( + +#[cfg(all(target_arch = "x86_64", not(windows)))] +#[rustc_abi(debug)] +pub extern "sysv64" fn take_va_list_sysv64(_: VaList<'_>) {} +//[x86_64]~^ ERROR fn_abi_of(take_va_list_sysv64) = FnAbi { +//[x86_64]~^^ ERROR mode: Indirect { +//[x86_64]~^^^ ERROR on_stack: false, + +#[cfg(all(target_arch = "x86_64", not(windows)))] +#[rustc_abi(debug)] +pub extern "win64" fn take_va_list_win64(_: VaList<'_>) {} +//[x86_64]~^ ERROR: fn_abi_of(take_va_list_win64) = FnAbi { +//[x86_64]~^^ ERROR mode: Indirect { +//[x86_64]~^^^ ERROR on_stack: false, diff --git a/tests/ui/c-variadic/pass-by-value-abi.win.stderr b/tests/ui/c-variadic/pass-by-value-abi.win.stderr new file mode 100644 index 000000000000..e84430859e02 --- /dev/null +++ b/tests/ui/c-variadic/pass-by-value-abi.win.stderr @@ -0,0 +1,83 @@ +error: fn_abi_of(take_va_list) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: VaList<'_>, + layout: Layout { + size: Size(8 bytes), + align: AbiAlign { + abi: Align(8 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: 0..=$MAX, + }, + ), + fields: Arbitrary { + offsets: $OFFSETS, + memory_index: $MEMORY_INDEX, + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: C, + can_unwind: false, + } + --> $DIR/pass-by-value-abi.rs:26:1 + | +LL | pub extern "C" fn take_va_list(_: VaList<'_>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr new file mode 100644 index 000000000000..73f1ccd5992a --- /dev/null +++ b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr @@ -0,0 +1,240 @@ +error: fn_abi_of(take_va_list) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: VaList<'_>, + layout: Layout { + size: Size(24 bytes), + align: AbiAlign { + abi: Align(8 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: $OFFSETS, + memory_index: $MEMORY_INDEX, + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, + }, + }, + mode: Indirect { + attrs: ArgAttributes { + regular: CapturesAddress | NoAlias | NonNull | NoUndef, + arg_ext: None, + pointee_size: Size(24 bytes), + pointee_align: Some( + Align(8 bytes), + ), + }, + meta_attrs: None, + on_stack: false, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: C, + can_unwind: false, + } + --> $DIR/pass-by-value-abi.rs:26:1 + | +LL | pub extern "C" fn take_va_list(_: VaList<'_>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(take_va_list_sysv64) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: VaList<'_>, + layout: Layout { + size: Size(24 bytes), + align: AbiAlign { + abi: Align(8 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: $OFFSETS, + memory_index: $MEMORY_INDEX, + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, + }, + }, + mode: Indirect { + attrs: ArgAttributes { + regular: CapturesAddress | NoAlias | NonNull | NoUndef, + arg_ext: None, + pointee_size: Size(24 bytes), + pointee_align: Some( + Align(8 bytes), + ), + }, + meta_attrs: None, + on_stack: false, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + SysV64, + ), + can_unwind: false, + } + --> $DIR/pass-by-value-abi.rs:36:1 + | +LL | pub extern "sysv64" fn take_va_list_sysv64(_: VaList<'_>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(take_va_list_win64) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: VaList<'_>, + layout: Layout { + size: Size(24 bytes), + align: AbiAlign { + abi: Align(8 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: $OFFSETS, + memory_index: $MEMORY_INDEX, + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, + }, + }, + mode: Indirect { + attrs: ArgAttributes { + regular: CapturesAddress | NoAlias | NonNull | NoUndef, + arg_ext: None, + pointee_size: Size(24 bytes), + pointee_align: Some( + Align(8 bytes), + ), + }, + meta_attrs: None, + on_stack: false, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + Win64, + ), + can_unwind: false, + } + --> $DIR/pass-by-value-abi.rs:43:1 + | +LL | pub extern "win64" fn take_va_list_win64(_: VaList<'_>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/c-variadic/variadic-ffi-4.rs b/tests/ui/c-variadic/variadic-ffi-4.rs index 806403794225..d9e2e617ce3a 100644 --- a/tests/ui/c-variadic/variadic-ffi-4.rs +++ b/tests/ui/c-variadic/variadic-ffi-4.rs @@ -2,37 +2,30 @@ #![no_std] #![feature(c_variadic)] -use core::ffi::{VaList, VaListImpl}; +use core::ffi::VaList; -pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { +pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaList<'f> { ap //~^ ERROR: lifetime may not live long enough - //~| ERROR: lifetime may not live long enough } -pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { +pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { ap //~ ERROR: lifetime may not live long enough } -pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) { - let _ = ap.with_copy(|ap| ap); //~ ERROR: lifetime may not live long enough -} - -pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { +pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { *ap0 = ap1; //~^ ERROR: lifetime may not live long enough - //~| ERROR: lifetime may not live long enough } -pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { +pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { ap0 = &mut ap1; //~^ ERROR: `ap1` does not live long enough //~| ERROR: lifetime may not live long enough //~| ERROR: lifetime may not live long enough } -pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { +pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaList, mut ap1: ...) { *ap0 = ap1.clone(); //~^ ERROR: lifetime may not live long enough - //~| ERROR: lifetime may not live long enough } diff --git a/tests/ui/c-variadic/variadic-ffi-4.stderr b/tests/ui/c-variadic/variadic-ffi-4.stderr index fc9f8036083a..a230bb6f5861 100644 --- a/tests/ui/c-variadic/variadic-ffi-4.stderr +++ b/tests/ui/c-variadic/variadic-ffi-4.stderr @@ -1,113 +1,64 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:8:5 | -LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | -- -- has type `VaListImpl<'1>` - | | - | lifetime `'f` defined here -LL | ap - | ^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'f` - | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` - = help: see for more information about variance - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:8:5 - | -LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | -- -- has type `VaListImpl<'1>` +LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaList<'f> { + | -- -- has type `VaList<'1>` | | | lifetime `'f` defined here LL | ap | ^^ function was supposed to return data with lifetime `'f` but it is returning data with lifetime `'1` - | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` - = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:14:5 + --> $DIR/variadic-ffi-4.rs:13:5 | -LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { - | -- has type `VaListImpl<'1>` +LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { + | -- has type `VaList<'1>` LL | ap | ^^ returning this value requires that `'1` must outlive `'static` - | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` - = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:18:31 + --> $DIR/variadic-ffi-4.rs:17:5 | -LL | let _ = ap.with_copy(|ap| ap); - | --- ^^ returning this value requires that `'1` must outlive `'2` - | | | - | | return type of closure is VaList<'2, '_> - | has type `VaList<'1, '_>` - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:22:5 - | -LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `VaListImpl<'2>` +LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | ------- ------- has type `VaList<'1>` | | - | has type `&mut VaListImpl<'1>` + | has type `&mut VaList<'2>` LL | *ap0 = ap1; | ^^^^ assignment requires that `'1` must outlive `'2` - | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` - = help: see for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:22:5 | -LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `VaListImpl<'2>` +LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | ------- ------- has type `VaList<'2>` | | - | has type `&mut VaListImpl<'1>` -LL | *ap0 = ap1; - | ^^^^ assignment requires that `'2` must outlive `'1` - | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` - = help: see for more information about variance - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:28:5 - | -LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `VaListImpl<'2>` - | | - | has type `&mut VaListImpl<'1>` + | has type `&mut VaList<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` | - = note: requirement occurs because of a mutable reference to `VaListImpl<'_>` + = note: requirement occurs because of a mutable reference to `VaList<'_>` = note: mutable references are invariant over their type parameter = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:28:5 + --> $DIR/variadic-ffi-4.rs:22:5 | -LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `VaListImpl<'2>` +LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | ------- ------- has type `VaList<'2>` | | - | has type `&mut VaListImpl<'1>` + | has type `&mut VaList<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1` | - = note: requirement occurs because of a mutable reference to `VaListImpl<'_>` + = note: requirement occurs because of a mutable reference to `VaList<'_>` = note: mutable references are invariant over their type parameter = help: see for more information about variance error[E0597]: `ap1` does not live long enough - --> $DIR/variadic-ffi-4.rs:28:11 + --> $DIR/variadic-ffi-4.rs:22:11 | -LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | - ------- binding `ap1` declared here +LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | - ------- binding `ap1` declared here | | | let's call the lifetime of this reference `'3` LL | ap0 = &mut ap1; @@ -120,33 +71,15 @@ LL | } | - `ap1` dropped here while still borrowed error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:35:5 + --> $DIR/variadic-ffi-4.rs:29:5 | -LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `VaListImpl<'2>` +LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | ------- ------- has type `VaList<'1>` | | - | has type `&mut VaListImpl<'1>` + | has type `&mut VaList<'2>` LL | *ap0 = ap1.clone(); - | ^^^^ assignment requires that `'2` must outlive `'1` - | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` - = help: see for more information about variance + | ^^^^ assignment requires that `'1` must outlive `'2` -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:35:12 - | -LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `VaListImpl<'2>` - | | - | has type `&mut VaListImpl<'1>` -LL | *ap0 = ap1.clone(); - | ^^^^^^^^^^^ argument requires that `'1` must outlive `'2` - | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` - = help: see for more information about variance - -error: aborting due to 11 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/parser/macro/macro-dotdotdot-may-not-begin-a-type.rs b/tests/ui/parser/macro/macro-dotdotdot-may-not-begin-a-type.rs index 8be99f22d2ee..b29f6915ae3d 100644 --- a/tests/ui/parser/macro/macro-dotdotdot-may-not-begin-a-type.rs +++ b/tests/ui/parser/macro/macro-dotdotdot-may-not-begin-a-type.rs @@ -1,4 +1,4 @@ -// A bare `...` represents `CVarArgs` (`VaListImpl<'_>`) in function argument type +// A bare `...` represents `CVarArgs` (`VaList<'_>`) in function argument type // position without being a proper type syntactically. // This test ensures that we do not regress certain MBE calls would we ever promote // `...` to a proper type syntactically. diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs index 025c0e3ecaca..6f61425a8bd6 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs @@ -32,12 +32,12 @@ extern "C" fn f3_3(_: ..., x: isize) {} const unsafe extern "C" fn f4_1(x: isize, _: ...) {} //~^ ERROR functions cannot be both `const` and C-variadic -//~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time +//~| ERROR destructor of `VaList<'_>` cannot be evaluated at compile-time const extern "C" fn f4_2(x: isize, _: ...) {} //~^ ERROR functions cannot be both `const` and C-variadic //~| ERROR functions with a C variable argument list must be unsafe -//~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time +//~| ERROR destructor of `VaList<'_>` cannot be evaluated at compile-time const extern "C" fn f4_3(_: ..., x: isize, _: ...) {} //~^ ERROR functions cannot be both `const` and C-variadic @@ -65,7 +65,7 @@ fn i_f4(_: ..., x: isize, _: ...) {} const fn i_f5(x: isize, _: ...) {} //~^ ERROR `...` is not supported for non-extern functions //~| ERROR functions cannot be both `const` and C-variadic - //~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time + //~| ERROR destructor of `VaList<'_>` cannot be evaluated at compile-time } trait T { diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr index 0e02d4434233..318015737fa1 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr @@ -236,7 +236,7 @@ error: `...` must be the last argument of a C-variadic function LL | fn t_f6(_: ..., x: isize); | ^^^^^^ -error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time +error[E0493]: destructor of `VaList<'_>` cannot be evaluated at compile-time --> $DIR/variadic-ffi-semantic-restrictions.rs:33:43 | LL | const unsafe extern "C" fn f4_1(x: isize, _: ...) {} @@ -244,7 +244,7 @@ LL | const unsafe extern "C" fn f4_1(x: isize, _: ...) {} | | | the destructor for this type cannot be evaluated in constant functions -error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time +error[E0493]: destructor of `VaList<'_>` cannot be evaluated at compile-time --> $DIR/variadic-ffi-semantic-restrictions.rs:37:36 | LL | const extern "C" fn f4_2(x: isize, _: ...) {} @@ -252,7 +252,7 @@ LL | const extern "C" fn f4_2(x: isize, _: ...) {} | | | the destructor for this type cannot be evaluated in constant functions -error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time +error[E0493]: destructor of `VaList<'_>` cannot be evaluated at compile-time --> $DIR/variadic-ffi-semantic-restrictions.rs:65:29 | LL | const fn i_f5(x: isize, _: ...) {} diff --git a/tests/ui/thir-print/c-variadic.stdout b/tests/ui/thir-print/c-variadic.stdout index d64b2b9aa9d1..f1905e04f72b 100644 --- a/tests/ui/thir-print/c-variadic.stdout +++ b/tests/ui/thir-print/c-variadic.stdout @@ -16,13 +16,13 @@ params: [ ) } Param { - ty: std::ffi::VaListImpl<'{erased}> + ty: std::ffi::VaList<'{erased}> ty_span: None self_kind: None hir_id: Some(HirId(DefId(0:3 ~ c_variadic[a5de]::foo).3)) param: Some( Pat: { - ty: std::ffi::VaListImpl<'{erased}> + ty: std::ffi::VaList<'{erased}> span: $DIR/c-variadic.rs:7:34: 7:37 (#0) kind: PatKind { Missing From 376b284521061803356c7c711c194b31be027ce4 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 4 Nov 2025 19:32:06 +0100 Subject: [PATCH 312/585] document `VaList` ABI for more targets --- library/core/src/ffi/va_list.rs | 57 ++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 449e62ac00d3..4c59ea0cc532 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -8,11 +8,29 @@ use crate::intrinsics::{va_arg, va_copy}; use crate::marker::PhantomCovariantLifetime; -// Most targets explicitly specify the layout of `va_list`, this layout is matched here. -// For `va_list`s which are single-element array in C (and therefore experience array-to-pointer -// decay when passed as arguments in C), the `VaList` struct is annotated with -// `#[rustc_pass_indirectly_in_non_rustic_abis]`. This ensures that the compiler uses the correct -// ABI for functions like `extern "C" fn takes_va_list(va: VaList<'_>)` by passing `va` indirectly. +// There are currently three flavors of how a C `va_list` is implemented for +// targets that Rust supports: +// +// - `va_list` is an opaque pointer +// - `va_list` is a struct +// - `va_list` is a single-element array, containing a struct +// +// The opaque pointer approach is the simplest to implement: the pointer just +// points to an array of arguments on the caller's stack. +// +// The struct and single-element array variants are more complex, but +// potentially more efficient because the additional state makes it +// possible to pass variadic arguments via registers. +// +// The Rust `VaList` type is ABI-compatible with the C `va_list`. +// The struct and pointer cases straightforwardly map to their Rust equivalents, +// but the single-element array case is special: in C, this type is subject to +// array-to-pointer decay. +// +// The `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute is used to match +// the pointer decay behavior in Rust, while otherwise matching Rust semantics. +// This attribute ensures that the compiler uses the correct ABI for functions +// like `extern "C" fn takes_va_list(va: VaList<'_>)` by passing `va` indirectly. crate::cfg_select! { all( target_arch = "aarch64", @@ -20,8 +38,9 @@ not(target_os = "uefi"), not(windows), ) => { - /// AArch64 ABI implementation of a `va_list`. See the - /// [AArch64 Procedure Call Standard] for more details. + /// AArch64 ABI implementation of a `va_list`. + /// + /// See the [AArch64 Procedure Call Standard] for more details. /// /// [AArch64 Procedure Call Standard]: /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf @@ -37,6 +56,12 @@ struct VaListInner { } all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)) => { /// PowerPC ABI implementation of a `va_list`. + /// + /// See the [LLVM source] and [GCC header] for more details. + /// + /// [LLVM source]: + /// https://github.com/llvm/llvm-project/blob/af9a4263a1a209953a1d339ef781a954e31268ff/llvm/lib/Target/PowerPC/PPCISelLowering.cpp#L4089-L4111 + /// [GCC header]: https://web.mit.edu/darwin/src/modules/gcc/gcc/ginclude/va-ppc.h #[repr(C)] #[derive(Debug)] #[rustc_pass_indirectly_in_non_rustic_abis] @@ -50,6 +75,11 @@ struct VaListInner { } target_arch = "s390x" => { /// s390x ABI implementation of a `va_list`. + /// + /// See the [S/390x ELF Application Binary Interface Supplement] for more details. + /// + /// [S/390x ELF Application Binary Interface Supplement]: + /// https://docs.google.com/gview?embedded=true&url=https://github.com/IBM/s390x-abi/releases/download/v1.7/lzsabi_s390x.pdf #[repr(C)] #[derive(Debug)] #[rustc_pass_indirectly_in_non_rustic_abis] @@ -61,7 +91,12 @@ struct VaListInner { } } all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)) => { - /// x86_64 ABI implementation of a `va_list`. + /// x86_64 System V ABI implementation of a `va_list`. + /// + /// See the [System V AMD64 ABI] for more details. + /// + /// [System V AMD64 ABI]: + /// https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf #[repr(C)] #[derive(Debug)] #[rustc_pass_indirectly_in_non_rustic_abis] @@ -74,6 +109,11 @@ struct VaListInner { } target_arch = "xtensa" => { /// Xtensa ABI implementation of a `va_list`. + /// + /// See the [LLVM source] for more details. + /// + /// [LLVM source]: + /// https://github.com/llvm/llvm-project/blob/af9a4263a1a209953a1d339ef781a954e31268ff/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp#L1211-L1215 #[repr(C)] #[derive(Debug)] #[rustc_pass_indirectly_in_non_rustic_abis] @@ -88,6 +128,7 @@ struct VaListInner { // // - apple aarch64 (see https://github.com/rust-lang/rust/pull/56599) // - windows + // - powerpc64 & powerpc64le // - uefi // - any other target for which we don't specify the `VaListInner` above // From 08979745c9bc87b38aa3a952593a08db25a83711 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 4 Dec 2025 11:13:24 +0100 Subject: [PATCH 313/585] split out `va_list` forwarding into its own test --- tests/codegen-llvm/cffi/c-variadic-va_list.rs | 36 +++++++++++++++++++ tests/codegen-llvm/cffi/c-variadic.rs | 22 ------------ 2 files changed, 36 insertions(+), 22 deletions(-) create mode 100644 tests/codegen-llvm/cffi/c-variadic-va_list.rs diff --git a/tests/codegen-llvm/cffi/c-variadic-va_list.rs b/tests/codegen-llvm/cffi/c-variadic-va_list.rs new file mode 100644 index 000000000000..e2652491f421 --- /dev/null +++ b/tests/codegen-llvm/cffi/c-variadic-va_list.rs @@ -0,0 +1,36 @@ +//@ needs-unwind +//@ compile-flags: -Copt-level=3 +//@ min-llvm-version: 21 + +#![crate_type = "lib"] +#![feature(c_variadic)] +#![no_std] +use core::ffi::VaList; + +// Ensure that we do not remove the `va_list` passed to the foreign function when +// removing the "spoofed" `VaList` that is used by Rust defined C-variadics. + +extern "C" { + fn foreign_c_variadic_1(_: VaList, ...); +} + +// CHECK-LABEL: use_foreign_c_variadic_1_0 +pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) { + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap) + foreign_c_variadic_1(ap); +} + +// CHECK-LABEL: use_foreign_c_variadic_1_1 +pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) { + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef 42) + foreign_c_variadic_1(ap, 42i32); +} +pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) { + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef 2, i32 noundef 42) + foreign_c_variadic_1(ap, 2i32, 42i32); +} + +pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) { + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef 2, i32 noundef 42, i32 noundef 0) + foreign_c_variadic_1(ap, 2i32, 42i32, 0i32); +} diff --git a/tests/codegen-llvm/cffi/c-variadic.rs b/tests/codegen-llvm/cffi/c-variadic.rs index 3ce421eb4a5c..7a2e2ba5047e 100644 --- a/tests/codegen-llvm/cffi/c-variadic.rs +++ b/tests/codegen-llvm/cffi/c-variadic.rs @@ -9,7 +9,6 @@ extern "C" { fn foreign_c_variadic_0(_: i32, ...); - fn foreign_c_variadic_1(_: VaList, ...); } pub unsafe extern "C" fn use_foreign_c_variadic_0() { @@ -24,27 +23,6 @@ foreign_c_variadic_0(0, 42i32, 1024i32, 0i32); } -// Ensure that we do not remove the `va_list` passed to the foreign function when -// removing the "spoofed" `VaList` that is used by Rust defined C-variadics. -pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %0) - foreign_c_variadic_1(ap); -} - -pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %0, [[PARAM]] 42) - foreign_c_variadic_1(ap, 42i32); -} -pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %0, [[PARAM]] 2, [[PARAM]] 42) - foreign_c_variadic_1(ap, 2i32, 42i32); -} - -pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %0, [[PARAM]] 2, [[PARAM]] 42, [[PARAM]] 0) - foreign_c_variadic_1(ap, 2i32, 42i32, 0i32); -} - // Ensure that `va_start` and `va_end` are properly injected. #[no_mangle] pub unsafe extern "C" fn c_variadic(n: i32, mut ap: ...) -> i32 { From 88c2c81848019c6f7fc4d98984d53d989e2d5c0b Mon Sep 17 00:00:00 2001 From: Roy Ammerschuber Date: Wed, 3 Dec 2025 12:08:01 +0100 Subject: [PATCH 314/585] factor out tree_visitor into own file --- .../src/borrow_tracker/tree_borrows/mod.rs | 1 + .../src/borrow_tracker/tree_borrows/tree.rs | 301 +----------------- .../tree_borrows/tree_visitor.rs | 286 +++++++++++++++++ 3 files changed, 296 insertions(+), 292 deletions(-) create mode 100644 src/tools/miri/src/borrow_tracker/tree_borrows/tree_visitor.rs diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index e1da12282cd9..018421ad1064 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -13,6 +13,7 @@ mod foreign_access_skipping; mod perms; mod tree; +mod tree_visitor; mod unimap; mod wildcard; diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 7fc9fa786e10..3532e2e0ba86 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -18,15 +18,16 @@ use rustc_span::Span; use smallvec::SmallVec; -use super::diagnostics::AccessCause; -use super::wildcard::WildcardState; -use crate::borrow_tracker::tree_borrows::Permission; -use crate::borrow_tracker::tree_borrows::diagnostics::{ - self, NodeDebugInfo, TbError, TransitionError, no_valid_exposed_references_error, +use super::Permission; +use super::diagnostics::{ + self, AccessCause, NodeDebugInfo, TbError, TransitionError, + no_valid_exposed_references_error, }; -use crate::borrow_tracker::tree_borrows::foreign_access_skipping::IdempotentForeignAccess; -use crate::borrow_tracker::tree_borrows::perms::PermTransition; -use crate::borrow_tracker::tree_borrows::unimap::{UniIndex, UniKeyMap, UniValMap}; +use super::foreign_access_skipping::IdempotentForeignAccess; +use super::perms::PermTransition; +use super::tree_visitor::{ChildrenVisitMode, ContinueTraversal, NodeAppArgs, TreeVisitor}; +use super::unimap::{UniIndex, UniKeyMap, UniValMap}; +use super::wildcard::WildcardState; use crate::borrow_tracker::{AccessKind, GlobalState, ProtectorKind}; use crate::*; @@ -339,290 +340,6 @@ pub(super) struct Node { pub debug_info: NodeDebugInfo, } -/// Data given to the transition function -struct NodeAppArgs<'visit> { - /// The index of the current node. - idx: UniIndex, - /// Relative position of the access. - rel_pos: AccessRelatedness, - /// The node map of this tree. - nodes: &'visit mut UniValMap, - /// The permissions map of this tree. - loc: &'visit mut LocationTree, -} -/// Internal contents of `Tree` with the minimum of mutable access for -/// For soundness do not modify the children or parent indexes of nodes -/// during traversal. -struct TreeVisitor<'tree> { - nodes: &'tree mut UniValMap, - loc: &'tree mut LocationTree, -} - -/// Whether to continue exploring the children recursively or not. -#[derive(Debug)] -enum ContinueTraversal { - Recurse, - SkipSelfAndChildren, -} - -#[derive(Clone, Copy, Debug)] -pub enum ChildrenVisitMode { - VisitChildrenOfAccessed, - SkipChildrenOfAccessed, -} - -enum RecursionState { - BeforeChildren, - AfterChildren, -} - -/// Stack of nodes left to explore in a tree traversal. -/// See the docs of `traverse_this_parents_children_other` for details on the -/// traversal order. -struct TreeVisitorStack { - /// Function describing whether to continue at a tag. - /// This is only invoked for foreign accesses. - f_continue: NodeContinue, - /// Function to apply to each tag. - f_propagate: NodeApp, - /// Mutable state of the visit: the tags left to handle. - /// Every tag pushed should eventually be handled, - /// and the precise order is relevant for diagnostics. - /// Since the traversal is piecewise bottom-up, we need to - /// remember whether we're here initially, or after visiting all children. - /// The last element indicates this. - /// This is just an artifact of how you hand-roll recursion, - /// it does not have a deeper meaning otherwise. - stack: Vec<(UniIndex, AccessRelatedness, RecursionState)>, -} - -impl TreeVisitorStack -where - NodeContinue: Fn(&NodeAppArgs<'_>) -> ContinueTraversal, - NodeApp: FnMut(NodeAppArgs<'_>) -> Result<(), Err>, -{ - fn should_continue_at( - &self, - this: &mut TreeVisitor<'_>, - idx: UniIndex, - rel_pos: AccessRelatedness, - ) -> ContinueTraversal { - let args = NodeAppArgs { idx, rel_pos, nodes: this.nodes, loc: this.loc }; - (self.f_continue)(&args) - } - - fn propagate_at( - &mut self, - this: &mut TreeVisitor<'_>, - idx: UniIndex, - rel_pos: AccessRelatedness, - ) -> Result<(), Err> { - (self.f_propagate)(NodeAppArgs { idx, rel_pos, nodes: this.nodes, loc: this.loc }) - } - - /// Returns the root of this tree. - fn go_upwards_from_accessed( - &mut self, - this: &mut TreeVisitor<'_>, - accessed_node: UniIndex, - visit_children: ChildrenVisitMode, - ) -> Result { - // We want to visit the accessed node's children first. - // However, we will below walk up our parents and push their children (our cousins) - // onto the stack. To ensure correct iteration order, this method thus finishes - // by reversing the stack. This only works if the stack is empty initially. - assert!(self.stack.is_empty()); - // First, handle accessed node. A bunch of things need to - // be handled differently here compared to the further parents - // of `accesssed_node`. - { - self.propagate_at(this, accessed_node, AccessRelatedness::LocalAccess)?; - if matches!(visit_children, ChildrenVisitMode::VisitChildrenOfAccessed) { - let accessed_node = this.nodes.get(accessed_node).unwrap(); - // We `rev()` here because we reverse the entire stack later. - for &child in accessed_node.children.iter().rev() { - self.stack.push(( - child, - AccessRelatedness::ForeignAccess, - RecursionState::BeforeChildren, - )); - } - } - } - // Then, handle the accessed node's parents. Here, we need to - // make sure we only mark the "cousin" subtrees for later visitation, - // not the subtree that contains the accessed node. - let mut last_node = accessed_node; - while let Some(current) = this.nodes.get(last_node).unwrap().parent { - self.propagate_at(this, current, AccessRelatedness::LocalAccess)?; - let node = this.nodes.get(current).unwrap(); - // We `rev()` here because we reverse the entire stack later. - for &child in node.children.iter().rev() { - if last_node == child { - continue; - } - self.stack.push(( - child, - AccessRelatedness::ForeignAccess, - RecursionState::BeforeChildren, - )); - } - last_node = current; - } - // Reverse the stack, as discussed above. - self.stack.reverse(); - Ok(last_node) - } - - fn finish_foreign_accesses(&mut self, this: &mut TreeVisitor<'_>) -> Result<(), Err> { - while let Some((idx, rel_pos, step)) = self.stack.last_mut() { - let idx = *idx; - let rel_pos = *rel_pos; - match *step { - // How to do bottom-up traversal, 101: Before you handle a node, you handle all children. - // For this, you must first find the children, which is what this code here does. - RecursionState::BeforeChildren => { - // Next time we come back will be when all the children are handled. - *step = RecursionState::AfterChildren; - // Now push the children, except if we are told to skip this subtree. - let handle_children = self.should_continue_at(this, idx, rel_pos); - match handle_children { - ContinueTraversal::Recurse => { - let node = this.nodes.get(idx).unwrap(); - for &child in node.children.iter() { - self.stack.push((child, rel_pos, RecursionState::BeforeChildren)); - } - } - ContinueTraversal::SkipSelfAndChildren => { - // skip self - self.stack.pop(); - continue; - } - } - } - // All the children are handled, let's actually visit this node - RecursionState::AfterChildren => { - self.stack.pop(); - self.propagate_at(this, idx, rel_pos)?; - } - } - } - Ok(()) - } - - fn new(f_continue: NodeContinue, f_propagate: NodeApp) -> Self { - Self { f_continue, f_propagate, stack: Vec::new() } - } -} - -impl<'tree> TreeVisitor<'tree> { - /// Applies `f_propagate` to every vertex of the tree in a piecewise bottom-up way: First, visit - /// all ancestors of `start_idx` (starting with `start_idx` itself), then children of `start_idx`, then the rest, - /// going bottom-up in each of these two "pieces" / sections. - /// This ensures that errors are triggered in the following order - /// - first invalid accesses with insufficient permissions, closest to the accessed node first, - /// - then protector violations, bottom-up, starting with the children of the accessed node, and then - /// going upwards and outwards. - /// - /// The following graphic visualizes it, with numbers indicating visitation order and `start_idx` being - /// the node that is visited first ("1"): - /// - /// ```text - /// 3 - /// /| - /// / | - /// 9 2 - /// | |\ - /// | | \ - /// 8 1 7 - /// / \ - /// 4 6 - /// | - /// 5 - /// ``` - /// - /// `f_propagate` should follow the following format: for a given `Node` it updates its - /// `Permission` depending on the position relative to `start_idx` (given by an - /// `AccessRelatedness`). - /// `f_continue` is called earlier on foreign nodes, and describes whether to even start - /// visiting the subtree at that node. If it e.g. returns `SkipSelfAndChildren` on node 6 - /// above, then nodes 5 _and_ 6 would not be visited by `f_propagate`. It is not used for - /// notes having a child access (nodes 1, 2, 3). - /// - /// Finally, remember that the iteration order is not relevant for UB, it only affects - /// diagnostics. It also affects tree traversal optimizations built on top of this, so - /// those need to be reviewed carefully as well whenever this changes. - /// - /// Returns the index of the root of the accessed tree. - fn traverse_this_parents_children_other( - mut self, - start_idx: UniIndex, - f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal, - f_propagate: impl FnMut(NodeAppArgs<'_>) -> Result<(), Err>, - ) -> Result { - let mut stack = TreeVisitorStack::new(f_continue, f_propagate); - // Visits the accessed node itself, and all its parents, i.e. all nodes - // undergoing a child access. Also pushes the children and the other - // cousin nodes (i.e. all nodes undergoing a foreign access) to the stack - // to be processed later. - let root = stack.go_upwards_from_accessed( - &mut self, - start_idx, - ChildrenVisitMode::VisitChildrenOfAccessed, - )?; - // Now visit all the foreign nodes we remembered earlier. - // For this we go bottom-up, but also allow f_continue to skip entire - // subtrees from being visited if it would be a NOP. - stack.finish_foreign_accesses(&mut self)?; - Ok(root) - } - - /// Like `traverse_this_parents_children_other`, but skips the children of `start_idx`. - /// - /// Returns the index of the root of the accessed tree. - fn traverse_nonchildren( - mut self, - start_idx: UniIndex, - f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal, - f_propagate: impl FnMut(NodeAppArgs<'_>) -> Result<(), Err>, - ) -> Result { - let mut stack = TreeVisitorStack::new(f_continue, f_propagate); - // Visits the accessed node itself, and all its parents, i.e. all nodes - // undergoing a child access. Also pushes the other cousin nodes to the - // stack, but not the children of the accessed node. - let root = stack.go_upwards_from_accessed( - &mut self, - start_idx, - ChildrenVisitMode::SkipChildrenOfAccessed, - )?; - // Now visit all the foreign nodes we remembered earlier. - // For this we go bottom-up, but also allow f_continue to skip entire - // subtrees from being visited if it would be a NOP. - stack.finish_foreign_accesses(&mut self)?; - Ok(root) - } - - /// Traverses all children of `start_idx` including `start_idx` itself. - /// Uses `f_continue` to filter out subtrees and then processes each node - /// with `f_propagate` so that the children get processed before their - /// parents. - fn traverse_children_this( - mut self, - start_idx: UniIndex, - f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal, - f_propagate: impl FnMut(NodeAppArgs<'_>) -> Result<(), Err>, - ) -> Result<(), Err> { - let mut stack = TreeVisitorStack::new(f_continue, f_propagate); - - stack.stack.push(( - start_idx, - AccessRelatedness::ForeignAccess, - RecursionState::BeforeChildren, - )); - stack.finish_foreign_accesses(&mut self) - } -} - impl Tree { /// Create a new tree, with only a root pointer. pub fn new(root_tag: BorTag, size: Size, span: Span) -> Self { diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree_visitor.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree_visitor.rs new file mode 100644 index 000000000000..aa9df89180b8 --- /dev/null +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree_visitor.rs @@ -0,0 +1,286 @@ +use super::tree::{AccessRelatedness, LocationTree, Node}; +use super::unimap::{UniIndex, UniValMap}; + +/// Data given to the transition function +pub struct NodeAppArgs<'visit> { + /// The index of the current node. + pub idx: UniIndex, + /// Relative position of the access. + pub rel_pos: AccessRelatedness, + /// The node map of this tree. + pub nodes: &'visit mut UniValMap, + /// The permissions map of this tree. + pub loc: &'visit mut LocationTree, +} +/// Internal contents of `Tree` with the minimum of mutable access for +/// For soundness do not modify the children or parent indexes of nodes +/// during traversal. +pub struct TreeVisitor<'tree> { + pub nodes: &'tree mut UniValMap, + pub loc: &'tree mut LocationTree, +} + +/// Whether to continue exploring the children recursively or not. +#[derive(Debug)] +pub enum ContinueTraversal { + Recurse, + SkipSelfAndChildren, +} + +#[derive(Clone, Copy, Debug)] +pub enum ChildrenVisitMode { + VisitChildrenOfAccessed, + SkipChildrenOfAccessed, +} + +enum RecursionState { + BeforeChildren, + AfterChildren, +} + +/// Stack of nodes left to explore in a tree traversal. +/// See the docs of `traverse_this_parents_children_other` for details on the +/// traversal order. +struct TreeVisitorStack { + /// Function describing whether to continue at a tag. + /// This is only invoked for foreign accesses. + f_continue: NodeContinue, + /// Function to apply to each tag. + f_propagate: NodeApp, + /// Mutable state of the visit: the tags left to handle. + /// Every tag pushed should eventually be handled, + /// and the precise order is relevant for diagnostics. + /// Since the traversal is piecewise bottom-up, we need to + /// remember whether we're here initially, or after visiting all children. + /// The last element indicates this. + /// This is just an artifact of how you hand-roll recursion, + /// it does not have a deeper meaning otherwise. + stack: Vec<(UniIndex, AccessRelatedness, RecursionState)>, +} + +impl TreeVisitorStack +where + NodeContinue: Fn(&NodeAppArgs<'_>) -> ContinueTraversal, + NodeApp: FnMut(NodeAppArgs<'_>) -> Result<(), Err>, +{ + fn should_continue_at( + &self, + this: &mut TreeVisitor<'_>, + idx: UniIndex, + rel_pos: AccessRelatedness, + ) -> ContinueTraversal { + let args = NodeAppArgs { idx, rel_pos, nodes: this.nodes, loc: this.loc }; + (self.f_continue)(&args) + } + + fn propagate_at( + &mut self, + this: &mut TreeVisitor<'_>, + idx: UniIndex, + rel_pos: AccessRelatedness, + ) -> Result<(), Err> { + (self.f_propagate)(NodeAppArgs { idx, rel_pos, nodes: this.nodes, loc: this.loc }) + } + + /// Returns the root of this tree. + fn go_upwards_from_accessed( + &mut self, + this: &mut TreeVisitor<'_>, + accessed_node: UniIndex, + visit_children: ChildrenVisitMode, + ) -> Result { + // We want to visit the accessed node's children first. + // However, we will below walk up our parents and push their children (our cousins) + // onto the stack. To ensure correct iteration order, this method thus finishes + // by reversing the stack. This only works if the stack is empty initially. + assert!(self.stack.is_empty()); + // First, handle accessed node. A bunch of things need to + // be handled differently here compared to the further parents + // of `accesssed_node`. + { + self.propagate_at(this, accessed_node, AccessRelatedness::LocalAccess)?; + if matches!(visit_children, ChildrenVisitMode::VisitChildrenOfAccessed) { + let accessed_node = this.nodes.get(accessed_node).unwrap(); + // We `rev()` here because we reverse the entire stack later. + for &child in accessed_node.children.iter().rev() { + self.stack.push(( + child, + AccessRelatedness::ForeignAccess, + RecursionState::BeforeChildren, + )); + } + } + } + // Then, handle the accessed node's parents. Here, we need to + // make sure we only mark the "cousin" subtrees for later visitation, + // not the subtree that contains the accessed node. + let mut last_node = accessed_node; + while let Some(current) = this.nodes.get(last_node).unwrap().parent { + self.propagate_at(this, current, AccessRelatedness::LocalAccess)?; + let node = this.nodes.get(current).unwrap(); + // We `rev()` here because we reverse the entire stack later. + for &child in node.children.iter().rev() { + if last_node == child { + continue; + } + self.stack.push(( + child, + AccessRelatedness::ForeignAccess, + RecursionState::BeforeChildren, + )); + } + last_node = current; + } + // Reverse the stack, as discussed above. + self.stack.reverse(); + Ok(last_node) + } + + fn finish_foreign_accesses(&mut self, this: &mut TreeVisitor<'_>) -> Result<(), Err> { + while let Some((idx, rel_pos, step)) = self.stack.last_mut() { + let idx = *idx; + let rel_pos = *rel_pos; + match *step { + // How to do bottom-up traversal, 101: Before you handle a node, you handle all children. + // For this, you must first find the children, which is what this code here does. + RecursionState::BeforeChildren => { + // Next time we come back will be when all the children are handled. + *step = RecursionState::AfterChildren; + // Now push the children, except if we are told to skip this subtree. + let handle_children = self.should_continue_at(this, idx, rel_pos); + match handle_children { + ContinueTraversal::Recurse => { + let node = this.nodes.get(idx).unwrap(); + for &child in node.children.iter() { + self.stack.push((child, rel_pos, RecursionState::BeforeChildren)); + } + } + ContinueTraversal::SkipSelfAndChildren => { + // skip self + self.stack.pop(); + continue; + } + } + } + // All the children are handled, let's actually visit this node + RecursionState::AfterChildren => { + self.stack.pop(); + self.propagate_at(this, idx, rel_pos)?; + } + } + } + Ok(()) + } + + fn new(f_continue: NodeContinue, f_propagate: NodeApp) -> Self { + Self { f_continue, f_propagate, stack: Vec::new() } + } +} + +impl<'tree> TreeVisitor<'tree> { + /// Applies `f_propagate` to every vertex of the tree in a piecewise bottom-up way: First, visit + /// all ancestors of `start_idx` (starting with `start_idx` itself), then children of `start_idx`, then the rest, + /// going bottom-up in each of these two "pieces" / sections. + /// This ensures that errors are triggered in the following order + /// - first invalid accesses with insufficient permissions, closest to the accessed node first, + /// - then protector violations, bottom-up, starting with the children of the accessed node, and then + /// going upwards and outwards. + /// + /// The following graphic visualizes it, with numbers indicating visitation order and `start_idx` being + /// the node that is visited first ("1"): + /// + /// ```text + /// 3 + /// /| + /// / | + /// 9 2 + /// | |\ + /// | | \ + /// 8 1 7 + /// / \ + /// 4 6 + /// | + /// 5 + /// ``` + /// + /// `f_propagate` should follow the following format: for a given `Node` it updates its + /// `Permission` depending on the position relative to `start_idx` (given by an + /// `AccessRelatedness`). + /// `f_continue` is called earlier on foreign nodes, and describes whether to even start + /// visiting the subtree at that node. If it e.g. returns `SkipSelfAndChildren` on node 6 + /// above, then nodes 5 _and_ 6 would not be visited by `f_propagate`. It is not used for + /// notes having a child access (nodes 1, 2, 3). + /// + /// Finally, remember that the iteration order is not relevant for UB, it only affects + /// diagnostics. It also affects tree traversal optimizations built on top of this, so + /// those need to be reviewed carefully as well whenever this changes. + /// + /// Returns the index of the root of the accessed tree. + pub fn traverse_this_parents_children_other( + mut self, + start_idx: UniIndex, + f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal, + f_propagate: impl FnMut(NodeAppArgs<'_>) -> Result<(), Err>, + ) -> Result { + let mut stack = TreeVisitorStack::new(f_continue, f_propagate); + // Visits the accessed node itself, and all its parents, i.e. all nodes + // undergoing a child access. Also pushes the children and the other + // cousin nodes (i.e. all nodes undergoing a foreign access) to the stack + // to be processed later. + let root = stack.go_upwards_from_accessed( + &mut self, + start_idx, + ChildrenVisitMode::VisitChildrenOfAccessed, + )?; + // Now visit all the foreign nodes we remembered earlier. + // For this we go bottom-up, but also allow f_continue to skip entire + // subtrees from being visited if it would be a NOP. + stack.finish_foreign_accesses(&mut self)?; + Ok(root) + } + + /// Like `traverse_this_parents_children_other`, but skips the children of `start_idx`. + /// + /// Returns the index of the root of the accessed tree. + pub fn traverse_nonchildren( + mut self, + start_idx: UniIndex, + f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal, + f_propagate: impl FnMut(NodeAppArgs<'_>) -> Result<(), Err>, + ) -> Result { + let mut stack = TreeVisitorStack::new(f_continue, f_propagate); + // Visits the accessed node itself, and all its parents, i.e. all nodes + // undergoing a child access. Also pushes the other cousin nodes to the + // stack, but not the children of the accessed node. + let root = stack.go_upwards_from_accessed( + &mut self, + start_idx, + ChildrenVisitMode::SkipChildrenOfAccessed, + )?; + // Now visit all the foreign nodes we remembered earlier. + // For this we go bottom-up, but also allow f_continue to skip entire + // subtrees from being visited if it would be a NOP. + stack.finish_foreign_accesses(&mut self)?; + Ok(root) + } + + /// Traverses all children of `start_idx` including `start_idx` itself. + /// Uses `f_continue` to filter out subtrees and then processes each node + /// with `f_propagate` so that the children get processed before their + /// parents. + pub fn traverse_children_this( + mut self, + start_idx: UniIndex, + f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal, + f_propagate: impl FnMut(NodeAppArgs<'_>) -> Result<(), Err>, + ) -> Result<(), Err> { + let mut stack = TreeVisitorStack::new(f_continue, f_propagate); + + stack.stack.push(( + start_idx, + AccessRelatedness::ForeignAccess, + RecursionState::BeforeChildren, + )); + stack.finish_foreign_accesses(&mut self) + } +} From 9622840f78198719da51fc1d3307086865cae5e0 Mon Sep 17 00:00:00 2001 From: Roy Ammerschuber Date: Wed, 3 Dec 2025 12:40:08 +0100 Subject: [PATCH 315/585] make tree_visitor generic --- .../src/borrow_tracker/tree_borrows/tree.rs | 96 +++++++++---------- .../tree_borrows/tree_visitor.rs | 51 +++++----- 2 files changed, 75 insertions(+), 72 deletions(-) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 3532e2e0ba86..ca68dc891020 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -20,8 +20,7 @@ use super::Permission; use super::diagnostics::{ - self, AccessCause, NodeDebugInfo, TbError, TransitionError, - no_valid_exposed_references_error, + self, AccessCause, NodeDebugInfo, TbError, TransitionError, no_valid_exposed_references_error, }; use super::foreign_access_skipping::IdempotentForeignAccess; use super::perms::PermTransition; @@ -562,42 +561,43 @@ pub fn dealloc( // Checks the tree containing `idx` for strong protector violations. // It does this in traversal order. let mut check_tree = |idx| { - TreeVisitor { nodes: &mut self.nodes, loc }.traverse_this_parents_children_other( - idx, - // Visit all children, skipping none. - |_| ContinueTraversal::Recurse, - |args: NodeAppArgs<'_>| { - let node = args.nodes.get(args.idx).unwrap(); + TreeVisitor { nodes: &mut self.nodes, data: loc } + .traverse_this_parents_children_other( + idx, + // Visit all children, skipping none. + |_| ContinueTraversal::Recurse, + |args: NodeAppArgs<'_, _>| { + let node = args.nodes.get(args.idx).unwrap(); - let perm = args - .loc - .perms - .get(args.idx) - .copied() - .unwrap_or_else(|| node.default_location_state()); - if global.borrow().protected_tags.get(&node.tag) - == Some(&ProtectorKind::StrongProtector) - // Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`). - // Related to https://github.com/rust-lang/rust/issues/55005. - && !perm.permission.is_cell() - // Only trigger UB if the accessed bit is set, i.e. if the protector is actually protecting this offset. See #4579. - && perm.accessed - { - Err(TbError { - conflicting_info: &node.debug_info, - access_cause: diagnostics::AccessCause::Dealloc, - alloc_id, - error_offset: loc_range.start, - error_kind: TransitionError::ProtectedDealloc, - accessed_info: start_idx - .map(|idx| &args.nodes.get(idx).unwrap().debug_info), + let perm = args + .data + .perms + .get(args.idx) + .copied() + .unwrap_or_else(|| node.default_location_state()); + if global.borrow().protected_tags.get(&node.tag) + == Some(&ProtectorKind::StrongProtector) + // Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`). + // Related to https://github.com/rust-lang/rust/issues/55005. + && !perm.permission.is_cell() + // Only trigger UB if the accessed bit is set, i.e. if the protector is actually protecting this offset. See #4579. + && perm.accessed + { + Err(TbError { + conflicting_info: &node.debug_info, + access_cause: diagnostics::AccessCause::Dealloc, + alloc_id, + error_offset: loc_range.start, + error_kind: TransitionError::ProtectedDealloc, + accessed_info: start_idx + .map(|idx| &args.nodes.get(idx).unwrap().debug_info), + } + .build()) + } else { + Ok(()) } - .build()) - } else { - Ok(()) - } - }, - ) + }, + ) }; // If we have a start index we first check its subtree in traversal order. // This results in us showing the error of the closest node instead of an @@ -967,16 +967,16 @@ fn perform_normal_access( // // `loc_range` is only for diagnostics (it is the range of // the `RangeMap` on which we are currently working). - let node_skipper = |args: &NodeAppArgs<'_>| -> ContinueTraversal { + let node_skipper = |args: &NodeAppArgs<'_, LocationTree>| -> ContinueTraversal { let node = args.nodes.get(args.idx).unwrap(); - let perm = args.loc.perms.get(args.idx); + let perm = args.data.perms.get(args.idx); let old_state = perm.copied().unwrap_or_else(|| node.default_location_state()); old_state.skip_if_known_noop(access_kind, args.rel_pos) }; - let node_app = |args: NodeAppArgs<'_>| { + let node_app = |args: NodeAppArgs<'_, LocationTree>| { let node = args.nodes.get_mut(args.idx).unwrap(); - let mut perm = args.loc.perms.entry(args.idx); + let mut perm = args.data.perms.entry(args.idx); let state = perm.or_insert(node.default_location_state()); @@ -985,7 +985,7 @@ fn perform_normal_access( .perform_transition( args.idx, args.nodes, - &mut args.loc.wildcard_accesses, + &mut args.data.wildcard_accesses, access_kind, access_cause, access_range, @@ -1007,7 +1007,7 @@ fn perform_normal_access( }) }; - let visitor = TreeVisitor { nodes, loc: self }; + let visitor = TreeVisitor { nodes, data: self }; match visit_children { ChildrenVisitMode::VisitChildrenOfAccessed => visitor.traverse_this_parents_children_other(access_source, node_skipper, node_app), @@ -1061,16 +1061,16 @@ fn perform_wildcard_access( // marked as having an exposed foreign node, but actually that foreign node cannot be // the source of the access due to `max_local_tag`. The wildcard tracking cannot know // about `max_local_tag` so we will incorrectly assume that this might be a foreign access. - TreeVisitor { loc: self, nodes }.traverse_children_this( + TreeVisitor { data: self, nodes }.traverse_children_this( root, |args| -> ContinueTraversal { let node = args.nodes.get(args.idx).unwrap(); - let perm = args.loc.perms.get(args.idx); + let perm = args.data.perms.get(args.idx); let old_state = perm.copied().unwrap_or_else(|| node.default_location_state()); // If we know where, relative to this node, the wildcard access occurs, // then check if we can skip the entire subtree. - if let Some(relatedness) = get_relatedness(args.idx, node, args.loc) + if let Some(relatedness) = get_relatedness(args.idx, node, args.data) && let Some(relatedness) = relatedness.to_relatedness() { // We can use the usual SIFA machinery to skip nodes. @@ -1084,7 +1084,7 @@ fn perform_wildcard_access( let protected = global.borrow().protected_tags.contains_key(&node.tag); - let Some(wildcard_relatedness) = get_relatedness(args.idx, node, args.loc) else { + let Some(wildcard_relatedness) = get_relatedness(args.idx, node, args.data) else { // There doesn't exist a valid exposed reference for this access to // happen through. // This can only happen if `root` is the main root: We set @@ -1105,13 +1105,13 @@ fn perform_wildcard_access( return Ok(()); }; - let mut entry = args.loc.perms.entry(args.idx); + let mut entry = args.data.perms.entry(args.idx); let perm = entry.or_insert(node.default_location_state()); // We know the exact relatedness, so we can actually do precise checks. perm.perform_transition( args.idx, args.nodes, - &mut args.loc.wildcard_accesses, + &mut args.data.wildcard_accesses, access_kind, access_cause, access_range, diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree_visitor.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree_visitor.rs index aa9df89180b8..b1ceeecf577d 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree_visitor.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree_visitor.rs @@ -1,23 +1,25 @@ -use super::tree::{AccessRelatedness, LocationTree, Node}; +use std::marker::PhantomData; + +use super::tree::{AccessRelatedness, Node}; use super::unimap::{UniIndex, UniValMap}; /// Data given to the transition function -pub struct NodeAppArgs<'visit> { +pub struct NodeAppArgs<'visit, T> { /// The index of the current node. pub idx: UniIndex, /// Relative position of the access. pub rel_pos: AccessRelatedness, /// The node map of this tree. pub nodes: &'visit mut UniValMap, - /// The permissions map of this tree. - pub loc: &'visit mut LocationTree, + /// Additional data we want to be able to modify in f_propagate and read in f_continue. + pub data: &'visit mut T, } /// Internal contents of `Tree` with the minimum of mutable access for /// For soundness do not modify the children or parent indexes of nodes /// during traversal. -pub struct TreeVisitor<'tree> { +pub struct TreeVisitor<'tree, T> { pub nodes: &'tree mut UniValMap, - pub loc: &'tree mut LocationTree, + pub data: &'tree mut T, } /// Whether to continue exploring the children recursively or not. @@ -41,7 +43,7 @@ enum RecursionState { /// Stack of nodes left to explore in a tree traversal. /// See the docs of `traverse_this_parents_children_other` for details on the /// traversal order. -struct TreeVisitorStack { +struct TreeVisitorStack { /// Function describing whether to continue at a tag. /// This is only invoked for foreign accesses. f_continue: NodeContinue, @@ -56,36 +58,37 @@ struct TreeVisitorStack { /// This is just an artifact of how you hand-roll recursion, /// it does not have a deeper meaning otherwise. stack: Vec<(UniIndex, AccessRelatedness, RecursionState)>, + phantom: PhantomData, } -impl TreeVisitorStack +impl TreeVisitorStack where - NodeContinue: Fn(&NodeAppArgs<'_>) -> ContinueTraversal, - NodeApp: FnMut(NodeAppArgs<'_>) -> Result<(), Err>, + NodeContinue: Fn(&NodeAppArgs<'_, T>) -> ContinueTraversal, + NodeApp: FnMut(NodeAppArgs<'_, T>) -> Result<(), Err>, { fn should_continue_at( &self, - this: &mut TreeVisitor<'_>, + this: &mut TreeVisitor<'_, T>, idx: UniIndex, rel_pos: AccessRelatedness, ) -> ContinueTraversal { - let args = NodeAppArgs { idx, rel_pos, nodes: this.nodes, loc: this.loc }; + let args = NodeAppArgs { idx, rel_pos, nodes: this.nodes, data: this.data }; (self.f_continue)(&args) } fn propagate_at( &mut self, - this: &mut TreeVisitor<'_>, + this: &mut TreeVisitor<'_, T>, idx: UniIndex, rel_pos: AccessRelatedness, ) -> Result<(), Err> { - (self.f_propagate)(NodeAppArgs { idx, rel_pos, nodes: this.nodes, loc: this.loc }) + (self.f_propagate)(NodeAppArgs { idx, rel_pos, nodes: this.nodes, data: this.data }) } /// Returns the root of this tree. fn go_upwards_from_accessed( &mut self, - this: &mut TreeVisitor<'_>, + this: &mut TreeVisitor<'_, T>, accessed_node: UniIndex, visit_children: ChildrenVisitMode, ) -> Result { @@ -136,7 +139,7 @@ fn go_upwards_from_accessed( Ok(last_node) } - fn finish_foreign_accesses(&mut self, this: &mut TreeVisitor<'_>) -> Result<(), Err> { + fn finish_foreign_accesses(&mut self, this: &mut TreeVisitor<'_, T>) -> Result<(), Err> { while let Some((idx, rel_pos, step)) = self.stack.last_mut() { let idx = *idx; let rel_pos = *rel_pos; @@ -173,11 +176,11 @@ fn finish_foreign_accesses(&mut self, this: &mut TreeVisitor<'_>) -> Result<(), } fn new(f_continue: NodeContinue, f_propagate: NodeApp) -> Self { - Self { f_continue, f_propagate, stack: Vec::new() } + Self { f_continue, f_propagate, stack: Vec::new(), phantom: PhantomData } } } -impl<'tree> TreeVisitor<'tree> { +impl<'tree, T> TreeVisitor<'tree, T> { /// Applies `f_propagate` to every vertex of the tree in a piecewise bottom-up way: First, visit /// all ancestors of `start_idx` (starting with `start_idx` itself), then children of `start_idx`, then the rest, /// going bottom-up in each of these two "pieces" / sections. @@ -219,8 +222,8 @@ impl<'tree> TreeVisitor<'tree> { pub fn traverse_this_parents_children_other( mut self, start_idx: UniIndex, - f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal, - f_propagate: impl FnMut(NodeAppArgs<'_>) -> Result<(), Err>, + f_continue: impl Fn(&NodeAppArgs<'_, T>) -> ContinueTraversal, + f_propagate: impl FnMut(NodeAppArgs<'_, T>) -> Result<(), Err>, ) -> Result { let mut stack = TreeVisitorStack::new(f_continue, f_propagate); // Visits the accessed node itself, and all its parents, i.e. all nodes @@ -245,8 +248,8 @@ pub fn traverse_this_parents_children_other( pub fn traverse_nonchildren( mut self, start_idx: UniIndex, - f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal, - f_propagate: impl FnMut(NodeAppArgs<'_>) -> Result<(), Err>, + f_continue: impl Fn(&NodeAppArgs<'_, T>) -> ContinueTraversal, + f_propagate: impl FnMut(NodeAppArgs<'_, T>) -> Result<(), Err>, ) -> Result { let mut stack = TreeVisitorStack::new(f_continue, f_propagate); // Visits the accessed node itself, and all its parents, i.e. all nodes @@ -271,8 +274,8 @@ pub fn traverse_nonchildren( pub fn traverse_children_this( mut self, start_idx: UniIndex, - f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal, - f_propagate: impl FnMut(NodeAppArgs<'_>) -> Result<(), Err>, + f_continue: impl Fn(&NodeAppArgs<'_, T>) -> ContinueTraversal, + f_propagate: impl FnMut(NodeAppArgs<'_, T>) -> Result<(), Err>, ) -> Result<(), Err> { let mut stack = TreeVisitorStack::new(f_continue, f_propagate); From 1b71459736bdf6f3a4b9401ab5ed236c066f2865 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 12 Nov 2025 11:57:00 +0100 Subject: [PATCH 316/585] emit WF goals in relate, not in generalize --- .../src/polonius/liveness_constraints.rs | 19 ++- .../src/type_check/relate_tys.rs | 27 +++- .../src/infer/outlives/test_type_match.rs | 20 +++ .../src/infer/relate/generalize.rs | 118 +++++------------- .../rustc_infer/src/infer/relate/lattice.rs | 16 ++- .../src/infer/relate/type_relating.rs | 28 +++-- .../rustc_lint/src/impl_trait_overcaptures.rs | 17 ++- .../src/error_reporting/infer/mod.rs | 13 ++ .../src/traits/select/_match.rs | 14 +++ compiler/rustc_type_ir/src/relate.rs | 68 ++++------ compiler/rustc_type_ir/src/relate/combine.rs | 75 +++++++++++ .../src/relate/solver_relating.rs | 23 ++-- .../subtype-obligations-bivariant-args.rs | 52 ++++++++ 13 files changed, 335 insertions(+), 155 deletions(-) create mode 100644 tests/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.rs diff --git a/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs b/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs index 2ba72180d66a..f1338b3bf1ee 100644 --- a/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs +++ b/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs @@ -1,8 +1,11 @@ use std::collections::BTreeMap; +use rustc_hir::def_id::DefId; use rustc_index::bit_set::SparseBitMatrix; use rustc_middle::mir::{Body, Location}; -use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::relate::{ + self, Relate, RelateResult, TypeRelation, relate_args_with_variances, +}; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable}; use rustc_mir_dataflow::points::PointIndex; @@ -256,6 +259,20 @@ fn cx(&self) -> TyCtxt<'tcx> { self.tcx } + fn relate_ty_args( + &mut self, + a_ty: Ty<'tcx>, + _: Ty<'tcx>, + def_id: DefId, + a_args: ty::GenericArgsRef<'tcx>, + b_args: ty::GenericArgsRef<'tcx>, + _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>, + ) -> RelateResult<'tcx, Ty<'tcx>> { + let variances = self.cx().variances_of(def_id); + relate_args_with_variances(self, variances, a_args, b_args)?; + Ok(a_ty) + } + fn relate_with_variance>>( &mut self, variance: ty::Variance, diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 7ac2dff12f75..18d5922f27d1 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; +use rustc_hir::def_id::DefId; use rustc_infer::infer::relate::{ PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation, }; @@ -9,7 +10,7 @@ use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys}; +use rustc_middle::ty::relate::combine::{combine_ty_args, super_combine_consts, super_combine_tys}; use rustc_middle::ty::{self, FnMutDelegate, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; @@ -303,6 +304,28 @@ fn cx(&self) -> TyCtxt<'tcx> { self.type_checker.infcx.tcx } + fn relate_ty_args( + &mut self, + a_ty: Ty<'tcx>, + b_ty: Ty<'tcx>, + def_id: DefId, + a_args: ty::GenericArgsRef<'tcx>, + b_args: ty::GenericArgsRef<'tcx>, + _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>, + ) -> RelateResult<'tcx, Ty<'tcx>> { + let variances = self.cx().variances_of(def_id); + combine_ty_args( + &self.type_checker.infcx.infcx, + self, + a_ty, + b_ty, + variances, + a_args, + b_args, + |_| a_ty, + ) + } + #[instrument(skip(self, info), level = "trace", ret)] fn relate_with_variance>>( &mut self, @@ -328,7 +351,7 @@ fn relate_with_variance>>( fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { let infcx = self.type_checker.infcx; - let a = self.type_checker.infcx.shallow_resolve(a); + let a = infcx.shallow_resolve(a); assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b); if a == b { diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 6592360cf0a5..7be5daf61056 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -1,8 +1,10 @@ use std::collections::hash_map::Entry; use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::DefId; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use rustc_type_ir::relate::relate_args_with_variances; use tracing::instrument; use crate::infer::region_constraints::VerifyIfEq; @@ -137,6 +139,20 @@ fn cx(&self) -> TyCtxt<'tcx> { self.tcx } + fn relate_ty_args( + &mut self, + a_ty: Ty<'tcx>, + _: Ty<'tcx>, + def_id: DefId, + a_args: ty::GenericArgsRef<'tcx>, + b_args: ty::GenericArgsRef<'tcx>, + _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>, + ) -> RelateResult<'tcx, Ty<'tcx>> { + let variances = self.cx().variances_of(def_id); + relate_args_with_variances(self, variances, a_args, b_args)?; + Ok(a_ty) + } + #[instrument(level = "trace", skip(self))] fn relate_with_variance>>( &mut self, @@ -145,6 +161,10 @@ fn relate_with_variance>>( a: T, b: T, ) -> RelateResult<'tcx, T> { + // FIXME(@lcnr): This is weird. We are ignoring the ambient variance + // here, effectively treating everything as being in either a covariant + // or contravariant context. + // // Opaque types args have lifetime parameters. // We must not check them to be equal, as we never insert anything to make them so. if variance != ty::Bivariant { self.relate(a, b) } else { Ok(a) } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index cc41957c110f..69c090b662e5 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -70,14 +70,13 @@ pub fn instantiate_ty_var>>( // // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and // `?1 <: ?3`. - let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = self - .generalize( - relation.span(), - relation.structurally_relate_aliases(), - target_vid, - instantiation_variance, - source_ty, - )?; + let Generalization { value_may_be_infer: generalized_ty } = self.generalize( + relation.span(), + relation.structurally_relate_aliases(), + target_vid, + instantiation_variance, + source_ty, + )?; // Constrain `b_vid` to the generalized type `generalized_ty`. if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() { @@ -86,11 +85,6 @@ pub fn instantiate_ty_var>>( self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty); } - // See the comment on `Generalization::has_unconstrained_ty_var`. - if has_unconstrained_ty_var { - relation.register_predicates([ty::ClauseKind::WellFormed(generalized_ty.into())]); - } - // Finally, relate `generalized_ty` to `source_ty`, as described in previous comment. // // FIXME(#16847): This code is non-ideal because all these subtype @@ -210,19 +204,15 @@ pub(crate) fn instantiate_const_var ) -> RelateResult<'tcx, ()> { // FIXME(generic_const_exprs): Occurs check failures for unevaluated // constants and generic expressions are not yet handled correctly. - let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = self - .generalize( - relation.span(), - relation.structurally_relate_aliases(), - target_vid, - ty::Invariant, - source_ct, - )?; + let Generalization { value_may_be_infer: generalized_ct } = self.generalize( + relation.span(), + relation.structurally_relate_aliases(), + target_vid, + ty::Invariant, + source_ct, + )?; debug_assert!(!generalized_ct.is_ct_infer()); - if has_unconstrained_ty_var { - bug!("unconstrained ty var when generalizing `{source_ct:?}`"); - } self.inner .borrow_mut() @@ -281,12 +271,10 @@ fn generalize> + Relate>>( ambient_variance, in_alias: false, cache: Default::default(), - has_unconstrained_ty_var: false, }; let value_may_be_infer = generalizer.relate(source_term, source_term)?; - let has_unconstrained_ty_var = generalizer.has_unconstrained_ty_var; - Ok(Generalization { value_may_be_infer, has_unconstrained_ty_var }) + Ok(Generalization { value_may_be_infer }) } } @@ -376,9 +364,6 @@ struct Generalizer<'me, 'tcx> { in_alias: bool, cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>, - - /// See the field `has_unconstrained_ty_var` in `Generalization`. - has_unconstrained_ty_var: bool, } impl<'tcx> Generalizer<'_, 'tcx> { @@ -391,10 +376,8 @@ fn cyclic_term_error(&self) -> TypeError<'tcx> { } /// Create a new type variable in the universe of the target when - /// generalizing an alias. This has to set `has_unconstrained_ty_var` - /// if we're currently in a bivariant context. - fn next_ty_var_for_alias(&mut self) -> Ty<'tcx> { - self.has_unconstrained_ty_var |= self.ambient_variance == ty::Bivariant; + /// generalizing an alias. + fn next_ty_var_for_alias(&self) -> Ty<'tcx> { self.infcx.next_ty_var_in_universe(self.span, self.for_universe) } @@ -461,29 +444,26 @@ fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } - fn relate_item_args( + fn relate_ty_args( &mut self, - item_def_id: DefId, - a_arg: ty::GenericArgsRef<'tcx>, - b_arg: ty::GenericArgsRef<'tcx>, - ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> { - if self.ambient_variance == ty::Invariant { + a_ty: Ty<'tcx>, + _: Ty<'tcx>, + def_id: DefId, + a_args: ty::GenericArgsRef<'tcx>, + b_args: ty::GenericArgsRef<'tcx>, + mk: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>, + ) -> RelateResult<'tcx, Ty<'tcx>> { + let args = if self.ambient_variance == ty::Invariant { // Avoid fetching the variance if we are in an invariant // context; no need, and it can induce dependency cycles // (e.g., #41849). - relate::relate_args_invariantly(self, a_arg, b_arg) + relate::relate_args_invariantly(self, a_args, b_args) } else { let tcx = self.cx(); - let opt_variances = tcx.variances_of(item_def_id); - relate::relate_args_with_variances( - self, - item_def_id, - opt_variances, - a_arg, - b_arg, - false, - ) - } + let variances = tcx.variances_of(def_id); + relate::relate_args_with_variances(self, variances, a_args, b_args) + }?; + if args == a_args { Ok(a_ty) } else { Ok(mk(args)) } } #[instrument(level = "debug", skip(self, variance, b), ret)] @@ -545,14 +525,8 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { } } - // Bivariant: make a fresh var, but remember that - // it is unconstrained. See the comment in - // `Generalization`. - ty::Bivariant => self.has_unconstrained_ty_var = true, - - // Co/contravariant: this will be - // sufficiently constrained later on. - ty::Covariant | ty::Contravariant => (), + // We do need a fresh type variable otherwise. + ty::Bivariant | ty::Covariant | ty::Contravariant => (), } let origin = inner.type_variables().var_origin(vid); @@ -771,32 +745,8 @@ struct Generalization { /// for `?0` generalization returns an inference /// variable. /// - /// This has to be handled wotj care as it can + /// This has to be handled with care as it can /// otherwise very easily result in infinite /// recursion. pub value_may_be_infer: T, - - /// In general, we do not check whether all types which occur during - /// type checking are well-formed. We only check wf of user-provided types - /// and when actually using a type, e.g. for method calls. - /// - /// This means that when subtyping, we may end up with unconstrained - /// inference variables if a generalized type has bivariant parameters. - /// A parameter may only be bivariant if it is constrained by a projection - /// bound in a where-clause. As an example, imagine a type: - /// - /// struct Foo where A: Iterator { - /// data: A - /// } - /// - /// here, `A` will be covariant, but `B` is unconstrained. - /// - /// However, whatever it is, for `Foo` to be WF, it must be equal to `A::Item`. - /// If we have an input `Foo`, then after generalization we will wind - /// up with a type like `Foo`. When we enforce `Foo <: Foo`, - /// we will wind up with the requirement that `?A <: ?C`, but no particular - /// relationship between `?B` and `?D` (after all, these types may be completely - /// different). If we do nothing else, this may mean that `?D` goes unconstrained - /// (as in #41677). To avoid this we emit a `WellFormed` obligation in these cases. - pub has_unconstrained_ty_var: bool, } diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 4eb77a99be78..a05e2d40e829 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -17,8 +17,9 @@ //! //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order) +use rustc_hir::def_id::DefId; use rustc_middle::traits::solve::Goal; -use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys}; +use rustc_middle::ty::relate::combine::{combine_ty_args, super_combine_consts, super_combine_tys}; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt}; use rustc_span::Span; @@ -75,6 +76,19 @@ fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } + fn relate_ty_args( + &mut self, + a_ty: Ty<'tcx>, + b_ty: Ty<'tcx>, + def_id: DefId, + a_args: ty::GenericArgsRef<'tcx>, + b_args: ty::GenericArgsRef<'tcx>, + mk: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>, + ) -> RelateResult<'tcx, Ty<'tcx>> { + let variances = self.cx().variances_of(def_id); + combine_ty_args(self.infcx, self, a_ty, b_ty, variances, a_args, b_args, |args| mk(args)) + } + fn relate_with_variance>>( &mut self, variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 04ff776594e6..96a0375f5fba 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -1,8 +1,7 @@ +use rustc_hir::def_id::DefId; use rustc_middle::traits::solve::Goal; -use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys}; -use rustc_middle::ty::relate::{ - Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances, -}; +use rustc_middle::ty::relate::combine::{combine_ty_args, super_combine_consts, super_combine_tys}; +use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation, relate_args_invariantly}; use rustc_middle::ty::{self, DelayedSet, Ty, TyCtxt, TyVar}; use rustc_span::Span; use tracing::{debug, instrument}; @@ -79,21 +78,24 @@ fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } - fn relate_item_args( + fn relate_ty_args( &mut self, - item_def_id: rustc_hir::def_id::DefId, - a_arg: ty::GenericArgsRef<'tcx>, - b_arg: ty::GenericArgsRef<'tcx>, - ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> { + a_ty: Ty<'tcx>, + b_ty: Ty<'tcx>, + def_id: DefId, + a_args: ty::GenericArgsRef<'tcx>, + b_args: ty::GenericArgsRef<'tcx>, + _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>, + ) -> RelateResult<'tcx, Ty<'tcx>> { if self.ambient_variance == ty::Invariant { // Avoid fetching the variance if we are in an invariant // context; no need, and it can induce dependency cycles // (e.g., #41849). - relate_args_invariantly(self, a_arg, b_arg) + relate_args_invariantly(self, a_args, b_args)?; + Ok(a_ty) } else { - let tcx = self.cx(); - let opt_variances = tcx.variances_of(item_def_id); - relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, false) + let variances = self.cx().variances_of(def_id); + combine_ty_args(self.infcx, self, a_ty, b_ty, variances, a_args, b_args, |_| a_ty) } } diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index b9afb62cf1c6..f54afce0615f 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -12,7 +12,8 @@ use rustc_macros::LintDiagnostic; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::ty::relate::{ - Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys, + Relate, RelateResult, TypeRelation, relate_args_with_variances, structurally_relate_consts, + structurally_relate_tys, }; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, @@ -502,6 +503,20 @@ fn cx(&self) -> TyCtxt<'tcx> { self.tcx } + fn relate_ty_args( + &mut self, + a_ty: Ty<'tcx>, + _: Ty<'tcx>, + def_id: DefId, + a_args: ty::GenericArgsRef<'tcx>, + b_args: ty::GenericArgsRef<'tcx>, + _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>, + ) -> RelateResult<'tcx, Ty<'tcx>> { + let variances = self.cx().variances_of(def_id); + relate_args_with_variances(self, variances, a_args, b_args)?; + Ok(a_ty) + } + fn relate_with_variance>>( &mut self, variance: ty::Variance, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index b280a6ec55af..32be23eed765 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2069,6 +2069,19 @@ fn cx(&self) -> TyCtxt<'tcx> { self.0.tcx } + fn relate_ty_args( + &mut self, + a_ty: Ty<'tcx>, + _: Ty<'tcx>, + _: DefId, + a_args: ty::GenericArgsRef<'tcx>, + b_args: ty::GenericArgsRef<'tcx>, + _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>, + ) -> RelateResult<'tcx, Ty<'tcx>> { + relate::relate_args_invariantly(self, a_args, b_args)?; + Ok(a_ty) + } + fn relate_with_variance>>( &mut self, _variance: ty::Variance, diff --git a/compiler/rustc_trait_selection/src/traits/select/_match.rs b/compiler/rustc_trait_selection/src/traits/select/_match.rs index 7c19c35a4f78..27de754aa7dc 100644 --- a/compiler/rustc_trait_selection/src/traits/select/_match.rs +++ b/compiler/rustc_trait_selection/src/traits/select/_match.rs @@ -1,3 +1,4 @@ +use rustc_hir::def_id::DefId; use rustc_infer::infer::relate::{ self, Relate, RelateResult, TypeRelation, structurally_relate_tys, }; @@ -36,6 +37,19 @@ fn cx(&self) -> TyCtxt<'tcx> { self.tcx } + fn relate_ty_args( + &mut self, + a_ty: Ty<'tcx>, + _: Ty<'tcx>, + _: DefId, + a_args: ty::GenericArgsRef<'tcx>, + b_args: ty::GenericArgsRef<'tcx>, + _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>, + ) -> RelateResult<'tcx, Ty<'tcx>> { + relate::relate_args_invariantly(self, a_args, b_args)?; + Ok(a_ty) + } + fn relate_with_variance>>( &mut self, _: ty::Variance, diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index fc74cbf47823..4f843503d1af 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -73,20 +73,15 @@ fn relate>(&mut self, a: T, b: T) -> RelateResult { Relate::relate(self, a, b) } - /// Relate the two args for the given item. The default - /// is to look up the variance for the item and proceed - /// accordingly. - #[instrument(skip(self), level = "trace")] - fn relate_item_args( + fn relate_ty_args( &mut self, - item_def_id: I::DefId, + a_ty: I::Ty, + b_ty: I::Ty, + ty_def_id: I::DefId, a_arg: I::GenericArgs, b_arg: I::GenericArgs, - ) -> RelateResult { - let cx = self.cx(); - let opt_variances = cx.variances_of(item_def_id); - relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, true) - } + mk: impl FnOnce(I::GenericArgs) -> I::Ty, + ) -> RelateResult; /// Switch variance for the purpose of relating `a` and `b`. fn relate_with_variance>( @@ -138,27 +133,17 @@ pub fn relate_args_invariantly>( pub fn relate_args_with_variances>( relation: &mut R, - ty_def_id: I::DefId, variances: I::VariancesOf, - a_arg: I::GenericArgs, - b_arg: I::GenericArgs, - fetch_ty_for_diag: bool, + a_args: I::GenericArgs, + b_args: I::GenericArgs, ) -> RelateResult { let cx = relation.cx(); - - let mut cached_ty = None; - let params = iter::zip(a_arg.iter(), b_arg.iter()).enumerate().map(|(i, (a, b))| { + let args = iter::zip(a_args.iter(), b_args.iter()).enumerate().map(|(i, (a, b))| { let variance = variances.get(i).unwrap(); - let variance_info = if variance == ty::Invariant && fetch_ty_for_diag { - let ty = *cached_ty.get_or_insert_with(|| cx.type_of(ty_def_id).instantiate(cx, a_arg)); - VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } - } else { - VarianceDiagInfo::default() - }; - relation.relate_with_variance(variance, variance_info, a, b) + relation.relate_with_variance(variance, VarianceDiagInfo::None, a, b) }); - - cx.mk_args_from_iter(params) + // FIXME: We can probably try to reuse `a_args` here if it did not change. + cx.mk_args_from_iter(args) } impl Relate for ty::FnSig { @@ -240,10 +225,7 @@ fn relate>( } else { let cx = relation.cx(); let args = if let Some(variances) = cx.opt_alias_variances(a.kind(cx), a.def_id) { - relate_args_with_variances( - relation, a.def_id, variances, a.args, b.args, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )? + relate_args_with_variances(relation, variances, a.args, b.args)? } else { relate_args_invariantly(relation, a.args, b.args)? }; @@ -268,11 +250,9 @@ fn relate>( let args = match a.kind(relation.cx()) { ty::AliasTermKind::OpaqueTy => relate_args_with_variances( relation, - a.def_id, relation.cx().variances_of(a.def_id), a.args, b.args, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle )?, ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::FreeConst @@ -402,12 +382,13 @@ pub fn structurally_relate_tys>( (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a), (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def == b_def => { - Ok(if a_args.is_empty() { - a + if a_args.is_empty() { + Ok(a) } else { - let args = relation.relate_item_args(a_def.def_id().into(), a_args, b_args)?; - if args == a_args { a } else { Ty::new_adt(cx, a_def, args) } - }) + relation.relate_ty_args(a, b, a_def.def_id().into(), a_args, b_args, |args| { + Ty::new_adt(cx, a_def, args) + }) + } } (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(cx, a_id)), @@ -516,12 +497,13 @@ pub fn structurally_relate_tys>( } (ty::FnDef(a_def_id, a_args), ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => { - Ok(if a_args.is_empty() { - a + if a_args.is_empty() { + Ok(a) } else { - let args = relation.relate_item_args(a_def_id.into(), a_args, b_args)?; - if args == a_args { a } else { Ty::new_fn_def(cx, a_def_id, args) } - }) + relation.relate_ty_args(a, b, a_def_id.into(), a_args, b_args, |args| { + Ty::new_fn_def(cx, a_def_id, args) + }) + } } (ty::FnPtr(a_sig_tys, a_hdr), ty::FnPtr(b_sig_tys, b_hdr)) => { diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 8dd7c4df2442..64b87fac77f9 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -1,3 +1,5 @@ +use std::iter; + use tracing::debug; use super::{ @@ -6,6 +8,7 @@ }; use crate::error::TypeError; use crate::inherent::*; +use crate::relate::VarianceDiagInfo; use crate::solve::Goal; use crate::visit::TypeVisitableExt as _; use crate::{self as ty, InferCtxtLike, Interner, TypingMode, Upcast}; @@ -219,3 +222,75 @@ pub fn super_combine_consts( _ => structurally_relate_consts(relation, a, b), } } + +pub fn combine_ty_args( + infcx: &Infcx, + relation: &mut R, + a_ty: I::Ty, + b_ty: I::Ty, + variances: I::VariancesOf, + a_args: I::GenericArgs, + b_args: I::GenericArgs, + mk: impl FnOnce(I::GenericArgs) -> I::Ty, +) -> RelateResult +where + Infcx: InferCtxtLike, + I: Interner, + R: PredicateEmittingRelation, +{ + let cx = infcx.cx(); + let mut has_unconstrained_bivariant_arg = false; + let args = iter::zip(a_args.iter(), b_args.iter()).enumerate().map(|(i, (a, b))| { + let variance = variances.get(i).unwrap(); + let variance_info = match variance { + ty::Invariant => { + VarianceDiagInfo::Invariant { ty: a_ty, param_index: i.try_into().unwrap() } + } + ty::Covariant | ty::Contravariant => VarianceDiagInfo::default(), + ty::Bivariant => { + let has_non_region_infer = |arg: I::GenericArg| { + arg.has_non_region_infer() + && infcx.resolve_vars_if_possible(arg).has_non_region_infer() + }; + if has_non_region_infer(a) || has_non_region_infer(b) { + has_unconstrained_bivariant_arg = true; + } + VarianceDiagInfo::default() + } + }; + relation.relate_with_variance(variance, variance_info, a, b) + }); + let args = cx.mk_args_from_iter(args)?; + + // In general, we do not check whether all types which occur during + // type checking are well-formed. We only check wf of user-provided types + // and when actually using a type, e.g. for method calls. + // + // This means that when subtyping, we may end up with unconstrained + // inference variables if a generalized type has bivariant parameters. + // A parameter may only be bivariant if it is constrained by a projection + // bound in a where-clause. As an example, imagine a type: + // + // struct Foo where A: Iterator { + // data: A + // } + // + // here, `A` will be covariant, but `B` is unconstrained. However, whatever it is, + // for `Foo` to be WF, it must be equal to `A::Item`. + // + // If we have an input `Foo`, then after generalization we will wind + // up with a type like `Foo`. When we enforce `Foo <: Foo`, + // we will wind up with the requirement that `?A <: ?C`, but no particular + // relationship between `?B` and `?D` (after all, these types may be completely + // different). If we do nothing else, this may mean that `?D` goes unconstrained + // (as in #41677). To avoid this we emit a `WellFormed` when relating types with + // bivariant arguments. + if has_unconstrained_bivariant_arg { + relation.register_predicates([ + ty::ClauseKind::WellFormed(a_ty.into()), + ty::ClauseKind::WellFormed(b_ty.into()), + ]); + } + + if a_args == args { Ok(a_ty) } else { Ok(mk(args)) } +} diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index 79f6bc5dabb4..82ee4f75fcb0 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -2,6 +2,7 @@ use self::combine::{PredicateEmittingRelation, super_combine_consts, super_combine_tys}; use crate::data_structures::DelayedSet; +use crate::relate::combine::combine_ty_args; pub use crate::relate::*; use crate::solve::Goal; use crate::{self as ty, InferCtxtLike, Interner}; @@ -139,24 +140,26 @@ fn cx(&self) -> I { self.infcx.cx() } - fn relate_item_args( + fn relate_ty_args( &mut self, - item_def_id: I::DefId, - a_arg: I::GenericArgs, - b_arg: I::GenericArgs, - ) -> RelateResult { + a_ty: I::Ty, + b_ty: I::Ty, + def_id: I::DefId, + a_args: I::GenericArgs, + b_args: I::GenericArgs, + _: impl FnOnce(I::GenericArgs) -> I::Ty, + ) -> RelateResult { if self.ambient_variance == ty::Invariant { // Avoid fetching the variance if we are in an invariant // context; no need, and it can induce dependency cycles // (e.g., #41849). - relate_args_invariantly(self, a_arg, b_arg) + relate_args_invariantly(self, a_args, b_args)?; + Ok(a_ty) } else { - let tcx = self.cx(); - let opt_variances = tcx.variances_of(item_def_id); - relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, false) + let variances = self.cx().variances_of(def_id); + combine_ty_args(self.infcx, self, a_ty, b_ty, variances, a_args, b_args, |_| a_ty) } } - fn relate_with_variance>( &mut self, variance: ty::Variance, diff --git a/tests/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.rs b/tests/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.rs new file mode 100644 index 000000000000..9e25401f0f9a --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.rs @@ -0,0 +1,52 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// Regression test for trait-system-refactor-initiative#250. +// Subtyping previously handled bivariant arguments by emitting +// a `WellFormed` obligation when generalizing them. +// +// This obligation then got dropped inside of an ambiguous `Subtype` +// obligation so we never constrained the bivariant arg. + +// Test case 1 +enum State +where + S: Iterator, +{ + Active { upstream: S }, + WindDown, + Complete, +} + +impl State +where + S: Iterator, +{ + fn foo(self) { + let x = match self { + State::Active { .. } => None, + State::WindDown => None, + State::Complete => Some(State::Complete), + }; + let _: Option> = x; + } +} + +// Test case 2 +trait Trait { + type Assoc; +} +impl Trait for T { + type Assoc = T; +} + +struct Foo, U>(T); + +fn main() { + let x = None.unwrap(); + let y = x; + let _: Foo<_, _> = x; + let _: Foo = x; +} From e1be0d2e2a1640da4b19c86025e3fd95c5007b36 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 13 Nov 2025 16:18:22 +0100 Subject: [PATCH 317/585] MIR typeck: invariant ctxt fast path This removes variance information from some diagnostics. However, that variance information is not actually relevant here. Casting `*const dyn Cat<'a>` to `*const S>` is an error regardless of whether `S` requires its argument to be invariant. Wide-pointer casts always require the trait object arguments to be invariant. --- .../src/type_check/relate_tys.rs | 30 ++++++++++++------- ...-different-regions-id-trait.current.stderr | 4 --- ...obj-different-regions-id-trait.next.stderr | 4 --- ...ied-bounds-unnorm-associated-type-2.stderr | 3 -- 4 files changed, 19 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 18d5922f27d1..539912609baa 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -11,6 +11,7 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::relate::combine::{combine_ty_args, super_combine_consts, super_combine_tys}; +use rustc_middle::ty::relate::relate_args_invariantly; use rustc_middle::ty::{self, FnMutDelegate, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; @@ -313,17 +314,24 @@ fn relate_ty_args( b_args: ty::GenericArgsRef<'tcx>, _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>, ) -> RelateResult<'tcx, Ty<'tcx>> { - let variances = self.cx().variances_of(def_id); - combine_ty_args( - &self.type_checker.infcx.infcx, - self, - a_ty, - b_ty, - variances, - a_args, - b_args, - |_| a_ty, - ) + if self.ambient_variance == ty::Invariant { + // Avoid fetching the variance if we are in an invariant context, + // slightly improves perf. + relate_args_invariantly(self, a_args, b_args)?; + Ok(a_ty) + } else { + let variances = self.cx().variances_of(def_id); + combine_ty_args( + &self.type_checker.infcx.infcx, + self, + a_ty, + b_ty, + variances, + a_args, + b_args, + |_| a_ty, + ) + } } #[instrument(skip(self, info), level = "trace", ret)] diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr index 4e43d3b93fa3..62f17a656855 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr @@ -6,10 +6,6 @@ LL | fn m<'a>() { LL | let unsend: *const dyn Cat<'a> = &(); LL | let _send = unsend as *const S>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = note: requirement occurs because of the type `S>`, which makes the generic argument `dyn Cat<'_>` invariant - = note: the struct `S` is invariant over the parameter `T` - = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr index 4e43d3b93fa3..62f17a656855 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr @@ -6,10 +6,6 @@ LL | fn m<'a>() { LL | let unsend: *const dyn Cat<'a> = &(); LL | let _send = unsend as *const S>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = note: requirement occurs because of the type `S>`, which makes the generic argument `dyn Cat<'_>` invariant - = note: the struct `S` is invariant over the parameter `T` - = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-2.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type-2.stderr index 85e3452fbf2c..95fac3ce51d2 100644 --- a/tests/ui/fn/implied-bounds-unnorm-associated-type-2.stderr +++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-2.stderr @@ -9,9 +9,6 @@ LL | f::<'a, 'b>(()); | ^^^^^^^^^^^^^^^ generic argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` - = note: requirement occurs because of a function pointer to `f` - = note: the function `f` is invariant over the parameter `'a` - = help: see for more information about variance error: aborting due to 1 previous error From 3d0f5f2f88678b894ebafad599852e129229e5d8 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 5 Dec 2025 00:39:55 +0900 Subject: [PATCH 318/585] Add regression test for 141845 --- ...solution-with-inherent-associated-types.rs | 13 +++++++++++++ ...tion-with-inherent-associated-types.stderr | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/ui/const-generics/mgca/resolution-with-inherent-associated-types.rs create mode 100644 tests/ui/const-generics/mgca/resolution-with-inherent-associated-types.stderr diff --git a/tests/ui/const-generics/mgca/resolution-with-inherent-associated-types.rs b/tests/ui/const-generics/mgca/resolution-with-inherent-associated-types.rs new file mode 100644 index 000000000000..6a8d291e3cc0 --- /dev/null +++ b/tests/ui/const-generics/mgca/resolution-with-inherent-associated-types.rs @@ -0,0 +1,13 @@ +//! Regression test for +//! Checks const resolution stability when using inherent associated types +//! and generic const arguments. + +//@compile-flags: --crate-type=lib +#![expect(incomplete_features)] +#![feature(inherent_associated_types, min_generic_const_args)] +trait Trait {} + +struct Struct; + +type Alias = Struct<{ Struct::N }>; +//~^ ERROR: missing generics for struct `Struct` [E0107] diff --git a/tests/ui/const-generics/mgca/resolution-with-inherent-associated-types.stderr b/tests/ui/const-generics/mgca/resolution-with-inherent-associated-types.stderr new file mode 100644 index 000000000000..13e73dafbea6 --- /dev/null +++ b/tests/ui/const-generics/mgca/resolution-with-inherent-associated-types.stderr @@ -0,0 +1,19 @@ +error[E0107]: missing generics for struct `Struct` + --> $DIR/resolution-with-inherent-associated-types.rs:12:33 + | +LL | type Alias = Struct<{ Struct::N }>; + | ^^^^^^ expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `N` + --> $DIR/resolution-with-inherent-associated-types.rs:10:8 + | +LL | struct Struct; + | ^^^^^^ -------------- +help: add missing generic argument + | +LL | type Alias = Struct<{ Struct::N }>; + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0107`. From ce050d6571c0bf4e37af08a6f45e92a54c7a22eb Mon Sep 17 00:00:00 2001 From: Redddy Date: Fri, 5 Dec 2025 02:02:48 +0900 Subject: [PATCH 319/585] Add Zed to quickstart --- src/doc/rustc-dev-guide/src/building/quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/building/quickstart.md b/src/doc/rustc-dev-guide/src/building/quickstart.md index 97314d803695..42058246cd05 100644 --- a/src/doc/rustc-dev-guide/src/building/quickstart.md +++ b/src/doc/rustc-dev-guide/src/building/quickstart.md @@ -66,6 +66,6 @@ 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 [Zulip](https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp). -If you use VSCode, Vim, Emacs or Helix, `./x setup` will ask you if you want to +If you use VSCode, Vim, Emacs, Helix or Zed, `./x setup` will ask you if you want to set up the editor config. For more information, check out [suggested workflows](./suggested.md). From d898b568d3f62ddfbc40fefec52019420b09a737 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Thu, 4 Dec 2025 13:10:02 -0500 Subject: [PATCH 320/585] Update cargo submodule --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index bd979347d814..2c283a9a5c59 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit bd979347d814dfe03bba124165dbce9554d0b4d8 +Subproject commit 2c283a9a5c5968eeb9a8f12313f04feb1ff8dfac From d21adb9158d1b3628855f49c58a3b65fc24c4332 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 4 Dec 2025 20:21:27 +0100 Subject: [PATCH 321/585] bootstrap: add `rustc-dev` install target --- src/bootstrap/src/core/build_steps/dist.rs | 4 ++-- src/bootstrap/src/core/build_steps/install.rs | 11 +++++++++++ src/bootstrap/src/core/builder/mod.rs | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 40149ee09427..caf0af35e401 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -892,8 +892,8 @@ fn metadata(&self) -> Option { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustcDev { /// The compiler that will build rustc which will be shipped in this component. - build_compiler: Compiler, - target: TargetSelection, + pub build_compiler: Compiler, + pub target: TargetSelection, } impl RustcDev { diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index d52cc52abbd3..d23fe029bcc7 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -279,6 +279,17 @@ fn run($sel, $builder: &Builder<'_>) { }); install_sh(builder, "rustc", self.build_compiler, Some(self.target), &tarball); }; + RustcDev, alias = "rustc-dev", Self::should_build(_config), IS_HOST: true, { + if let Some(tarball) = builder.ensure(dist::RustcDev { + build_compiler: self.build_compiler, target: self.target + }) { + install_sh(builder, "rustc-dev", self.build_compiler, Some(self.target), &tarball); + } else { + builder.info( + &format!("skipping Install RustcDev stage{} ({})", self.build_compiler.stage + 1, self.target), + ); + } + }; RustcCodegenCranelift, alias = "rustc-codegen-cranelift", Self::should_build(_config), IS_HOST: true, { if let Some(tarball) = builder.ensure(dist::CraneliftCodegenBackend { compilers: RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, self.target), diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 961d0cd855ae..0bf70883a47a 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -998,6 +998,7 @@ macro_rules! describe { // binary path, we must install rustc before the tools. Otherwise, the rust-installer will // install the same binaries twice for each tool, leaving backup files (*.old) as a result. install::Rustc, + install::RustcDev, install::Cargo, install::RustAnalyzer, install::Rustfmt, From 74387157c7edaf8a0ace3cbb54c42d2dfa7b8f93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 4 Dec 2025 21:17:40 +0100 Subject: [PATCH 322/585] Revert "Rollup merge of #149147 - chenyukang:yukang-fix-unused_assignments-macro-gen-147648, r=JonathanBrouwer" This reverts commit 82a17b30d8cd379a43c3ee8d12598e89e3be0fbd, reversing changes made to 5019bdaefeebecac42b778ae98def56cab69ab30. --- compiler/rustc_mir_transform/src/liveness.rs | 5 ----- tests/ui/liveness/auxiliary/aux_issue_147648.rs | 7 ------- .../liveness/unused-assignments-from-macro-147648.rs | 10 ---------- 3 files changed, 22 deletions(-) delete mode 100644 tests/ui/liveness/auxiliary/aux_issue_147648.rs delete mode 100644 tests/ui/liveness/unused-assignments-from-macro-147648.rs diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index 7ee7c3a81c7e..1d1ba455a81e 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -75,11 +75,6 @@ pub(crate) fn check_liveness<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Den return DenseBitSet::new_empty(0); } - // Don't run unused pass for items generated by foreign macros - if tcx.def_span(parent).in_external_macro(tcx.sess.source_map()) { - return DenseBitSet::new_empty(0); - } - let mut body = &*tcx.mir_promoted(def_id).0.borrow(); let mut body_mem; diff --git a/tests/ui/liveness/auxiliary/aux_issue_147648.rs b/tests/ui/liveness/auxiliary/aux_issue_147648.rs deleted file mode 100644 index ccb5ad6b8fc0..000000000000 --- a/tests/ui/liveness/auxiliary/aux_issue_147648.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[macro_export] -macro_rules! unused_assign { - ($x:ident) => { - let mut $x = 1; - $x = 2; - }; -} diff --git a/tests/ui/liveness/unused-assignments-from-macro-147648.rs b/tests/ui/liveness/unused-assignments-from-macro-147648.rs deleted file mode 100644 index c32c281538b4..000000000000 --- a/tests/ui/liveness/unused-assignments-from-macro-147648.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ check-pass -//@ aux-build:aux_issue_147648.rs - -#![deny(unused_assignments)] - -extern crate aux_issue_147648; - -fn main() { - aux_issue_147648::unused_assign!(y); -} From ad73972e999b79ea4e17d997676bdb8327288c77 Mon Sep 17 00:00:00 2001 From: Alina Sbirlea Date: Thu, 4 Dec 2025 20:21:49 +0000 Subject: [PATCH 323/585] Fix for LLVM22 making lowering decisions dependent on RuntimeLibraryInfo. LLVM reference commit: https://github.com/llvm/llvm-project/commit/04c81a99735c04b2018eeb687e74f9860e1d0e1b. --- compiler/rustc_codegen_llvm/src/back/write.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 12 +++++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index c0c01b80372f..b131de1df8ba 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -75,7 +75,7 @@ fn write_output_file<'ll>( let result = unsafe { let pm = llvm::LLVMCreatePassManager(); llvm::LLVMAddAnalysisPasses(target, pm); - llvm::LLVMRustAddLibraryInfo(pm, m, no_builtins); + llvm::LLVMRustAddLibraryInfo(target, pm, m, no_builtins); llvm::LLVMRustWriteOutputFile( target, pm, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 53b9a2bda894..c5cbc92ae772 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2379,6 +2379,7 @@ pub(crate) fn LLVMRustCreateTargetMachine( ) -> *mut TargetMachine; pub(crate) fn LLVMRustAddLibraryInfo<'a>( + T: &TargetMachine, PM: &PassManager<'a>, M: &'a Module, DisableSimplifyLibCalls: bool, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 143cc9479089..714ba0f177a8 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -6,6 +6,9 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/Lint.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#if LLVM_VERSION_GE(22, 0) +#include "llvm/Analysis/RuntimeLibcallInfo.h" +#endif #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm/CodeGen/CommandFlags.h" @@ -379,13 +382,20 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( // Unfortunately, the LLVM C API doesn't provide a way to create the // TargetLibraryInfo pass, so we use this method to do so. -extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M, +extern "C" void LLVMRustAddLibraryInfo(LLVMTargetMachineRef T, + LLVMPassManagerRef PMR, LLVMModuleRef M, bool DisableSimplifyLibCalls) { auto TargetTriple = Triple(unwrap(M)->getTargetTriple()); + TargetOptions *Options = &unwrap(T)->Options; auto TLII = TargetLibraryInfoImpl(TargetTriple); if (DisableSimplifyLibCalls) TLII.disableAllFunctions(); unwrap(PMR)->add(new TargetLibraryInfoWrapperPass(TLII)); +#if LLVM_VERSION_GE(22, 0) + unwrap(PMR)->add(new RuntimeLibraryInfoWrapper( + TargetTriple, Options->ExceptionModel, Options->FloatABIType, + Options->EABIVersion, Options->MCOptions.ABIName, Options->VecLib)); +#endif } extern "C" void LLVMRustSetLLVMOptions(int Argc, char **Argv) { From 84ff44c74933374a941f0c8c49e8381d830c3193 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 5 Dec 2025 13:44:03 +1100 Subject: [PATCH 324/585] Add perma-unstable `--print=backend-has-zstd` for use by compiletest Tests for `-Zdebuginfo-compression=zstd` need to be skipped if LLVM was built without support for zstd compression. Currently, compiletest relies on messy and fragile heuristics to detect whether the compiler's LLVM was built with zstd support. But the compiler itself already knows whether LLVM has zstd or not, so it's easier for compiletest to just ask the compiler. --- compiler/rustc_codegen_llvm/src/lib.rs | 4 + compiler/rustc_driver_impl/src/lib.rs | 1 + .../rustc_session/src/config/print_request.rs | 3 + src/tools/compiletest/src/common.rs | 6 +- src/tools/compiletest/src/directives.rs | 101 ------------------ src/tools/compiletest/src/directives/needs.rs | 23 +++- .../help-diff.diff | 2 +- .../unstable-invalid-print-request-help.err | 2 +- tests/run-make/rustc-help/help-v.stdout | 2 +- tests/run-make/rustc-help/help.stdout | 2 +- .../print-without-arg.stderr | 2 +- tests/ui/invalid-compile-flags/print.stderr | 2 +- .../backend-has-zstd-unstable.rs | 8 ++ .../backend-has-zstd-unstable.stderr | 2 + .../ui/print-request/print-lints-help.stderr | 2 +- 15 files changed, 50 insertions(+), 112 deletions(-) create mode 100644 tests/ui/print-request/backend-has-zstd-unstable.rs create mode 100644 tests/ui/print-request/backend-has-zstd-unstable.stderr diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 1b65a133d58c..8c0c0afcc1dd 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -257,6 +257,10 @@ fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) { } writeln!(out).unwrap(); } + PrintKind::BackendHasZstd => { + let has_zstd = llvm::LLVMRustLLVMHasZstdCompression(); + writeln!(out, "{has_zstd}").unwrap(); + } PrintKind::CodeModels => { writeln!(out, "Available code models:").unwrap(); for name in &["tiny", "small", "kernel", "medium", "large"] { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 9a3d7cc506cf..0853f638509f 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -799,6 +799,7 @@ fn print_crate_info( println_info!("{}", calling_conventions.join("\n")); } RelocationModels + | BackendHasZstd | CodeModels | TlsModels | TargetCPUs diff --git a/compiler/rustc_session/src/config/print_request.rs b/compiler/rustc_session/src/config/print_request.rs index b8111fbc17f8..395f7a4fab71 100644 --- a/compiler/rustc_session/src/config/print_request.rs +++ b/compiler/rustc_session/src/config/print_request.rs @@ -22,6 +22,7 @@ pub struct PrintRequest { pub enum PrintKind { // tidy-alphabetical-start AllTargetSpecsJson, + BackendHasZstd, CallingConventions, Cfg, CheckCfg, @@ -59,6 +60,7 @@ fn name(self) -> &'static str { match self { // tidy-alphabetical-start AllTargetSpecsJson => "all-target-specs-json", + BackendHasZstd => "backend-has-zstd", CallingConventions => "calling-conventions", Cfg => "cfg", CheckCfg => "check-cfg", @@ -111,6 +113,7 @@ fn is_stable(self) -> bool { // Unstable values: AllTargetSpecsJson => false, + BackendHasZstd => false, // (perma-unstable, for use by compiletest) CheckCfg => false, CrateRootLintLevels => false, SupportedCrateTypes => false, diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index eb1fc55a2624..d8472691afdf 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -1096,7 +1096,11 @@ fn supported_crate_types(config: &Config) -> HashSet { crate_types } -fn query_rustc_output(config: &Config, args: &[&str], envs: HashMap) -> String { +pub(crate) fn query_rustc_output( + config: &Config, + args: &[&str], + envs: HashMap, +) -> String { let query_rustc_path = config.query_rustc_path.as_deref().unwrap_or(&config.rustc_path); let mut command = Command::new(query_rustc_path); diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index fed30415de56..c154886ebcde 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -885,107 +885,6 @@ pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option { None } -/// For tests using the `needs-llvm-zstd` directive: -/// - for local LLVM builds, try to find the static zstd library in the llvm-config system libs. -/// - for `download-ci-llvm`, see if `lld` was built with zstd support. -pub fn llvm_has_libzstd(config: &Config) -> bool { - // Strategy 1: works for local builds but not with `download-ci-llvm`. - // - // We check whether `llvm-config` returns the zstd library. Bootstrap's `llvm.libzstd` will only - // ask to statically link it when building LLVM, so we only check if the list of system libs - // contains a path to that static lib, and that it exists. - // - // See compiler/rustc_llvm/build.rs for more details and similar expectations. - fn is_zstd_in_config(llvm_bin_dir: &Utf8Path) -> Option<()> { - let llvm_config_path = llvm_bin_dir.join("llvm-config"); - let output = Command::new(llvm_config_path).arg("--system-libs").output().ok()?; - assert!(output.status.success(), "running llvm-config --system-libs failed"); - - let libs = String::from_utf8(output.stdout).ok()?; - for lib in libs.split_whitespace() { - if lib.ends_with("libzstd.a") && Utf8Path::new(lib).exists() { - return Some(()); - } - } - - None - } - - // Strategy 2: `download-ci-llvm`'s `llvm-config --system-libs` will not return any libs to - // use. - // - // The CI artifacts also don't contain the bootstrap config used to build them: otherwise we - // could have looked at the `llvm.libzstd` config. - // - // We infer whether `LLVM_ENABLE_ZSTD` was used to build LLVM as a byproduct of testing whether - // `lld` supports it. If not, an error will be emitted: "LLVM was not built with - // LLVM_ENABLE_ZSTD or did not find zstd at build time". - #[cfg(unix)] - fn is_lld_built_with_zstd(llvm_bin_dir: &Utf8Path) -> Option<()> { - let lld_path = llvm_bin_dir.join("lld"); - if lld_path.exists() { - // We can't call `lld` as-is, it expects to be invoked by a compiler driver using a - // different name. Prepare a temporary symlink to do that. - let lld_symlink_path = llvm_bin_dir.join("ld.lld"); - if !lld_symlink_path.exists() { - std::os::unix::fs::symlink(lld_path, &lld_symlink_path).ok()?; - } - - // Run `lld` with a zstd flag. We expect this command to always error here, we don't - // want to link actual files and don't pass any. - let output = Command::new(&lld_symlink_path) - .arg("--compress-debug-sections=zstd") - .output() - .ok()?; - assert!(!output.status.success()); - - // Look for a specific error caused by LLVM not being built with zstd support. We could - // also look for the "no input files" message, indicating the zstd flag was accepted. - let stderr = String::from_utf8(output.stderr).ok()?; - let zstd_available = !stderr.contains("LLVM was not built with LLVM_ENABLE_ZSTD"); - - // We don't particularly need to clean the link up (so the previous commands could fail - // in theory but won't in practice), but we can try. - std::fs::remove_file(lld_symlink_path).ok()?; - - if zstd_available { - return Some(()); - } - } - - None - } - - #[cfg(not(unix))] - fn is_lld_built_with_zstd(_llvm_bin_dir: &Utf8Path) -> Option<()> { - None - } - - if let Some(llvm_bin_dir) = &config.llvm_bin_dir { - // Strategy 1: for local LLVM builds. - if is_zstd_in_config(llvm_bin_dir).is_some() { - return true; - } - - // Strategy 2: for LLVM artifacts built on CI via `download-ci-llvm`. - // - // It doesn't work for cases where the artifacts don't contain the linker, but it's - // best-effort: CI has `llvm.libzstd` and `lld` enabled on the x64 linux artifacts, so it - // will at least work there. - // - // If this can be improved and expanded to less common cases in the future, it should. - if config.target == "x86_64-unknown-linux-gnu" - && config.host == config.target - && is_lld_built_with_zstd(llvm_bin_dir).is_some() - { - return true; - } - } - - // Otherwise, all hope is lost. - false -} - /// Takes a directive of the form `" [- ]"`, returns the numeric representation /// of `` and `` as tuple: `(, )`. /// diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs index b54400621092..208e96166021 100644 --- a/src/tools/compiletest/src/directives/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -1,5 +1,7 @@ -use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer}; -use crate::directives::{DirectiveLine, IgnoreDecision, llvm_has_libzstd}; +use crate::common::{ + Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer, query_rustc_output, +}; +use crate::directives::{DirectiveLine, IgnoreDecision}; pub(super) fn handle_needs( cache: &CachedNeedsConditions, @@ -377,7 +379,7 @@ pub(super) fn load(config: &Config) -> Self { .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" }) .exists(), - llvm_zstd: llvm_has_libzstd(&config), + llvm_zstd: llvm_has_zstd(&config), dlltool: find_dlltool(&config), symlinks: has_symlinks(), } @@ -428,3 +430,18 @@ fn has_symlinks() -> bool { fn has_symlinks() -> bool { true } + +fn llvm_has_zstd(config: &Config) -> bool { + // The compiler already knows whether LLVM was built with zstd or not, + // so compiletest can just ask the compiler. + let output = query_rustc_output( + config, + &["-Zunstable-options", "--print=backend-has-zstd"], + Default::default(), + ); + match output.trim() { + "true" => true, + "false" => false, + _ => panic!("unexpected output from `--print=backend-has-zstd`: {output:?}"), + } +} diff --git a/tests/run-make/print-request-help-stable-unstable/help-diff.diff b/tests/run-make/print-request-help-stable-unstable/help-diff.diff index 044302a19a01..e382a2478271 100644 --- a/tests/run-make/print-request-help-stable-unstable/help-diff.diff +++ b/tests/run-make/print-request-help-stable-unstable/help-diff.diff @@ -2,6 +2,6 @@ error: unknown print request: `xxx` | - = help: valid print requests are: `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `tls-models` -+ = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` ++ = help: valid print requests are: `all-target-specs-json`, `backend-has-zstd`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err b/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err index cc6c3c909b36..70764ea13aa8 100644 --- a/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err +++ b/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err @@ -1,5 +1,5 @@ error: unknown print request: `xxx` | - = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `backend-has-zstd`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout index cd161c51ee3b..c41cb5e3bde8 100644 --- a/tests/run-make/rustc-help/help-v.stdout +++ b/tests/run-make/rustc-help/help-v.stdout @@ -43,7 +43,7 @@ Options: --print [=] Compiler information to print on stdout (or to a file) INFO may be one of - . + . -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 -o Write output to FILENAME diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout index 74ec083bdee7..5e13a900484d 100644 --- a/tests/run-make/rustc-help/help.stdout +++ b/tests/run-make/rustc-help/help.stdout @@ -43,7 +43,7 @@ Options: --print [=] Compiler information to print on stdout (or to a file) INFO may be one of - . + . -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 -o Write output to FILENAME diff --git a/tests/ui/invalid-compile-flags/print-without-arg.stderr b/tests/ui/invalid-compile-flags/print-without-arg.stderr index 4163d4e06022..ff9669614360 100644 --- a/tests/ui/invalid-compile-flags/print-without-arg.stderr +++ b/tests/ui/invalid-compile-flags/print-without-arg.stderr @@ -3,5 +3,5 @@ error: Argument to option 'print' missing --print [=] Compiler information to print on stdout (or to a file) INFO may be one of - . + . diff --git a/tests/ui/invalid-compile-flags/print.stderr b/tests/ui/invalid-compile-flags/print.stderr index e8adbfd87d76..e2521ebf26a4 100644 --- a/tests/ui/invalid-compile-flags/print.stderr +++ b/tests/ui/invalid-compile-flags/print.stderr @@ -1,5 +1,5 @@ error: unknown print request: `yyyy` | - = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `backend-has-zstd`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/ui/print-request/backend-has-zstd-unstable.rs b/tests/ui/print-request/backend-has-zstd-unstable.rs new file mode 100644 index 000000000000..cfed4af0c794 --- /dev/null +++ b/tests/ui/print-request/backend-has-zstd-unstable.rs @@ -0,0 +1,8 @@ +//! Check that `--print=backend-has-zstd` is unstable. +//! +//! That print value is intended for use by compiletest, and should probably +//! never be stabilized in this form. + +//@ compile-flags: --print=backend-has-zstd + +//~? ERROR: the `-Z unstable-options` flag must also be passed diff --git a/tests/ui/print-request/backend-has-zstd-unstable.stderr b/tests/ui/print-request/backend-has-zstd-unstable.stderr new file mode 100644 index 000000000000..c7b5aa68d873 --- /dev/null +++ b/tests/ui/print-request/backend-has-zstd-unstable.stderr @@ -0,0 +1,2 @@ +error: the `-Z unstable-options` flag must also be passed to enable the `backend-has-zstd` print option + diff --git a/tests/ui/print-request/print-lints-help.stderr b/tests/ui/print-request/print-lints-help.stderr index 297a3aa79e1f..d39c6326e318 100644 --- a/tests/ui/print-request/print-lints-help.stderr +++ b/tests/ui/print-request/print-lints-help.stderr @@ -1,6 +1,6 @@ error: unknown print request: `lints` | - = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `backend-has-zstd`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` = help: use `-Whelp` to print a list of lints = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information From 66e9c33dcb854428dbb83afcf4303af09f8e910c Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Fri, 5 Dec 2025 04:56:09 +0000 Subject: [PATCH 325/585] Prepare for merging from rust-lang/rust This updates the rust-version file to 864339abf952f07098dd82610256338520167d4a. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 5c4de1da0312..45bf94eb4de4 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -3ff30e7eafc1da7104c3960187d17939172428ed +864339abf952f07098dd82610256338520167d4a From f040a1a9152b6bd080692750183810cb0c37290b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Dec 2025 08:42:24 +0100 Subject: [PATCH 326/585] interpret: test SNaN handling of float min/max and update comments --- .../src/interpret/intrinsics.rs | 52 +++++++++++++------ .../src/interpret/intrinsics/simd.rs | 12 ++--- src/tools/miri/tests/pass/float.rs | 52 ++++++++----------- 3 files changed, 64 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index fa5041daa69e..a7a3bbebed5f 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -40,18 +40,20 @@ pub(crate) enum MinMax { /// In particular, `-0.0` is considered smaller than `+0.0` and /// if either input is NaN, the result is NaN. Minimum, - /// The IEEE-2008 `minNum` operation - see `f32::min` etc. + /// The IEEE-2008 `minNum` operation with the SNaN handling of the + /// IEEE-2019 `minimumNumber` operation - see `f32::min` etc. /// In particular, if the inputs are `-0.0` and `+0.0`, the result is non-deterministic, - /// and if one argument is NaN, the other one is returned. - MinNum, + /// and if one argument is NaN (quiet or signaling), the other one is returned. + MinimumNumber, /// The IEEE-2019 `maximum` operation - see `f32::maximum` etc. /// In particular, `-0.0` is considered smaller than `+0.0` and /// if either input is NaN, the result is NaN. Maximum, - /// The IEEE-2008 `maxNum` operation - see `f32::max` etc. + /// The IEEE-2008 `maxNum` operation with the SNaN handling of the + /// IEEE-2019 `maximumNumber` operation - see `f32::max` etc. /// In particular, if the inputs are `-0.0` and `+0.0`, the result is non-deterministic, - /// and if one argument is NaN, the other one is returned. - MaxNum, + /// and if one argument is NaN (quiet or signaling), the other one is returned. + MaximumNumber, } /// Directly returns an `Allocation` containing an absolute path representation of the given type. @@ -524,10 +526,18 @@ pub fn eval_intrinsic( self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?; } - sym::minnumf16 => self.float_minmax_intrinsic::(args, MinMax::MinNum, dest)?, - sym::minnumf32 => self.float_minmax_intrinsic::(args, MinMax::MinNum, dest)?, - sym::minnumf64 => self.float_minmax_intrinsic::(args, MinMax::MinNum, dest)?, - sym::minnumf128 => self.float_minmax_intrinsic::(args, MinMax::MinNum, dest)?, + sym::minnumf16 => { + self.float_minmax_intrinsic::(args, MinMax::MinimumNumber, dest)? + } + sym::minnumf32 => { + self.float_minmax_intrinsic::(args, MinMax::MinimumNumber, dest)? + } + sym::minnumf64 => { + self.float_minmax_intrinsic::(args, MinMax::MinimumNumber, dest)? + } + sym::minnumf128 => { + self.float_minmax_intrinsic::(args, MinMax::MinimumNumber, dest)? + } sym::minimumf16 => self.float_minmax_intrinsic::(args, MinMax::Minimum, dest)?, sym::minimumf32 => { @@ -538,10 +548,18 @@ pub fn eval_intrinsic( } sym::minimumf128 => self.float_minmax_intrinsic::(args, MinMax::Minimum, dest)?, - sym::maxnumf16 => self.float_minmax_intrinsic::(args, MinMax::MaxNum, dest)?, - sym::maxnumf32 => self.float_minmax_intrinsic::(args, MinMax::MaxNum, dest)?, - sym::maxnumf64 => self.float_minmax_intrinsic::(args, MinMax::MaxNum, dest)?, - sym::maxnumf128 => self.float_minmax_intrinsic::(args, MinMax::MaxNum, dest)?, + sym::maxnumf16 => { + self.float_minmax_intrinsic::(args, MinMax::MaximumNumber, dest)? + } + sym::maxnumf32 => { + self.float_minmax_intrinsic::(args, MinMax::MaximumNumber, dest)? + } + sym::maxnumf64 => { + self.float_minmax_intrinsic::(args, MinMax::MaximumNumber, dest)? + } + sym::maxnumf128 => { + self.float_minmax_intrinsic::(args, MinMax::MaximumNumber, dest)? + } sym::maximumf16 => self.float_minmax_intrinsic::(args, MinMax::Maximum, dest)?, sym::maximumf32 => { @@ -966,16 +984,16 @@ fn float_minmax( { let a: F = a.to_float()?; let b: F = b.to_float()?; - let res = if matches!(op, MinMax::MinNum | MinMax::MaxNum) && a == b { + let res = if matches!(op, MinMax::MinimumNumber | MinMax::MaximumNumber) && a == b { // They are definitely not NaN (those are never equal), but they could be `+0` and `-0`. // Let the machine decide which one to return. M::equal_float_min_max(self, a, b) } else { let result = match op { MinMax::Minimum => a.minimum(b), - MinMax::MinNum => a.min(b), + MinMax::MinimumNumber => a.min(b), MinMax::Maximum => a.maximum(b), - MinMax::MaxNum => a.max(b), + MinMax::MaximumNumber => a.max(b), }; self.adjust_nan(result, &[a, b]) }; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs index bae423840ee1..20de47683122 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs @@ -202,8 +202,8 @@ enum Op { sym::simd_le => Op::MirOp(BinOp::Le), sym::simd_gt => Op::MirOp(BinOp::Gt), sym::simd_ge => Op::MirOp(BinOp::Ge), - sym::simd_fmax => Op::FMinMax(MinMax::MaxNum), - sym::simd_fmin => Op::FMinMax(MinMax::MinNum), + sym::simd_fmax => Op::FMinMax(MinMax::MaximumNumber), + sym::simd_fmin => Op::FMinMax(MinMax::MinimumNumber), sym::simd_saturating_add => Op::SaturatingOp(BinOp::Add), sym::simd_saturating_sub => Op::SaturatingOp(BinOp::Sub), sym::simd_arith_offset => Op::WrappingOffset, @@ -295,8 +295,8 @@ enum Op { sym::simd_reduce_xor => Op::MirOp(BinOp::BitXor), sym::simd_reduce_any => Op::MirOpBool(BinOp::BitOr), sym::simd_reduce_all => Op::MirOpBool(BinOp::BitAnd), - sym::simd_reduce_max => Op::MinMax(MinMax::MaxNum), - sym::simd_reduce_min => Op::MinMax(MinMax::MinNum), + sym::simd_reduce_max => Op::MinMax(MinMax::MaximumNumber), + sym::simd_reduce_min => Op::MinMax(MinMax::MinimumNumber), _ => unreachable!(), }; @@ -320,8 +320,8 @@ enum Op { } else { // Just boring integers, no NaNs to worry about. let mirop = match mmop { - MinMax::MinNum | MinMax::Minimum => BinOp::Le, - MinMax::MaxNum | MinMax::Maximum => BinOp::Ge, + MinMax::MinimumNumber | MinMax::Minimum => BinOp::Le, + MinMax::MaximumNumber | MinMax::Maximum => BinOp::Ge, }; if self.binary_op(mirop, &res, &op)?.to_scalar().to_bool()? { res diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 7b23518d73da..a74a66d5455a 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -48,29 +48,15 @@ macro_rules! assert_approx_eq { }; } -/// From IEEE 754 a Signaling NaN for single precision has the following representation: -/// ``` -/// s | 1111 1111 | 0x..x -/// ```` -/// Were at least one `x` is a 1. -/// -/// This sNaN has the following representation and is used for testing purposes.: -/// ``` -/// 0 | 1111111 | 01..0 -/// ``` -const SNAN_F32: f32 = f32::from_bits(0x7fa00000); - -/// From IEEE 754 a Signaling NaN for double precision has the following representation: -/// ``` -/// s | 1111 1111 111 | 0x..x -/// ```` -/// Were at least one `x` is a 1. -/// -/// This sNaN has the following representation and is used for testing purposes.: -/// ``` -/// 0 | 1111 1111 111 | 01..0 -/// ``` -const SNAN_F64: f64 = f64::from_bits(0x7ff4000000000000); +/// We turn the quiet NaN f*::NAN into a signaling one by flipping the first (most significant) +/// two bits of the mantissa. For this we have to shift by `MANTISSA_DIGITS-3` because: +/// we subtract 1 as the actual mantissa is 1 bit smaller, and 2 more as that's the width +/// if the value we are shifting. +const F16_SNAN: f16 = f16::from_bits(f16::NAN.to_bits() ^ (0b11 << (f16::MANTISSA_DIGITS - 3))); +const F32_SNAN: f32 = f32::from_bits(f32::NAN.to_bits() ^ (0b11 << (f32::MANTISSA_DIGITS - 3))); +const F64_SNAN: f64 = f64::from_bits(f64::NAN.to_bits() ^ (0b11 << (f64::MANTISSA_DIGITS - 3))); +const F128_SNAN: f128 = + f128::from_bits(f128::NAN.to_bits() ^ (0b11 << (f128::MANTISSA_DIGITS - 3))); fn main() { basic(); @@ -757,6 +743,8 @@ fn ops() { assert_eq(f16::NAN.max(-9.0), -9.0); assert_eq((9.0_f16).min(f16::NAN), 9.0); assert_eq((-9.0_f16).max(f16::NAN), -9.0); + assert_eq(F16_SNAN.min(9.0), 9.0); + assert_eq((-9.0_f16).max(F16_SNAN), -9.0); // f32 min/max assert_eq((1.0 as f32).max(-1.0), 1.0); @@ -765,6 +753,8 @@ fn ops() { assert_eq(f32::NAN.max(-9.0), -9.0); assert_eq((9.0 as f32).min(f32::NAN), 9.0); assert_eq((-9.0 as f32).max(f32::NAN), -9.0); + assert_eq(F32_SNAN.min(9.0), 9.0); + assert_eq((-9.0_f32).max(F32_SNAN), -9.0); // f64 min/max assert_eq((1.0 as f64).max(-1.0), 1.0); @@ -773,6 +763,8 @@ fn ops() { assert_eq(f64::NAN.max(-9.0), -9.0); assert_eq((9.0 as f64).min(f64::NAN), 9.0); assert_eq((-9.0 as f64).max(f64::NAN), -9.0); + assert_eq(F64_SNAN.min(9.0), 9.0); + assert_eq((-9.0_f64).max(F64_SNAN), -9.0); // f128 min/max assert_eq((1.0_f128).max(-1.0), 1.0); @@ -781,6 +773,8 @@ fn ops() { assert_eq(f128::NAN.max(-9.0), -9.0); assert_eq((9.0_f128).min(f128::NAN), 9.0); assert_eq((-9.0_f128).max(f128::NAN), -9.0); + assert_eq(F128_SNAN.min(9.0), 9.0); + assert_eq((-9.0_f128).max(F128_SNAN), -9.0); // f16 copysign assert_eq(3.5_f16.copysign(0.42), 3.5_f16); @@ -1548,15 +1542,15 @@ fn test_operations_f128(a: f128, b: f128) { test_operations_f128(25., 18.); // SNaN^0 = (1 | NaN) - check_nondet(|| f32::powf(SNAN_F32, 0.0).is_nan()); - check_nondet(|| f64::powf(SNAN_F64, 0.0).is_nan()); + check_nondet(|| f32::powf(F32_SNAN, 0.0).is_nan()); + check_nondet(|| f64::powf(F64_SNAN, 0.0).is_nan()); // 1^SNaN = (1 | NaN) - check_nondet(|| f32::powf(1.0, SNAN_F32).is_nan()); - check_nondet(|| f64::powf(1.0, SNAN_F64).is_nan()); + check_nondet(|| f32::powf(1.0, F32_SNAN).is_nan()); + check_nondet(|| f64::powf(1.0, F64_SNAN).is_nan()); // same as powf (keep it consistent): // x^SNaN = (1 | NaN) - check_nondet(|| f32::powi(SNAN_F32, 0).is_nan()); - check_nondet(|| f64::powi(SNAN_F64, 0).is_nan()); + check_nondet(|| f32::powi(F32_SNAN, 0).is_nan()); + check_nondet(|| f64::powi(F64_SNAN, 0).is_nan()); } From c2e43fffbc7936c33c68062f71892899bac23ba7 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 5 Dec 2025 16:15:20 +0900 Subject: [PATCH 327/585] moved tests --- src/tools/tidy/src/issues.txt | 1 - .../issue-3429.rs => closures/simple-capture-and-call.rs} | 0 .../issue-2642.rs => for-loop-while/nested-loop-break-unit.rs} | 0 .../issue-47673.rs => imports/duplicate-empty-imports.rs} | 0 .../{issues/issue-3500.rs => match/match-ref-option-pattern.rs} | 0 .../match-stack-overflow-72933-.rs} | 0 .../{issues/issue-3993.rs => privacy/private-item-simple-2.rs} | 0 .../issue-3993.stderr => privacy/private-item-simple-2.stderr} | 0 tests/ui/{issues/issue-47380.rs => str/str-add-operator-2.rs} | 0 .../{issues/issue-47380.stderr => str/str-add-operator-2.stderr} | 0 tests/ui/{issues/issue-47377.rs => str/str-add-operator.rs} | 0 .../{issues/issue-47377.stderr => str/str-add-operator.stderr} | 0 .../normalize-associated-type-in-where-clause.rs} | 0 .../{issues/issue-2151.rs => type/never-type-inference-fail.rs} | 0 .../issue-2151.stderr => type/never-type-inference-fail.stderr} | 0 tests/ui/typeck/{issue-10969.rs => non-function-call-error-2.rs} | 0 .../{issue-10969.stderr => non-function-call-error-2.stderr} | 0 .../{issues/issue-22468.rs => typeck/non-function-call-error.rs} | 0 .../issue-22468.stderr => typeck/non-function-call-error.stderr} | 0 19 files changed, 1 deletion(-) rename tests/ui/{issues/issue-3429.rs => closures/simple-capture-and-call.rs} (100%) rename tests/ui/{issues/issue-2642.rs => for-loop-while/nested-loop-break-unit.rs} (100%) rename tests/ui/{issues/issue-47673.rs => imports/duplicate-empty-imports.rs} (100%) rename tests/ui/{issues/issue-3500.rs => match/match-ref-option-pattern.rs} (100%) rename tests/ui/{issues/issue-72933-match-stack-overflow.rs => match/match-stack-overflow-72933-.rs} (100%) rename tests/ui/{issues/issue-3993.rs => privacy/private-item-simple-2.rs} (100%) rename tests/ui/{issues/issue-3993.stderr => privacy/private-item-simple-2.stderr} (100%) rename tests/ui/{issues/issue-47380.rs => str/str-add-operator-2.rs} (100%) rename tests/ui/{issues/issue-47380.stderr => str/str-add-operator-2.stderr} (100%) rename tests/ui/{issues/issue-47377.rs => str/str-add-operator.rs} (100%) rename tests/ui/{issues/issue-47377.stderr => str/str-add-operator.stderr} (100%) rename tests/ui/{issues/issue-51044.rs => traits/normalize-associated-type-in-where-clause.rs} (100%) rename tests/ui/{issues/issue-2151.rs => type/never-type-inference-fail.rs} (100%) rename tests/ui/{issues/issue-2151.stderr => type/never-type-inference-fail.stderr} (100%) rename tests/ui/typeck/{issue-10969.rs => non-function-call-error-2.rs} (100%) rename tests/ui/typeck/{issue-10969.stderr => non-function-call-error-2.stderr} (100%) rename tests/ui/{issues/issue-22468.rs => typeck/non-function-call-error.rs} (100%) rename tests/ui/{issues/issue-22468.stderr => typeck/non-function-call-error.stderr} (100%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 0f3f2f37ebf2..1500c82c411a 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2892,7 +2892,6 @@ ui/typeck/issue-105946.rs ui/typeck/issue-106929.rs ui/typeck/issue-107087.rs ui/typeck/issue-107775.rs -ui/typeck/issue-10969.rs ui/typeck/issue-110017-format-into-help-deletes-macro.rs ui/typeck/issue-110052.rs ui/typeck/issue-112007-leaked-writeln-macro-internals.rs diff --git a/tests/ui/issues/issue-3429.rs b/tests/ui/closures/simple-capture-and-call.rs similarity index 100% rename from tests/ui/issues/issue-3429.rs rename to tests/ui/closures/simple-capture-and-call.rs diff --git a/tests/ui/issues/issue-2642.rs b/tests/ui/for-loop-while/nested-loop-break-unit.rs similarity index 100% rename from tests/ui/issues/issue-2642.rs rename to tests/ui/for-loop-while/nested-loop-break-unit.rs diff --git a/tests/ui/issues/issue-47673.rs b/tests/ui/imports/duplicate-empty-imports.rs similarity index 100% rename from tests/ui/issues/issue-47673.rs rename to tests/ui/imports/duplicate-empty-imports.rs diff --git a/tests/ui/issues/issue-3500.rs b/tests/ui/match/match-ref-option-pattern.rs similarity index 100% rename from tests/ui/issues/issue-3500.rs rename to tests/ui/match/match-ref-option-pattern.rs diff --git a/tests/ui/issues/issue-72933-match-stack-overflow.rs b/tests/ui/match/match-stack-overflow-72933-.rs similarity index 100% rename from tests/ui/issues/issue-72933-match-stack-overflow.rs rename to tests/ui/match/match-stack-overflow-72933-.rs diff --git a/tests/ui/issues/issue-3993.rs b/tests/ui/privacy/private-item-simple-2.rs similarity index 100% rename from tests/ui/issues/issue-3993.rs rename to tests/ui/privacy/private-item-simple-2.rs diff --git a/tests/ui/issues/issue-3993.stderr b/tests/ui/privacy/private-item-simple-2.stderr similarity index 100% rename from tests/ui/issues/issue-3993.stderr rename to tests/ui/privacy/private-item-simple-2.stderr diff --git a/tests/ui/issues/issue-47380.rs b/tests/ui/str/str-add-operator-2.rs similarity index 100% rename from tests/ui/issues/issue-47380.rs rename to tests/ui/str/str-add-operator-2.rs diff --git a/tests/ui/issues/issue-47380.stderr b/tests/ui/str/str-add-operator-2.stderr similarity index 100% rename from tests/ui/issues/issue-47380.stderr rename to tests/ui/str/str-add-operator-2.stderr diff --git a/tests/ui/issues/issue-47377.rs b/tests/ui/str/str-add-operator.rs similarity index 100% rename from tests/ui/issues/issue-47377.rs rename to tests/ui/str/str-add-operator.rs diff --git a/tests/ui/issues/issue-47377.stderr b/tests/ui/str/str-add-operator.stderr similarity index 100% rename from tests/ui/issues/issue-47377.stderr rename to tests/ui/str/str-add-operator.stderr diff --git a/tests/ui/issues/issue-51044.rs b/tests/ui/traits/normalize-associated-type-in-where-clause.rs similarity index 100% rename from tests/ui/issues/issue-51044.rs rename to tests/ui/traits/normalize-associated-type-in-where-clause.rs diff --git a/tests/ui/issues/issue-2151.rs b/tests/ui/type/never-type-inference-fail.rs similarity index 100% rename from tests/ui/issues/issue-2151.rs rename to tests/ui/type/never-type-inference-fail.rs diff --git a/tests/ui/issues/issue-2151.stderr b/tests/ui/type/never-type-inference-fail.stderr similarity index 100% rename from tests/ui/issues/issue-2151.stderr rename to tests/ui/type/never-type-inference-fail.stderr diff --git a/tests/ui/typeck/issue-10969.rs b/tests/ui/typeck/non-function-call-error-2.rs similarity index 100% rename from tests/ui/typeck/issue-10969.rs rename to tests/ui/typeck/non-function-call-error-2.rs diff --git a/tests/ui/typeck/issue-10969.stderr b/tests/ui/typeck/non-function-call-error-2.stderr similarity index 100% rename from tests/ui/typeck/issue-10969.stderr rename to tests/ui/typeck/non-function-call-error-2.stderr diff --git a/tests/ui/issues/issue-22468.rs b/tests/ui/typeck/non-function-call-error.rs similarity index 100% rename from tests/ui/issues/issue-22468.rs rename to tests/ui/typeck/non-function-call-error.rs diff --git a/tests/ui/issues/issue-22468.stderr b/tests/ui/typeck/non-function-call-error.stderr similarity index 100% rename from tests/ui/issues/issue-22468.stderr rename to tests/ui/typeck/non-function-call-error.stderr From d6db951b22dc3deb48a637aca54c5bb0a3db4795 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 5 Dec 2025 12:14:03 +0100 Subject: [PATCH 328/585] only run `pass-by-value-abi` on 64-bit windows the 32-bit variant differs only in the alignment/size, and I can't test it locally --- tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr | 2 +- tests/ui/c-variadic/pass-by-value-abi.rs | 3 ++- tests/ui/c-variadic/pass-by-value-abi.win.stderr | 2 +- tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr | 6 +++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr index fe11c4288618..a86b28d98ecc 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr @@ -71,7 +71,7 @@ error: fn_abi_of(take_va_list) = FnAbi { conv: C, can_unwind: false, } - --> $DIR/pass-by-value-abi.rs:26:1 + --> $DIR/pass-by-value-abi.rs:27:1 | LL | pub extern "C" fn take_va_list(_: VaList<'_>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/c-variadic/pass-by-value-abi.rs b/tests/ui/c-variadic/pass-by-value-abi.rs index b65442af2472..1e3935067cc2 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.rs +++ b/tests/ui/c-variadic/pass-by-value-abi.rs @@ -12,9 +12,10 @@ //@ [aarch64] ignore-windows //@ [aarch64] ignore-apple //@ [aarch64] ignore-uefi -// Windows dosen't use `#[rustc_pass_indirectly_in_non_rustic_abis]` and is tested in CI, so is here +// Windows doesn't use `#[rustc_pass_indirectly_in_non_rustic_abis]` and is tested in CI, so is here // for comparison. //@ [win] only-windows +//@ [win] only-x86_64 #![feature(rustc_attrs, c_variadic)] #![crate_type = "lib"] diff --git a/tests/ui/c-variadic/pass-by-value-abi.win.stderr b/tests/ui/c-variadic/pass-by-value-abi.win.stderr index e84430859e02..8ff93961f667 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.win.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.win.stderr @@ -74,7 +74,7 @@ error: fn_abi_of(take_va_list) = FnAbi { conv: C, can_unwind: false, } - --> $DIR/pass-by-value-abi.rs:26:1 + --> $DIR/pass-by-value-abi.rs:27:1 | LL | pub extern "C" fn take_va_list(_: VaList<'_>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr index 73f1ccd5992a..aafe89d59e33 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr @@ -71,7 +71,7 @@ error: fn_abi_of(take_va_list) = FnAbi { conv: C, can_unwind: false, } - --> $DIR/pass-by-value-abi.rs:26:1 + --> $DIR/pass-by-value-abi.rs:27:1 | LL | pub extern "C" fn take_va_list(_: VaList<'_>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -151,7 +151,7 @@ error: fn_abi_of(take_va_list_sysv64) = FnAbi { ), can_unwind: false, } - --> $DIR/pass-by-value-abi.rs:36:1 + --> $DIR/pass-by-value-abi.rs:37:1 | LL | pub extern "sysv64" fn take_va_list_sysv64(_: VaList<'_>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -231,7 +231,7 @@ error: fn_abi_of(take_va_list_win64) = FnAbi { ), can_unwind: false, } - --> $DIR/pass-by-value-abi.rs:43:1 + --> $DIR/pass-by-value-abi.rs:44:1 | LL | pub extern "win64" fn take_va_list_win64(_: VaList<'_>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 3e717121a1c96ed9717ebac84ecbeac021dabb21 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Tue, 2 Dec 2025 15:30:06 +0300 Subject: [PATCH 329/585] Generate error delegation body when delegation is not resolved --- compiler/rustc_ast_lowering/src/delegation.rs | 40 +++++++++++++++++-- .../ice-line-bounds-issue-148732.rs | 1 + .../ice-line-bounds-issue-148732.stderr | 18 +++++++-- .../ui/delegation/unused-import-ice-144594.rs | 13 ++++++ .../unused-import-ice-144594.stderr | 15 +++++++ 5 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 tests/ui/delegation/unused-import-ice-144594.rs create mode 100644 tests/ui/delegation/unused-import-ice-144594.stderr diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 9bfcd232221b..e6e88eff2d5b 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -96,7 +96,7 @@ pub(crate) fn lower_delegation( let generics = self.lower_delegation_generics(span); DelegationResults { body_id, sig, ident, generics } } - Err(err) => self.generate_delegation_error(err, span), + Err(err) => self.generate_delegation_error(err, span, delegation), } } @@ -404,6 +404,7 @@ fn generate_delegation_error( &mut self, err: ErrorGuaranteed, span: Span, + delegation: &Delegation, ) -> DelegationResults<'hir> { let generics = self.lower_delegation_generics(span); @@ -418,8 +419,41 @@ fn generate_delegation_error( let header = self.generate_header_error(); let sig = hir::FnSig { decl, header, span }; - let ident = Ident::dummy(); - let body_id = self.lower_body(|this| (&[], this.mk_expr(hir::ExprKind::Err(err), span))); + let ident = self.lower_ident(delegation.ident); + + let body_id = self.lower_body(|this| { + let body_expr = match delegation.body.as_ref() { + Some(box block) => { + // Generates a block when we failed to resolve delegation, where a target expression is its only statement, + // thus there will be no ICEs on further stages of analysis (see #144594) + + // As we generate a void function we want to convert target expression to statement to avoid additional + // errors, such as mismatched return type + let stmts = this.arena.alloc_from_iter([hir::Stmt { + hir_id: this.next_id(), + kind: rustc_hir::StmtKind::Semi( + this.arena.alloc(this.lower_target_expr(block)), + ), + span, + }]); + + let block = this.arena.alloc(hir::Block { + stmts, + expr: None, + hir_id: this.next_id(), + rules: hir::BlockCheckMode::DefaultBlock, + span, + targeted_by_break: false, + }); + + hir::ExprKind::Block(block, None) + } + None => hir::ExprKind::Err(err), + }; + + (&[], this.mk_expr(body_expr, span)) + }); + DelegationResults { ident, generics, body_id, sig } } diff --git a/tests/ui/delegation/ice-line-bounds-issue-148732.rs b/tests/ui/delegation/ice-line-bounds-issue-148732.rs index 699e7d86f258..e44c78476021 100644 --- a/tests/ui/delegation/ice-line-bounds-issue-148732.rs +++ b/tests/ui/delegation/ice-line-bounds-issue-148732.rs @@ -3,6 +3,7 @@ //~| ERROR functions delegation is not yet fully implemented dbg!(b); //~^ ERROR missing lifetime specifier + //~| ERROR `fn() {b}` doesn't implement `Debug` } fn main() {} diff --git a/tests/ui/delegation/ice-line-bounds-issue-148732.stderr b/tests/ui/delegation/ice-line-bounds-issue-148732.stderr index c65b1560818d..1f43ec335448 100644 --- a/tests/ui/delegation/ice-line-bounds-issue-148732.stderr +++ b/tests/ui/delegation/ice-line-bounds-issue-148732.stderr @@ -20,7 +20,7 @@ LL | / reuse a as b { LL | | LL | | LL | | dbg!(b); -LL | | +... | LL | | } | |_^ | @@ -28,7 +28,19 @@ LL | | } = help: add `#![feature(fn_delegation)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 3 previous errors +error[E0277]: `fn() {b}` doesn't implement `Debug` + --> $DIR/ice-line-bounds-issue-148732.rs:4:5 + | +LL | reuse a as b { + | - consider calling this function +... +LL | dbg!(b); + | ^^^^^^^ the trait `Debug` is not implemented for fn item `fn() {b}` + | + = help: use parentheses to call this function: `b()` + = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) -Some errors have detailed explanations: E0106, E0425, E0658. +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0106, E0277, E0425, E0658. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/delegation/unused-import-ice-144594.rs b/tests/ui/delegation/unused-import-ice-144594.rs new file mode 100644 index 000000000000..1d064a4c978f --- /dev/null +++ b/tests/ui/delegation/unused-import-ice-144594.rs @@ -0,0 +1,13 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +reuse a as b { + //~^ ERROR cannot find function `a` in this scope [E0425] + || { + use std::ops::Add; + x.add + //~^ ERROR cannot find value `x` in this scope [E0425] + } +} + +fn main() {} diff --git a/tests/ui/delegation/unused-import-ice-144594.stderr b/tests/ui/delegation/unused-import-ice-144594.stderr new file mode 100644 index 000000000000..1939380235ee --- /dev/null +++ b/tests/ui/delegation/unused-import-ice-144594.stderr @@ -0,0 +1,15 @@ +error[E0425]: cannot find function `a` in this scope + --> $DIR/unused-import-ice-144594.rs:4:7 + | +LL | reuse a as b { + | ^ not found in this scope + +error[E0425]: cannot find value `x` in this scope + --> $DIR/unused-import-ice-144594.rs:8:9 + | +LL | x.add + | ^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. From a27bd22519f4b2acf3b2e05091250f0ce7b3f569 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 5 Dec 2025 12:45:58 +0100 Subject: [PATCH 330/585] clean-up This mostly qualifies variable names with either `is_empty_` or `len_`, to make it easier to understand which of the two methods they relate to --- clippy_lints/src/len_zero.rs | 173 +++++++++++++++++------------------ 1 file changed, 84 insertions(+), 89 deletions(-) diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 877bd34a732b..7c1d62951eaf 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -156,8 +156,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) && let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id() && let Some(local_id) = ty_id.as_local() && let ty_hir_id = cx.tcx.local_def_id_to_hir_id(local_id) - && let Some(output) = - parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder()) + && let Some(output) = LenOutput::new(cx, cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder()) { let (name, kind) = match cx.tcx.hir_node(ty_hir_id) { Node::ForeignItem(x) => (x.ident.name, "extern type"), @@ -401,13 +400,6 @@ fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) { } } -#[derive(Debug, Clone, Copy)] -enum LenOutput { - Integral, - Option(DefId), - Result(DefId), -} - fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { if let ty::Alias(_, alias_ty) = ty.kind() && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir_get_if_local(alias_ty.def_id) @@ -439,42 +431,49 @@ fn is_first_generic_integral<'tcx>(segment: &'tcx PathSegment<'tcx>) -> bool { } } -fn parse_len_output<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option { - if let Some(segment) = extract_future_output(cx, sig.output()) { - let res = segment.res; - - if matches!(res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) { - return Some(LenOutput::Integral); - } - - if let Res::Def(_, def_id) = res - && let Some(res) = match cx.tcx.get_diagnostic_name(def_id) { - Some(sym::Option) => Some(LenOutput::Option(def_id)), - Some(sym::Result) => Some(LenOutput::Result(def_id)), - _ => None, - } - && is_first_generic_integral(segment) - { - return Some(res); - } - - return None; - } - - match *sig.output().kind() { - ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral), - ty::Adt(adt, subs) => match cx.tcx.get_diagnostic_name(adt.did()) { - Some(sym::Option) => subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did())), - Some(sym::Result) => subs.type_at(0).is_integral().then(|| LenOutput::Result(adt.did())), - _ => None, - }, - _ => None, - } +#[derive(Debug, Clone, Copy)] +enum LenOutput { + Integral, + Option(DefId), + Result(DefId), } impl LenOutput { - fn matches_is_empty_output<'tcx>(self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - if let Some(segment) = extract_future_output(cx, ty) { + fn new<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option { + if let Some(segment) = extract_future_output(cx, sig.output()) { + let res = segment.res; + + if matches!(res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) { + return Some(Self::Integral); + } + + if let Res::Def(_, def_id) = res + && let Some(res) = match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::Option) => Some(Self::Option(def_id)), + Some(sym::Result) => Some(Self::Result(def_id)), + _ => None, + } + && is_first_generic_integral(segment) + { + return Some(res); + } + + return None; + } + + match *sig.output().kind() { + ty::Int(_) | ty::Uint(_) => Some(Self::Integral), + ty::Adt(adt, subs) => match cx.tcx.get_diagnostic_name(adt.did()) { + Some(sym::Option) => subs.type_at(0).is_integral().then(|| Self::Option(adt.did())), + Some(sym::Result) => subs.type_at(0).is_integral().then(|| Self::Result(adt.did())), + _ => None, + }, + _ => None, + } + } + + fn matches_is_empty_output<'tcx>(self, cx: &LateContext<'tcx>, is_empty_output: Ty<'tcx>) -> bool { + if let Some(segment) = extract_future_output(cx, is_empty_output) { return match (self, segment.res) { (_, Res::PrimTy(PrimTy::Bool)) => true, (Self::Option(_), Res::Def(_, def_id)) if cx.tcx.is_diagnostic_item(sym::Option, def_id) => true, @@ -483,48 +482,51 @@ fn matches_is_empty_output<'tcx>(self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> }; } - match (self, ty.kind()) { + match (self, is_empty_output.kind()) { (_, &ty::Bool) => true, (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(), (Self::Result(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(), _ => false, } } +} - fn expected_sig(self, self_kind: ImplicitSelfKind) -> String { - let self_ref = match self_kind { - ImplicitSelfKind::RefImm => "&", - ImplicitSelfKind::RefMut => "&mut ", - _ => "", - }; - match self { - Self::Integral => format!("expected signature: `({self_ref}self) -> bool`"), - Self::Option(_) => { - format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Option") - }, - Self::Result(..) => { - format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Result") - }, - } +/// The expected signature of `is_empty`, based on that of `len` +fn expected_is_empty_sig(len_output: LenOutput, len_self_kind: ImplicitSelfKind) -> String { + let self_ref = match len_self_kind { + ImplicitSelfKind::RefImm => "&", + ImplicitSelfKind::RefMut => "&mut ", + _ => "", + }; + match len_output { + LenOutput::Integral => format!("expected signature: `({self_ref}self) -> bool`"), + LenOutput::Option(_) => { + format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Option") + }, + LenOutput::Result(..) => { + format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Result") + }, } } /// Checks if the given signature matches the expectations for `is_empty` fn check_is_empty_sig<'tcx>( cx: &LateContext<'tcx>, - sig: FnSig<'tcx>, - self_kind: ImplicitSelfKind, + is_empty_sig: FnSig<'tcx>, + len_self_kind: ImplicitSelfKind, len_output: LenOutput, ) -> bool { - match &**sig.inputs_and_output { - [arg, res] if len_output.matches_is_empty_output(cx, *res) => { - matches!( - (arg.kind(), self_kind), - (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::RefImm) - | (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::RefMut) - ) || (!arg.is_ref() && matches!(self_kind, ImplicitSelfKind::Imm | ImplicitSelfKind::Mut)) - }, - _ => false, + if let [is_empty_self_arg, is_empty_output] = &**is_empty_sig.inputs_and_output + && len_output.matches_is_empty_output(cx, *is_empty_output) + { + match (is_empty_self_arg.kind(), len_self_kind) { + (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::RefImm) + | (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::RefMut) => true, + (_, ImplicitSelfKind::Imm | ImplicitSelfKind::Mut) if !is_empty_self_arg.is_ref() => true, + _ => false, + } + } else { + false } } @@ -532,9 +534,9 @@ fn check_is_empty_sig<'tcx>( #[expect(clippy::too_many_arguments)] fn check_for_is_empty( cx: &LateContext<'_>, - span: Span, - self_kind: ImplicitSelfKind, - output: LenOutput, + len_span: Span, + len_self_kind: ImplicitSelfKind, + len_output: LenOutput, impl_ty: DefId, item_name: Symbol, item_kind: &str, @@ -556,20 +558,14 @@ fn check_for_is_empty( .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(sym::is_empty)) .find(|item| item.is_fn()); - let (msg, is_empty_span, self_kind) = match is_empty { + let (msg, is_empty_span, is_empty_expected_sig) = match is_empty { None => ( - format!( - "{item_kind} `{}` has a public `len` method, but no `is_empty` method", - item_name.as_str(), - ), + format!("{item_kind} `{item_name}` has a public `len` method, but no `is_empty` method"), None, None, ), Some(is_empty) if !cx.effective_visibilities.is_exported(is_empty.def_id.expect_local()) => ( - format!( - "{item_kind} `{}` has a public `len` method, but a private `is_empty` method", - item_name.as_str(), - ), + format!("{item_kind} `{item_name}` has a public `len` method, but a private `is_empty` method"), Some(cx.tcx.def_span(is_empty.def_id)), None, ), @@ -578,29 +574,28 @@ fn check_for_is_empty( && check_is_empty_sig( cx, cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(), - self_kind, - output, + len_self_kind, + len_output, )) => { ( format!( - "{item_kind} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature", - item_name.as_str(), + "{item_kind} `{item_name}` has a public `len` method, but the `is_empty` method has an unexpected signature", ), Some(cx.tcx.def_span(is_empty.def_id)), - Some(self_kind), + Some(expected_is_empty_sig(len_output, len_self_kind)), ) }, Some(_) => return, }; if !fulfill_or_allowed(cx, LEN_WITHOUT_IS_EMPTY, [len_method_hir_id, ty_decl_hir_id]) { - span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, msg, |db| { + span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, len_span, msg, |db| { if let Some(span) = is_empty_span { db.span_note(span, "`is_empty` defined here"); } - if let Some(self_kind) = self_kind { - db.note(output.expected_sig(self_kind)); + if let Some(expected_sig) = is_empty_expected_sig { + db.note(expected_sig); } }); } From d6b561376e932fc136f2443cc733d830ec160b6d Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 5 Dec 2025 13:53:02 +0100 Subject: [PATCH 331/585] fix(len_without_is_empty): allow `is_empty(&self)` with `len(&mut self)` --- clippy_lints/src/len_zero.rs | 8 ++++++-- tests/ui/len_without_is_empty.rs | 12 ++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 7c1d62951eaf..f5a832f3adfd 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -495,7 +495,7 @@ fn matches_is_empty_output<'tcx>(self, cx: &LateContext<'tcx>, is_empty_output: fn expected_is_empty_sig(len_output: LenOutput, len_self_kind: ImplicitSelfKind) -> String { let self_ref = match len_self_kind { ImplicitSelfKind::RefImm => "&", - ImplicitSelfKind::RefMut => "&mut ", + ImplicitSelfKind::RefMut => "&(mut) ", _ => "", }; match len_output { @@ -520,8 +520,12 @@ fn check_is_empty_sig<'tcx>( && len_output.matches_is_empty_output(cx, *is_empty_output) { match (is_empty_self_arg.kind(), len_self_kind) { + // if `len` takes `&self`, `is_empty` should do so as well (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::RefImm) - | (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::RefMut) => true, + // if `len` takes `&mut self`, `is_empty` may take that _or_ `&self` (#16190) + | (ty::Ref(_, _, Mutability::Mut | Mutability::Not), ImplicitSelfKind::RefMut) => true, + // if len takes `self`, `is_empty` should do so as well + // XXX: we might want to relax this to allow `&self` and `&mut self` (_, ImplicitSelfKind::Imm | ImplicitSelfKind::Mut) if !is_empty_self_arg.is_ref() => true, _ => false, } diff --git a/tests/ui/len_without_is_empty.rs b/tests/ui/len_without_is_empty.rs index 011833072d76..509348628dd6 100644 --- a/tests/ui/len_without_is_empty.rs +++ b/tests/ui/len_without_is_empty.rs @@ -473,4 +473,16 @@ pub fn len(&self) -> usize { } } +// Issue #16190 +pub struct RefMutLenButRefIsEmpty; +impl RefMutLenButRefIsEmpty { + pub fn len(&mut self) -> usize { + todo!() + } + + pub fn is_empty(&self) -> bool { + todo!() + } +} + fn main() {} From 8f59eb017753e4e72f0d2b0a736ba9172002e321 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Thu, 4 Dec 2025 20:59:53 +0100 Subject: [PATCH 332/585] Move attribute lints to `rustc_lint` --- Cargo.lock | 3 +- compiler/rustc_attr_parsing/messages.ftl | 31 ----- .../src/attributes/inline.rs | 5 +- .../src/attributes/link_attrs.rs | 5 +- .../src/attributes/macro_attrs.rs | 15 +-- .../src/attributes/prelude.rs | 2 - .../src/attributes/test_attrs.rs | 13 +- compiler/rustc_attr_parsing/src/context.rs | 20 ++- compiler/rustc_attr_parsing/src/interface.rs | 17 ++- compiler/rustc_attr_parsing/src/lib.rs | 2 - compiler/rustc_attr_parsing/src/lints.rs | 114 ------------------ compiler/rustc_attr_parsing/src/safety.rs | 3 + .../src/session_diagnostics.rs | 65 +--------- .../rustc_attr_parsing/src/target_checking.rs | 31 ++++- .../rustc_attr_parsing/src/validate_attr.rs | 5 +- compiler/rustc_errors/src/lib.rs | 16 +-- compiler/rustc_hir/Cargo.toml | 1 + compiler/rustc_hir/src/lints.rs | 44 +------ compiler/rustc_hir_analysis/Cargo.toml | 2 +- compiler/rustc_hir_analysis/src/lib.rs | 14 ++- compiler/rustc_lint/messages.ftl | 34 ++++++ compiler/rustc_lint/src/early/diagnostics.rs | 54 ++++++++- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_lint/src/lints.rs | 65 ++++++++++ compiler/rustc_lint_defs/src/lib.rs | 32 +++++ compiler/rustc_middle/src/ty/context.rs | 16 +-- compiler/rustc_session/src/session.rs | 17 +-- 27 files changed, 284 insertions(+), 344 deletions(-) delete mode 100644 compiler/rustc_attr_parsing/src/lints.rs diff --git a/Cargo.lock b/Cargo.lock index 2cc2e094e9f9..003bc6adb0e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3945,6 +3945,7 @@ dependencies = [ "rustc_hashes", "rustc_hir_id", "rustc_index", + "rustc_lint_defs", "rustc_macros", "rustc_serialize", "rustc_span", @@ -3962,7 +3963,6 @@ dependencies = [ "rustc_abi", "rustc_arena", "rustc_ast", - "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_feature", @@ -3970,6 +3970,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_infer", + "rustc_lint", "rustc_lint_defs", "rustc_macros", "rustc_middle", diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index a2a5f8ab1423..0d53ed9d97a5 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -14,18 +14,6 @@ attr_parsing_deprecated_item_suggestion = .help = add `#![feature(deprecated_suggestion)]` to the crate root .note = see #94785 for more details -attr_parsing_empty_attribute = - unused attribute - .suggestion = {$valid_without_list -> - [true] remove these parentheses - *[other] remove this attribute - } - .note = {$valid_without_list -> - [true] using `{$attr_path}` with an empty list is equivalent to not using a list at all - *[other] using `{$attr_path}` with an empty list has no effect - } - - attr_parsing_empty_confusables = expected at least one confusable name attr_parsing_empty_link_name = @@ -119,19 +107,9 @@ attr_parsing_invalid_repr_hint_no_value = attr_parsing_invalid_since = 'since' must be a Rust version number, such as "1.31.0" -attr_parsing_invalid_style = {$is_used_as_inner -> - [false] crate-level attribute should be an inner attribute: add an exclamation mark: `#![{$name}]` - *[other] the `#![{$name}]` attribute can only be used at the crate root - } - .note = This attribute does not have an `!`, which means it is applied to this {$target} - attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target} .help = `#[{$name}]` can {$only}be applied to {$applied} .suggestion = remove the attribute -attr_parsing_invalid_target_lint = `#[{$name}]` attribute cannot be used on {$target} - .warn = {-attr_parsing_previously_accepted} - .help = `#[{$name}]` can {$only}be applied to {$applied} - .suggestion = remove the attribute attr_parsing_limit_invalid = `limit` must be a non-negative integer @@ -250,19 +228,10 @@ attr_parsing_unsupported_literal_generic = attr_parsing_unsupported_literal_suggestion = consider removing the prefix -attr_parsing_unused_duplicate = - unused attribute - .suggestion = remove this attribute - .note = attribute also specified here - .warn = {-attr_parsing_previously_accepted} - attr_parsing_unused_multiple = multiple `{$name}` attributes .suggestion = remove this attribute .note = attribute also specified here --attr_parsing_previously_accepted = - this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - attr_parsing_whole_archive_needs_static = linking modifier `whole-archive` is only compatible with `static` linking kind diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index eda272fb7f2b..fba1a663c057 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -3,6 +3,7 @@ // SingleAttributeParser which is what we have two of here. use rustc_hir::attrs::{AttributeKind, InlineAttr}; +use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use super::prelude::*; @@ -56,9 +57,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { - let suggestions = cx.suggestions(); - let span = cx.attr_span; - cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); + cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT); return None; } } diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 5a4a4e759910..46fa8ee71343 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -2,6 +2,7 @@ use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; use rustc_hir::attrs::*; use rustc_session::Session; +use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_session::parse::feature_err; use rustc_span::kw; use rustc_target::spec::{Arch, BinaryFormat}; @@ -71,9 +72,7 @@ fn extend<'c>( // Specifically `#[link = "dl"]` is accepted with a FCW // For more information, see https://github.com/rust-lang/rust/pull/143193 ArgParser::NameValue(nv) if nv.value_as_str().is_some_and(|v| v == sym::dl) => { - let suggestions = cx.suggestions(); - let span = cx.attr_span; - cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); + cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT); return None; } _ => { diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 787003519e78..d2fa1d440f40 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,5 +1,6 @@ use rustc_errors::DiagArgValue; use rustc_hir::attrs::MacroUseArgs; +use rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS; use super::prelude::*; use crate::session_diagnostics::IllFormedAttributeInputLint; @@ -152,23 +153,13 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option false, ArgParser::List(list) => { let Some(l) = list.single() else { - let span = cx.attr_span; - let suggestions = cx.suggestions(); - cx.emit_lint( - AttributeLintKind::InvalidMacroExportArguments { suggestions }, - span, - ); + cx.warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS); return None; }; match l.meta_item().and_then(|i| i.path().word_sym()) { Some(sym::local_inner_macros) => true, _ => { - let span = cx.attr_span; - let suggestions = cx.suggestions(); - cx.emit_lint( - AttributeLintKind::InvalidMacroExportArguments { suggestions }, - span, - ); + cx.warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS); return None; } } diff --git a/compiler/rustc_attr_parsing/src/attributes/prelude.rs b/compiler/rustc_attr_parsing/src/attributes/prelude.rs index 980366b5c372..65c408fa6358 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prelude.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prelude.rs @@ -4,8 +4,6 @@ #[doc(hidden)] pub(super) use rustc_hir::attrs::AttributeKind; #[doc(hidden)] -pub(super) use rustc_hir::lints::AttributeLintKind; -#[doc(hidden)] pub(super) use rustc_hir::{MethodKind, Target}; #[doc(hidden)] pub(super) use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 23ecc0bf7d29..e0b006030758 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -1,3 +1,5 @@ +use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; + use super::prelude::*; pub(crate) struct IgnoreParser; @@ -20,20 +22,13 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option None, ArgParser::NameValue(name_value) => { let Some(str_value) = name_value.value_as_str() else { - let suggestions = cx.suggestions(); - let span = cx.attr_span; - cx.emit_lint( - AttributeLintKind::IllFormedAttributeInput { suggestions }, - span, - ); + cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT); return None; }; Some(str_value) } ArgParser::List(_) => { - let suggestions = cx.suggestions(); - let span = cx.attr_span; - cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); + cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT); return None; } }, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index dcb7341b4b5e..bc74eaad50bc 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -11,6 +11,7 @@ use rustc_hir::lints::{AttributeLint, AttributeLintKind}; use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId}; use rustc_session::Session; +use rustc_session::lint::{Lint, LintId}; use rustc_span::{ErrorGuaranteed, Span, Symbol}; use crate::AttributeParser; @@ -381,7 +382,7 @@ pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuarant /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing /// must be delayed until after HIR is built. This method will take care of the details of /// that. - pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) { + pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) { if !matches!( self.stage.should_emit(), ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true } @@ -389,11 +390,12 @@ pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) { return; } let id = self.target_id; - (self.emit_lint)(AttributeLint { id, span, kind: lint }); + (self.emit_lint)(AttributeLint { lint_id: LintId::of(lint), id, span, kind }); } pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) { self.emit_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, AttributeLintKind::UnusedDuplicate { this: unused_span, other: used_span, @@ -409,6 +411,7 @@ pub(crate) fn warn_unused_duplicate_future_error( unused_span: Span, ) { self.emit_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, AttributeLintKind::UnusedDuplicate { this: unused_span, other: used_span, @@ -632,14 +635,25 @@ pub(crate) fn expected_specific_argument_strings( } pub(crate) fn warn_empty_attribute(&mut self, span: Span) { - let attr_path = self.attr_path.clone(); + let attr_path = self.attr_path.clone().to_string(); let valid_without_list = self.template.word; self.emit_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, AttributeLintKind::EmptyAttribute { first_span: span, attr_path, valid_without_list }, span, ); } + pub(crate) fn warn_ill_formed_attribute_input(&mut self, lint: &'static Lint) { + let suggestions = self.suggestions(); + let span = self.attr_span; + self.emit_lint( + lint, + AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None }, + span, + ); + } + pub(crate) fn suggestions(&self) -> Vec { let style = match self.parsed_description { // If the outer and inner spans are equal, we are parsing an embedded attribute diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 87e29b7b0de6..b26a4a29cd2e 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -8,6 +8,7 @@ use rustc_hir::lints::AttributeLint; use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target}; use rustc_session::Session; +use rustc_session::lint::BuiltinLintDiag; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage}; @@ -115,7 +116,12 @@ pub fn parse_limited_all( OmitDoc::Skip, std::convert::identity, |lint| { - crate::lints::emit_attribute_lint(&lint, sess); + sess.psess.buffer_lint( + lint.lint_id.lint, + lint.span, + lint.id, + BuiltinLintDiag::AttributeLint(lint.kind), + ) }, ) } @@ -183,8 +189,13 @@ pub fn parse_single_args( sess, stage: Early { emit_errors }, }; - let mut emit_lint = |lint| { - crate::lints::emit_attribute_lint(&lint, sess); + let mut emit_lint = |lint: AttributeLint| { + sess.psess.buffer_lint( + lint.lint_id.lint, + lint.span, + lint.id, + BuiltinLintDiag::AttributeLint(lint.kind), + ) }; if let Some(safety) = attr_safety { parser.check_attribute_safety( diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 7a7f2555287a..7cef70f88e1c 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -97,7 +97,6 @@ /// like lists or name-value pairs. pub mod parser; -mod lints; mod safety; mod session_diagnostics; mod target_checking; @@ -111,7 +110,6 @@ pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version}; pub use context::{Early, Late, OmitDoc, ShouldEmit}; pub use interface::AttributeParser; -pub use lints::emit_attribute_lint; pub use session_diagnostics::ParsedDescription; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs deleted file mode 100644 index a23884d7f71e..000000000000 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ /dev/null @@ -1,114 +0,0 @@ -use std::borrow::Cow; - -use rustc_errors::{DiagArgValue, LintEmitter}; -use rustc_hir::Target; -use rustc_hir::lints::{AttributeLint, AttributeLintKind}; -use rustc_span::sym; - -use crate::session_diagnostics; - -pub fn emit_attribute_lint(lint: &AttributeLint, lint_emitter: L) { - let AttributeLint { id, span, kind } = lint; - - match kind { - &AttributeLintKind::UnusedDuplicate { this, other, warning } => lint_emitter - .emit_node_span_lint( - rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - *id, - *span, - session_diagnostics::UnusedDuplicate { this, other, warning }, - ), - AttributeLintKind::IllFormedAttributeInput { suggestions } => { - lint_emitter.emit_node_span_lint( - rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT, - *id, - *span, - session_diagnostics::IllFormedAttributeInput { - num_suggestions: suggestions.len(), - suggestions: DiagArgValue::StrListSepByAnd( - suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), - ), - }, - ); - } - AttributeLintKind::InvalidMacroExportArguments { suggestions } => lint_emitter - .emit_node_span_lint( - rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS, - *id, - *span, - session_diagnostics::IllFormedAttributeInput { - num_suggestions: suggestions.len(), - suggestions: DiagArgValue::StrListSepByAnd( - suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), - ), - }, - ), - AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => { - lint_emitter.emit_node_span_lint( - rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - *id, - *first_span, - session_diagnostics::EmptyAttributeList { - attr_span: *first_span, - attr_path: attr_path.clone(), - valid_without_list: *valid_without_list, - }, - ) - } - AttributeLintKind::InvalidTarget { name, target, applied, only } => lint_emitter - .emit_node_span_lint( - // This check is here because `deprecated` had its own lint group and removing this would be a breaking change - if name.segments[0].name == sym::deprecated - && ![ - Target::Closure, - Target::Expression, - Target::Statement, - Target::Arm, - Target::MacroCall, - ] - .contains(target) - { - rustc_session::lint::builtin::USELESS_DEPRECATED - } else { - rustc_session::lint::builtin::UNUSED_ATTRIBUTES - }, - *id, - *span, - session_diagnostics::InvalidTargetLint { - name: name.clone(), - target: target.plural_name(), - applied: DiagArgValue::StrListSepByAnd( - applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(), - ), - only, - attr_span: *span, - }, - ), - - &AttributeLintKind::InvalidStyle { ref name, is_used_as_inner, target, target_span } => { - lint_emitter.emit_node_span_lint( - rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - *id, - *span, - session_diagnostics::InvalidAttrStyle { - name: name.clone(), - is_used_as_inner, - target_span: (!is_used_as_inner).then_some(target_span), - target, - }, - ) - } - &AttributeLintKind::UnsafeAttrOutsideUnsafe { - attribute_name_span, - sugg_spans: (left, right), - } => lint_emitter.emit_node_span_lint( - rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE, - *id, - *span, - session_diagnostics::UnsafeAttrOutsideUnsafeLint { - span: attribute_name_span, - suggestion: session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion { left, right }, - }, - ), - } -} diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs index ff385bf13aaa..52baf2136173 100644 --- a/compiler/rustc_attr_parsing/src/safety.rs +++ b/compiler/rustc_attr_parsing/src/safety.rs @@ -2,6 +2,8 @@ use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir::AttrPath; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; +use rustc_session::lint::LintId; +use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE; use rustc_span::{Span, sym}; use crate::context::Stage; @@ -74,6 +76,7 @@ pub fn check_attribute_safety( ); } else { emit_lint(AttributeLint { + lint_id: LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE), id: target_id, span: path_span, kind: AttributeLintKind::UnsafeAttrOutsideUnsafe { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index f94f0867451f..c4f6f9c6a38c 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -6,8 +6,8 @@ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, }; use rustc_feature::AttributeTemplate; -use rustc_hir::{AttrPath, Target}; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_hir::AttrPath; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; @@ -417,25 +417,6 @@ pub(crate) struct UnusedMultiple { pub name: Symbol, } -#[derive(LintDiagnostic)] -#[diag(attr_parsing_unused_duplicate)] -pub(crate) struct UnusedDuplicate { - #[suggestion(code = "", applicability = "machine-applicable")] - pub this: Span, - #[note] - pub other: Span, - #[warning] - pub warning: bool, -} - -// FIXME(jdonszelmann): duplicated in rustc_lints, should be moved here completely. -#[derive(LintDiagnostic)] -#[diag(attr_parsing_ill_formed_attribute_input)] -pub(crate) struct IllFormedAttributeInput { - pub num_suggestions: usize, - pub suggestions: DiagArgValue, -} - #[derive(Diagnostic)] #[diag(attr_parsing_ill_formed_attribute_input)] pub(crate) struct IllFormedAttributeInputLint { @@ -501,29 +482,6 @@ pub(crate) struct EmptyConfusables { pub span: Span, } -#[derive(LintDiagnostic)] -#[diag(attr_parsing_empty_attribute)] -#[note] -pub(crate) struct EmptyAttributeList { - #[suggestion(code = "", applicability = "machine-applicable")] - pub attr_span: Span, - pub attr_path: AttrPath, - pub valid_without_list: bool, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_invalid_target_lint)] -#[warning] -#[help] -pub(crate) struct InvalidTargetLint { - pub name: AttrPath, - pub target: &'static str, - pub applied: DiagArgValue, - pub only: &'static str, - #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] - pub attr_span: Span, -} - #[derive(Diagnostic)] #[help] #[diag(attr_parsing_invalid_target)] @@ -803,15 +761,6 @@ pub(crate) struct UnsafeAttrOutsideUnsafe { pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, } -#[derive(LintDiagnostic)] -#[diag(attr_parsing_unsafe_attr_outside_unsafe)] -pub(crate) struct UnsafeAttrOutsideUnsafeLint { - #[label] - pub span: Span, - #[subdiagnostic] - pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, -} - #[derive(Subdiagnostic)] #[multipart_suggestion( attr_parsing_unsafe_attr_outside_unsafe_suggestion, @@ -881,16 +830,6 @@ pub(crate) struct SuffixedLiteralInAttribute { pub span: Span, } -#[derive(LintDiagnostic)] -#[diag(attr_parsing_invalid_style)] -pub(crate) struct InvalidAttrStyle { - pub name: AttrPath, - pub is_used_as_inner: bool, - #[note] - pub target_span: Option, - pub target: Target, -} - #[derive(Diagnostic)] #[diag(attr_parsing_empty_link_name, code = E0454)] pub(crate) struct EmptyLinkName { diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index fabd364d3d7f..88efb910c160 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -5,6 +5,7 @@ use rustc_feature::Features; use rustc_hir::lints::AttributeLintKind; use rustc_hir::{MethodKind, Target}; +use rustc_span::sym; use crate::AttributeParser; use crate::context::{AcceptContext, Stage}; @@ -102,13 +103,31 @@ pub(crate) fn check_target( let allowed_targets = allowed_targets.allowed_targets(); let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features); let name = cx.attr_path.clone(); + + let lint = if name.segments[0].name == sym::deprecated + && ![ + Target::Closure, + Target::Expression, + Target::Statement, + Target::Arm, + Target::MacroCall, + ] + .contains(&target) + { + rustc_session::lint::builtin::USELESS_DEPRECATED + } else { + rustc_session::lint::builtin::UNUSED_ATTRIBUTES + }; + let attr_span = cx.attr_span; cx.emit_lint( + lint, AttributeLintKind::InvalidTarget { - name, - target, + name: name.to_string(), + target: target.plural_name(), only: if only { "only " } else { "" }, applied, + attr_span, }, attr_span, ); @@ -145,15 +164,15 @@ pub(crate) fn check_type( return; } - let lint = AttributeLintKind::InvalidStyle { - name: cx.attr_path.clone(), + let kind = AttributeLintKind::InvalidStyle { + name: cx.attr_path.to_string(), is_used_as_inner: cx.attr_style == AttrStyle::Inner, - target, + target: target.name(), target_span: cx.target_span, }; let attr_span = cx.attr_span; - cx.emit_lint(lint, attr_span); + cx.emit_lint(rustc_session::lint::builtin::UNUSED_ATTRIBUTES, kind, attr_span); } } diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index c57e0baea05f..cd28677b6a8f 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -11,6 +11,7 @@ use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; use rustc_hir::AttrPath; +use rustc_hir::lints::AttributeLintKind; use rustc_parse::parse_in; use rustc_session::errors::report_lit_error; use rustc_session::lint::BuiltinLintDiag; @@ -202,10 +203,10 @@ fn emit_malformed_attribute( ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, - BuiltinLintDiag::IllFormedAttributeInput { + BuiltinLintDiag::AttributeLint(AttributeLintKind::IllFormedAttributeInput { suggestions: suggestions.clone(), docs: template.docs, - }, + }), ); } else { suggestions.sort(); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 5a7a178582e3..12e6700e0b8d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -64,8 +64,8 @@ fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display, }; use rustc_hashes::Hash128; +use rustc_lint_defs::LintExpectationId; pub use rustc_lint_defs::{Applicability, listify, pluralize}; -use rustc_lint_defs::{Lint, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; pub use rustc_span::ErrorGuaranteed; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; @@ -106,20 +106,6 @@ #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24); -/// Used to avoid depending on `rustc_middle` in `rustc_attr_parsing`. -/// Always the `TyCtxt`. -pub trait LintEmitter: Copy { - type Id: Copy; - #[track_caller] - fn emit_node_span_lint( - self, - lint: &'static Lint, - hir_id: Self::Id, - span: impl Into, - decorator: impl for<'a> LintDiagnostic<'a, ()> + DynSend + 'static, - ); -} - #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)] pub enum SuggestionStyle { /// Hide the suggested code when displaying this suggestion inline. diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index 1008a3e787d0..13e73acf0737 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -16,6 +16,7 @@ rustc_error_messages = { path = "../rustc_error_messages" } rustc_hashes = { path = "../rustc_hashes" } rustc_hir_id = { path = "../rustc_hir_id" } rustc_index = { path = "../rustc_index" } +rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index a4c60fd2cc1a..eba2d182d2c4 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -1,8 +1,10 @@ use rustc_data_structures::fingerprint::Fingerprint; +pub use rustc_lint_defs::AttributeLintKind; +use rustc_lint_defs::LintId; use rustc_macros::HashStable_Generic; use rustc_span::Span; -use crate::{AttrPath, HirId, Target}; +use crate::HirId; #[derive(Debug)] pub struct DelayedLints { @@ -24,46 +26,8 @@ pub enum DelayedLint { #[derive(Debug, HashStable_Generic)] pub struct AttributeLint { + pub lint_id: LintId, pub id: Id, pub span: Span, pub kind: AttributeLintKind, } - -#[derive(Debug, HashStable_Generic)] -pub enum AttributeLintKind { - /// Copy of `IllFormedAttributeInput` - /// specifically for the `invalid_macro_export_arguments` lint until that is removed, - /// see - InvalidMacroExportArguments { - suggestions: Vec, - }, - UnusedDuplicate { - this: Span, - other: Span, - warning: bool, - }, - IllFormedAttributeInput { - suggestions: Vec, - }, - EmptyAttribute { - first_span: Span, - attr_path: AttrPath, - valid_without_list: bool, - }, - InvalidTarget { - name: AttrPath, - target: Target, - applied: Vec, - only: &'static str, - }, - InvalidStyle { - name: AttrPath, - is_used_as_inner: bool, - target: Target, - target_span: Span, - }, - UnsafeAttrOutsideUnsafe { - attribute_name_span: Span, - sugg_spans: (Span, Span), - }, -} diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index e5017794d8f2..8d114862b3fe 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -13,7 +13,6 @@ itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } @@ -21,6 +20,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } +rustc_lint = { path = "../rustc_lint" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 1d2a456b555e..538fb8c7df1e 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -158,7 +158,19 @@ pub fn provide(providers: &mut Providers) { fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) { match lint { DelayedLint::AttributeParsing(attribute_lint) => { - rustc_attr_parsing::emit_attribute_lint(attribute_lint, tcx) + tcx.node_span_lint( + attribute_lint.lint_id.lint, + attribute_lint.id, + attribute_lint.span, + |diag| { + rustc_lint::decorate_attribute_lint( + tcx.sess, + Some(tcx), + &attribute_lint.kind, + diag, + ); + }, + ); } } } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 75e7af4c1173..1bcdda96e13a 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -245,6 +245,19 @@ lint_dropping_copy_types = calls to `std::mem::drop` with a value that implement lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing .label = argument has type `{$arg_ty}` +lint_empty_attribute = + unused attribute + .suggestion = {$valid_without_list -> + [true] remove these parentheses + *[other] remove this attribute + } + .note = {$valid_without_list -> + [true] using `{$attr_path}` with an empty list is equivalent to not using a list at all + *[other] using `{$attr_path}` with an empty list has no effect + } + +-lint_previously_accepted = + this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! lint_enum_intrinsics_mem_discriminant = the return value of `mem::discriminant` is unspecified when called with a non-enum type .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum @@ -458,6 +471,17 @@ lint_invalid_reference_casting_note_book = for more information, visit + [false] crate-level attribute should be an inner attribute: add an exclamation mark: `#![{$name}]` + *[other] the `#![{$name}]` attribute can only be used at the crate root + } + .note = This attribute does not have an `!`, which means it is applied to this {$target} + +lint_invalid_target = `#[{$name}]` attribute cannot be used on {$target} + .warn = {-lint_previously_accepted} + .help = `#[{$name}]` can {$only}be applied to {$applied} + .suggestion = remove the attribute + lint_lintpass_by_hand = implementing `LintPass` by hand .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead @@ -890,6 +914,10 @@ lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::` +lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe + .label = usage of unsafe attribute +lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` + lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´ lint_untranslatable_diag = diagnostics should be created using translatable messages @@ -922,6 +950,12 @@ lint_unused_def = unused {$pre}`{$def}`{$post} that must be used lint_unused_delim = unnecessary {$delim} around {$item} .suggestion = remove these {$delim} +lint_unused_duplicate = + unused attribute + .suggestion = remove this attribute + .note = attribute also specified here + .warn = {-lint_previously_accepted} + lint_unused_import_braces = braces around {$node} is unnecessary lint_unused_imports = {$num_snippets -> diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 87ccd114ee97..b654bc848ecf 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -4,6 +4,7 @@ use rustc_errors::{ Applicability, Diag, DiagArgValue, LintDiagnostic, elided_lifetime_in_path_suggestion, }; +use rustc_hir::lints::AttributeLintKind; use rustc_middle::middle::stability; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -301,7 +302,21 @@ pub fn decorate_builtin_lint( BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag) } - BuiltinLintDiag::IllFormedAttributeInput { suggestions, docs } => { + BuiltinLintDiag::AttributeLint(kind) => decorate_attribute_lint(sess, tcx, &kind, diag), + } +} + +pub fn decorate_attribute_lint( + _sess: &Session, + _tcx: Option>, + kind: &AttributeLintKind, + diag: &mut Diag<'_, ()>, +) { + match kind { + &AttributeLintKind::UnusedDuplicate { this, other, warning } => { + lints::UnusedDuplicate { this, other, warning }.decorate_lint(diag) + } + AttributeLintKind::IllFormedAttributeInput { suggestions, docs } => { lints::IllFormedAttributeInput { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( @@ -312,5 +327,42 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag) } + AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => { + lints::EmptyAttributeList { + attr_span: *first_span, + attr_path: attr_path.clone(), + valid_without_list: *valid_without_list, + } + .decorate_lint(diag) + } + AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => { + lints::InvalidTargetLint { + name: name.clone(), + target, + applied: DiagArgValue::StrListSepByAnd( + applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(), + ), + only, + attr_span: *attr_span, + } + .decorate_lint(diag) + } + &AttributeLintKind::InvalidStyle { ref name, is_used_as_inner, target, target_span } => { + lints::InvalidAttrStyle { + name: name.clone(), + is_used_as_inner, + target_span: (!is_used_as_inner).then_some(target_span), + target, + } + .decorate_lint(diag) + } + &AttributeLintKind::UnsafeAttrOutsideUnsafe { + attribute_name_span, + sugg_spans: (left, right), + } => lints::UnsafeAttrOutsideUnsafeLint { + span: attribute_name_span, + suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }, + } + .decorate_lint(diag), } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 78b76e083d41..23afbf6c0d7b 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -129,7 +129,7 @@ #[rustfmt::skip] pub use builtin::{MissingDoc, SoftLints}; pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore}; -pub use early::diagnostics::decorate_builtin_lint; +pub use early::diagnostics::{decorate_attribute_lint, decorate_builtin_lint}; pub use early::{EarlyCheckNode, check_ast_node}; pub use late::{check_crate, late_lint_mod, unerased_lint_store}; pub use levels::LintLevelsBuilder; diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 51708bc04583..4f28d503af3c 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3126,3 +3126,68 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { } } } + +#[derive(LintDiagnostic)] +#[diag(lint_empty_attribute)] +#[note] +pub(crate) struct EmptyAttributeList { + #[suggestion(code = "", applicability = "machine-applicable")] + pub attr_span: Span, + pub attr_path: String, + pub valid_without_list: bool, +} + +#[derive(LintDiagnostic)] +#[diag(lint_invalid_target)] +#[warning] +#[help] +pub(crate) struct InvalidTargetLint { + pub name: String, + pub target: &'static str, + pub applied: DiagArgValue, + pub only: &'static str, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub attr_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_invalid_style)] +pub(crate) struct InvalidAttrStyle { + pub name: String, + pub is_used_as_inner: bool, + #[note] + pub target_span: Option, + pub target: &'static str, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_duplicate)] +pub(crate) struct UnusedDuplicate { + #[suggestion(code = "", applicability = "machine-applicable")] + pub this: Span, + #[note] + pub other: Span, + #[warning] + pub warning: bool, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unsafe_attr_outside_unsafe)] +pub(crate) struct UnsafeAttrOutsideUnsafeLint { + #[label] + pub span: Span, + #[subdiagnostic] + pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + lint_unsafe_attr_outside_unsafe_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { + #[suggestion_part(code = "unsafe(")] + pub left: Span, + #[suggestion_part(code = ")")] + pub right: Span, +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index abdc41eb57c2..3c6e7d04a29d 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -696,10 +696,42 @@ pub enum BuiltinLintDiag { extern_crate: Symbol, local_crate: Symbol, }, + AttributeLint(AttributeLintKind), +} + +#[derive(Debug, HashStable_Generic)] +pub enum AttributeLintKind { + UnusedDuplicate { + this: Span, + other: Span, + warning: bool, + }, IllFormedAttributeInput { suggestions: Vec, docs: Option<&'static str>, }, + EmptyAttribute { + first_span: Span, + attr_path: String, + valid_without_list: bool, + }, + InvalidTarget { + name: String, + target: &'static str, + applied: Vec, + only: &'static str, + attr_span: Span, + }, + InvalidStyle { + name: String, + is_used_as_inner: bool, + target: &'static str, + target_span: Span, + }, + UnsafeAttrOutsideUnsafe { + attribute_name_span: Span, + sugg_spans: (Span, Span), + }, } pub type RegisteredTools = FxIndexSet; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0cd36d5e971d..a16c2232c3a6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -30,7 +30,7 @@ self, DynSend, DynSync, FreezeReadGuard, Lock, RwLock, WorkerLocal, }; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, LintEmitter, MultiSpan, + Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan, }; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; @@ -1534,20 +1534,6 @@ pub struct TyCtxt<'tcx> { gcx: &'tcx GlobalCtxt<'tcx>, } -impl<'tcx> LintEmitter for TyCtxt<'tcx> { - type Id = HirId; - - fn emit_node_span_lint( - self, - lint: &'static Lint, - hir_id: HirId, - span: impl Into, - decorator: impl for<'a> LintDiagnostic<'a, ()>, - ) { - self.emit_node_span_lint(lint, hir_id, span, decorator); - } -} - // Explicitly implement `DynSync` and `DynSend` for `TyCtxt` to short circuit trait resolution. Its // field are asserted to implement these traits below, so this is trivially safe, and it greatly // speeds-up compilation of this crate and its dependents. diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index e52475cdd5bd..acc65fc11a2a 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -6,7 +6,6 @@ use std::{env, io}; use rand::{RngCore, rng}; -use rustc_ast::NodeId; use rustc_data_structures::base_n::{CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; @@ -22,7 +21,7 @@ use rustc_errors::translation::Translator; use rustc_errors::{ Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, FatalAbort, - LintEmitter, TerminalUrl, fallback_fluent_bundle, + TerminalUrl, fallback_fluent_bundle, }; use rustc_hir::limit::Limit; use rustc_macros::HashStable_Generic; @@ -160,20 +159,6 @@ pub struct Session { pub invocation_temp: Option, } -impl LintEmitter for &'_ Session { - type Id = NodeId; - - fn emit_node_span_lint( - self, - lint: &'static rustc_lint_defs::Lint, - node_id: Self::Id, - span: impl Into, - decorator: impl for<'a> rustc_errors::LintDiagnostic<'a, ()> + DynSend + 'static, - ) { - self.psess.buffer_lint(lint, span, node_id, decorator); - } -} - #[derive(Clone, Copy)] pub enum CodegenUnits { /// Specified by the user. In this case we try fairly hard to produce the From 24219203940952557b66e5f8e532e4a78ade256e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Dec 2025 22:40:12 +0100 Subject: [PATCH 333/585] f*::min/max: fix comparing with libm and IEEE operations --- library/core/src/intrinsics/mod.rs | 48 +++++++++++++++--------------- library/core/src/num/f128.rs | 30 ++++++++++--------- library/core/src/num/f16.rs | 30 ++++++++++--------- library/core/src/num/f32.rs | 30 ++++++++++--------- library/core/src/num/f64.rs | 30 ++++++++++--------- 5 files changed, 88 insertions(+), 80 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 2115c5c9a85d..a9735a7e6f31 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2949,9 +2949,9 @@ pub const fn aggregate_raw_ptr(data: D, meta: M) /// Returns the minimum of two `f16` values, ignoring NaN. /// -/// This behaves like IEEE 754-2008 minNum. In particular: -/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal -/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. +/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If +/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` +/// and `-0.0`), either input may be returned non-deterministically. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -2965,9 +2965,9 @@ pub const fn aggregate_raw_ptr(data: D, meta: M) /// Returns the minimum of two `f32` values, ignoring NaN. /// -/// This behaves like IEEE 754-2008 minNum. In particular: -/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal -/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. +/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If +/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` +/// and `-0.0`), either input may be returned non-deterministically. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -2982,9 +2982,9 @@ pub const fn aggregate_raw_ptr(data: D, meta: M) /// Returns the minimum of two `f64` values, ignoring NaN. /// -/// This behaves like IEEE 754-2008 minNum. In particular: -/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal -/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. +/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If +/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` +/// and `-0.0`), either input may be returned non-deterministically. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -2999,9 +2999,9 @@ pub const fn aggregate_raw_ptr(data: D, meta: M) /// Returns the minimum of two `f128` values, ignoring NaN. /// -/// This behaves like IEEE 754-2008 minNum. In particular: -/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal -/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. +/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If +/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` +/// and `-0.0`), either input may be returned non-deterministically. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -3115,9 +3115,9 @@ pub const fn minimumf128(x: f128, y: f128) -> f128 { /// Returns the maximum of two `f16` values, ignoring NaN. /// -/// This behaves like IEEE 754-2008 maxNum. In particular: -/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal -/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. +/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If +/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` +/// and `-0.0`), either input may be returned non-deterministically. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -3131,9 +3131,9 @@ pub const fn minimumf128(x: f128, y: f128) -> f128 { /// Returns the maximum of two `f32` values, ignoring NaN. /// -/// This behaves like IEEE 754-2008 maxNum. In particular: -/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal -/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. +/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If +/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` +/// and `-0.0`), either input may be returned non-deterministically. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -3148,9 +3148,9 @@ pub const fn minimumf128(x: f128, y: f128) -> f128 { /// Returns the maximum of two `f64` values, ignoring NaN. /// -/// This behaves like IEEE 754-2008 maxNum. In particular: -/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal -/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. +/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If +/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` +/// and `-0.0`), either input may be returned non-deterministically. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -3165,9 +3165,9 @@ pub const fn minimumf128(x: f128, y: f128) -> f128 { /// Returns the maximum of two `f128` values, ignoring NaN. /// -/// This behaves like IEEE 754-2008 maxNum. In particular: -/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal -/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. +/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If +/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` +/// and `-0.0`), either input may be returned non-deterministically. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 9b9cc80a606c..3d1f48ca6e1a 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -694,14 +694,15 @@ pub const fn to_radians(self) -> f128 { /// Returns the maximum of the two numbers, ignoring NaN. /// - /// If exactly one of the arguments is NaN, then the other argument is returned. If both - /// arguments are NaN, the return value is NaN, with the bit pattern picked using the usual - /// [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs compare equal (such - /// as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. + /// If exactly one of the arguments is NaN (quiet or signaling), then the other argument is + /// returned. If both arguments are NaN, the return value is NaN, with the bit pattern picked + /// using the usual [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs + /// compare equal (such as for the case of `+0.0` and `-0.0`), either input may be returned + /// non-deterministically. /// - /// This follows the IEEE 754-2008 semantics for `maxNum`, except for handling of signaling NaNs; - /// this function handles all NaNs the same way and avoids `maxNum`'s problems with associativity. - /// This also matches the behavior of libm’s `fmax`. + /// The handling of NaNs follows the IEEE 754-2019 semantics for `maximumNumber`, treating all + /// NaNs the same way to ensure the operation is associative. The handling of signed zeros + /// follows the IEEE 754-2008 semantics for `maxNum`. /// /// ``` /// #![feature(f128)] @@ -725,14 +726,15 @@ pub const fn max(self, other: f128) -> f128 { /// Returns the minimum of the two numbers, ignoring NaN. /// - /// If exactly one of the arguments is NaN, then the other argument is returned. If both - /// arguments are NaN, the return value is NaN, with the bit pattern picked using the usual - /// [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs compare equal (such - /// as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. + /// If exactly one of the arguments is NaN (quiet or signaling), then the other argument is + /// returned. If both arguments are NaN, the return value is NaN, with the bit pattern picked + /// using the usual [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs + /// compare equal (such as for the case of `+0.0` and `-0.0`), either input may be returned + /// non-deterministically. /// - /// This follows the IEEE 754-2008 semantics for `minNum`, except for handling of signaling NaNs; - /// this function handles all NaNs the same way and avoids `minNum`'s problems with associativity. - /// This also matches the behavior of libm’s `fmin`. + /// The handling of NaNs follows the IEEE 754-2019 semantics for `minimumNumber`, treating all + /// NaNs the same way to ensure the operation is associative. The handling of signed zeros + /// follows the IEEE 754-2008 semantics for `minNum`. /// /// ``` /// #![feature(f128)] diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index ab765ebcb7fa..937394b339cc 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -687,14 +687,15 @@ pub const fn to_radians(self) -> f16 { /// Returns the maximum of the two numbers, ignoring NaN. /// - /// If exactly one of the arguments is NaN, then the other argument is returned. If both - /// arguments are NaN, the return value is NaN, with the bit pattern picked using the usual - /// [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs compare equal (such - /// as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. + /// If exactly one of the arguments is NaN (quiet or signaling), then the other argument is + /// returned. If both arguments are NaN, the return value is NaN, with the bit pattern picked + /// using the usual [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs + /// compare equal (such as for the case of `+0.0` and `-0.0`), either input may be returned + /// non-deterministically. /// - /// This follows the IEEE 754-2008 semantics for `maxNum`, except for handling of signaling NaNs; - /// this function handles all NaNs the same way and avoids `maxNum`'s problems with associativity. - /// This also matches the behavior of libm’s `fmax`. + /// The handling of NaNs follows the IEEE 754-2019 semantics for `maximumNumber`, treating all + /// NaNs the same way to ensure the operation is associative. The handling of signed zeros + /// follows the IEEE 754-2008 semantics for `maxNum`. /// /// ``` /// #![feature(f16)] @@ -717,14 +718,15 @@ pub const fn max(self, other: f16) -> f16 { /// Returns the minimum of the two numbers, ignoring NaN. /// - /// If exactly one of the arguments is NaN, then the other argument is returned. If both - /// arguments are NaN, the return value is NaN, with the bit pattern picked using the usual - /// [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs compare equal (such - /// as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. + /// If exactly one of the arguments is NaN (quiet or signaling), then the other argument is + /// returned. If both arguments are NaN, the return value is NaN, with the bit pattern picked + /// using the usual [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs + /// compare equal (such as for the case of `+0.0` and `-0.0`), either input may be returned + /// non-deterministically. /// - /// This follows the IEEE 754-2008 semantics for `minNum`, except for handling of signaling NaNs; - /// this function handles all NaNs the same way and avoids `minNum`'s problems with associativity. - /// This also matches the behavior of libm’s `fmin`. + /// The handling of NaNs follows the IEEE 754-2019 semantics for `minimumNumber`, treating all + /// NaNs the same way to ensure the operation is associative. The handling of signed zeros + /// follows the IEEE 754-2008 semantics for `minNum`. /// /// ``` /// #![feature(f16)] diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 361f273ead01..04760ddc1d67 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -897,14 +897,15 @@ pub const fn to_radians(self) -> f32 { /// Returns the maximum of the two numbers, ignoring NaN. /// - /// If exactly one of the arguments is NaN, then the other argument is returned. If both - /// arguments are NaN, the return value is NaN, with the bit pattern picked using the usual - /// [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs compare equal (such - /// as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. + /// If exactly one of the arguments is NaN (quiet or signaling), then the other argument is + /// returned. If both arguments are NaN, the return value is NaN, with the bit pattern picked + /// using the usual [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs + /// compare equal (such as for the case of `+0.0` and `-0.0`), either input may be returned + /// non-deterministically. /// - /// This follows the IEEE 754-2008 semantics for `maxNum`, except for handling of signaling NaNs; - /// this function handles all NaNs the same way and avoids `maxNum`'s problems with associativity. - /// This also matches the behavior of libm’s `fmax`. + /// The handling of NaNs follows the IEEE 754-2019 semantics for `maximumNumber`, treating all + /// NaNs the same way to ensure the operation is associative. The handling of signed zeros + /// follows the IEEE 754-2008 semantics for `maxNum`. /// /// ``` /// let x = 1.0f32; @@ -923,14 +924,15 @@ pub const fn max(self, other: f32) -> f32 { /// Returns the minimum of the two numbers, ignoring NaN. /// - /// If exactly one of the arguments is NaN, then the other argument is returned. If both - /// arguments are NaN, the return value is NaN, with the bit pattern picked using the usual - /// [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs compare equal (such - /// as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. + /// If exactly one of the arguments is NaN (quiet or signaling), then the other argument is + /// returned. If both arguments are NaN, the return value is NaN, with the bit pattern picked + /// using the usual [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs + /// compare equal (such as for the case of `+0.0` and `-0.0`), either input may be returned + /// non-deterministically. /// - /// This follows the IEEE 754-2008 semantics for `minNum`, except for handling of signaling NaNs; - /// this function handles all NaNs the same way and avoids `minNum`'s problems with associativity. - /// This also matches the behavior of libm’s `fmin`. + /// The handling of NaNs follows the IEEE 754-2019 semantics for `minimumNumber`, treating all + /// NaNs the same way to ensure the operation is associative. The handling of signed zeros + /// follows the IEEE 754-2008 semantics for `minNum`. /// /// ``` /// let x = 1.0f32; diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 17a908643a41..e7cab39dca44 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -915,14 +915,15 @@ pub const fn to_radians(self) -> f64 { /// Returns the maximum of the two numbers, ignoring NaN. /// - /// If exactly one of the arguments is NaN, then the other argument is returned. If both - /// arguments are NaN, the return value is NaN, with the bit pattern picked using the usual - /// [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs compare equal (such - /// as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. + /// If exactly one of the arguments is NaN (quiet or signaling), then the other argument is + /// returned. If both arguments are NaN, the return value is NaN, with the bit pattern picked + /// using the usual [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs + /// compare equal (such as for the case of `+0.0` and `-0.0`), either input may be returned + /// non-deterministically. /// - /// This follows the IEEE 754-2008 semantics for `maxNum`, except for handling of signaling NaNs; - /// this function handles all NaNs the same way and avoids `maxNum`'s problems with associativity. - /// This also matches the behavior of libm’s `fmax`. + /// The handling of NaNs follows the IEEE 754-2019 semantics for `maximumNumber`, treating all + /// NaNs the same way to ensure the operation is associative. The handling of signed zeros + /// follows the IEEE 754-2008 semantics for `maxNum`. /// /// ``` /// let x = 1.0_f64; @@ -941,14 +942,15 @@ pub const fn max(self, other: f64) -> f64 { /// Returns the minimum of the two numbers, ignoring NaN. /// - /// If exactly one of the arguments is NaN, then the other argument is returned. If both - /// arguments are NaN, the return value is NaN, with the bit pattern picked using the usual - /// [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs compare equal (such - /// as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. + /// If exactly one of the arguments is NaN (quiet or signaling), then the other argument is + /// returned. If both arguments are NaN, the return value is NaN, with the bit pattern picked + /// using the usual [rules for arithmetic operations](f32#nan-bit-patterns). If the inputs + /// compare equal (such as for the case of `+0.0` and `-0.0`), either input may be returned + /// non-deterministically. /// - /// This follows the IEEE 754-2008 semantics for `minNum`, except for handling of signaling NaNs; - /// this function handles all NaNs the same way and avoids `minNum`'s problems with associativity. - /// This also matches the behavior of libm’s `fmin`. + /// The handling of NaNs follows the IEEE 754-2019 semantics for `minimumNumber`, treating all + /// NaNs the same way to ensure the operation is associative. The handling of signed zeros + /// follows the IEEE 754-2008 semantics for `minNum`. /// /// ``` /// let x = 1.0_f64; From a1f4caf46751d3e166a35897fa064c394c3a16dd Mon Sep 17 00:00:00 2001 From: Paul Murphy Date: Thu, 4 Dec 2025 17:52:55 -0600 Subject: [PATCH 334/585] Restrict spe_acc to PowerPC SPE targets Update the tests, add powerpc-*-gnuspe testing, and create a distinct clobber_abi list for PowerPC SPE targets. Note, the SPE target does not have vector, vector-scalar, or floating-point specific registers. --- compiler/rustc_target/src/asm/mod.rs | 24 +- compiler/rustc_target/src/asm/powerpc.rs | 12 +- tests/codegen-llvm/asm/powerpc-clobbers.rs | 31 +- tests/ui/asm/powerpc/bad-reg.aix64.stderr | 238 ++--- tests/ui/asm/powerpc/bad-reg.powerpc.stderr | 268 ++--- tests/ui/asm/powerpc/bad-reg.powerpc64.stderr | 258 ++--- .../ui/asm/powerpc/bad-reg.powerpc64le.stderr | 238 ++--- .../ui/asm/powerpc/bad-reg.powerpcspe.stderr | 938 ++++++++++++++++++ tests/ui/asm/powerpc/bad-reg.rs | 52 +- 9 files changed, 1547 insertions(+), 512 deletions(-) create mode 100644 tests/ui/asm/powerpc/bad-reg.powerpcspe.stderr diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index c6d22a51774c..05b24d710948 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -5,7 +5,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::Symbol; -use crate::spec::{Arch, RelocModel, Target}; +use crate::spec::{Abi, Arch, RelocModel, Target}; pub struct ModifierInfo { pub modifier: char, @@ -936,6 +936,7 @@ pub enum InlineAsmClobberAbi { RiscVE, LoongArch, PowerPC, + PowerPCSPE, S390x, Bpf, Msp430, @@ -1000,7 +1001,11 @@ pub fn parse( _ => Err(&["C", "system"]), }, InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => match name { - "C" | "system" => Ok(InlineAsmClobberAbi::PowerPC), + "C" | "system" => Ok(if target.abi == Abi::Spe { + InlineAsmClobberAbi::PowerPCSPE + } else { + InlineAsmClobberAbi::PowerPC + }), _ => Err(&["C", "system"]), }, InlineAsmArch::S390x => match name { @@ -1271,8 +1276,21 @@ macro_rules! clobbered_regs { ctr, lr, xer, + } + }, + InlineAsmClobberAbi::PowerPCSPE => clobbered_regs! { + PowerPC PowerPCInlineAsmReg { + // r0, r3-r12 + r0, + r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, - // These are only supported on PowerPC SPE targets. + // cr0-cr1, cr5-cr7, ctr, lr, xer, spe_acc + cr0, cr1, + cr5, cr6, cr7, + ctr, + lr, + xer, spe_acc, } }, diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index 4fbe8adcbc61..fd0e118fcc87 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -115,6 +115,16 @@ fn reserved_v20to31( } } +fn spe_acc_target_check( + _arch: InlineAsmArch, + _reloc_model: RelocModel, + _target_features: &FxIndexSet, + target: &Target, + _is_clobber: bool, +) -> Result<(), &'static str> { + if target.abi == Abi::Spe { Ok(()) } else { Err("spe_acc is only available on spe targets") } +} + def_regs! { PowerPC PowerPCInlineAsmReg PowerPCInlineAsmRegClass { r0: reg = ["r0", "0"], @@ -286,7 +296,7 @@ fn reserved_v20to31( ctr: ctr = ["ctr"], lr: lr = ["lr"], xer: xer = ["xer"], - spe_acc: spe_acc = ["spe_acc"], + spe_acc: spe_acc = ["spe_acc"] % spe_acc_target_check, #error = ["r1", "1", "sp"] => "the stack pointer cannot be used as an operand for inline asm", #error = ["r2", "2"] => diff --git a/tests/codegen-llvm/asm/powerpc-clobbers.rs b/tests/codegen-llvm/asm/powerpc-clobbers.rs index 6abf82cb0f4b..c146d58e4ab6 100644 --- a/tests/codegen-llvm/asm/powerpc-clobbers.rs +++ b/tests/codegen-llvm/asm/powerpc-clobbers.rs @@ -1,11 +1,13 @@ //@ add-minicore -//@ revisions: powerpc powerpc64 powerpc64le aix64 +//@ revisions: powerpc powerpc64 powerpc64le aix64 powerpcspe //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu //@[powerpc] needs-llvm-components: powerpc //@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu //@[powerpc64] needs-llvm-components: powerpc //@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu //@[powerpc64le] needs-llvm-components: powerpc +//@[powerpcspe] compile-flags: --target powerpc-unknown-linux-gnuspe +//@[powerpcspe] needs-llvm-components: powerpc //@[aix64] compile-flags: --target powerpc64-ibm-aix //@[aix64] needs-llvm-components: powerpc // ignore-tidy-linelength @@ -67,12 +69,22 @@ pub unsafe fn vs32_clobber() { asm!("", out("vs32") _, options(nostack, nomem, preserves_flags)); } +// This register is only available on SPE targets. +// CHECK-LABEL: @spe_acc_clobber +// powerpcspe: call void asm sideeffect "", "~{spe_acc}"() +#[no_mangle] +pub unsafe fn spe_acc_clobber() { + #[cfg(target_abi = "spe")] + asm!("", out("spe_acc") _, options(nostack, nomem, preserves_flags)); +} + // Output format depends on the availability of altivec and vsx // CHECK-LABEL: @clobber_abi -// powerpc: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() -// powerpc64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() -// powerpc64le: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() -// aix64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() +// powerpc: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() +// powerpc64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() +// powerpc64le: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() +// aix64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() +// powerpcspe: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() #[no_mangle] pub unsafe fn clobber_abi() { asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); @@ -104,10 +116,11 @@ pub unsafe fn clobber_preservesflags() { // Output format depends on the availability of altivec and vsx // CHECK-LABEL: @clobber_abi_no_preserves_flags #[no_mangle] -// powerpc: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() -// powerpc64: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() -// powerpc64le: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() -// aix64: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() +// powerpc: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() +// powerpc64: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{vs0},~{vs1},~{vs2},~{vs3},~{vs4},~{vs5},~{vs6},~{vs7},~{vs8},~{vs9},~{vs10},~{vs11},~{vs12},~{vs13},~{vs14},~{vs15},~{vs16},~{vs17},~{vs18},~{vs19},~{vs20},~{vs21},~{vs22},~{vs23},~{vs24},~{vs25},~{vs26},~{vs27},~{vs28},~{vs29},~{vs30},~{vs31},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() +// powerpc64le: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() +// aix64: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={vs0},={vs1},={vs2},={vs3},={vs4},={vs5},={vs6},={vs7},={vs8},={vs9},={vs10},={vs11},={vs12},={vs13},={vs14},={vs15},={vs16},={vs17},={vs18},={vs19},={vs20},={vs21},={vs22},={vs23},={vs24},={vs25},={vs26},={vs27},={vs28},={vs29},={vs30},={vs31},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() +// powerpcspe: asm sideeffect "nop", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer},~{spe_acc}"() pub unsafe fn clobber_abi_no_preserves_flags() { // Use a nop to prevent aliasing of identical functions here. asm!("nop", clobber_abi("C"), options(nostack, nomem)); diff --git a/tests/ui/asm/powerpc/bad-reg.aix64.stderr b/tests/ui/asm/powerpc/bad-reg.aix64.stderr index 4490053215b5..c7373780e382 100644 --- a/tests/ui/asm/powerpc/bad-reg.aix64.stderr +++ b/tests/ui/asm/powerpc/bad-reg.aix64.stderr @@ -1,131 +1,131 @@ error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:36:18 + --> $DIR/bad-reg.rs:38:18 | LL | asm!("", out("sp") _); | ^^^^^^^^^^^ error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:38:18 + --> $DIR/bad-reg.rs:40:18 | LL | asm!("", out("r2") _); | ^^^^^^^^^^^ error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:44:18 + --> $DIR/bad-reg.rs:46:18 | LL | asm!("", out("r30") _); | ^^^^^^^^^^^^ error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:46:18 + --> $DIR/bad-reg.rs:48:18 | LL | asm!("", out("fp") _); | ^^^^^^^^^^^ error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:48:18 + --> $DIR/bad-reg.rs:50:18 | LL | asm!("", out("vrsave") _); | ^^^^^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:137:18 + --> $DIR/bad-reg.rs:139:18 | LL | asm!("", in("cr") x); | ^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:140:18 + --> $DIR/bad-reg.rs:142:18 | LL | asm!("", out("cr") x); | ^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:143:26 + --> $DIR/bad-reg.rs:145:26 | LL | asm!("/* {} */", in(cr) x); | ^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:146:26 + --> $DIR/bad-reg.rs:148:26 | LL | asm!("/* {} */", out(cr) _); | ^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:150:18 + --> $DIR/bad-reg.rs:152:18 | LL | asm!("", in("ctr") x); | ^^^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:153:18 + --> $DIR/bad-reg.rs:155:18 | LL | asm!("", out("ctr") x); | ^^^^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:156:26 + --> $DIR/bad-reg.rs:158:26 | LL | asm!("/* {} */", in(ctr) x); | ^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:159:26 + --> $DIR/bad-reg.rs:161:26 | LL | asm!("/* {} */", out(ctr) _); | ^^^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:163:18 + --> $DIR/bad-reg.rs:165:18 | LL | asm!("", in("lr") x); | ^^^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:166:18 + --> $DIR/bad-reg.rs:168:18 | LL | asm!("", out("lr") x); | ^^^^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:169:26 + --> $DIR/bad-reg.rs:171:26 | LL | asm!("/* {} */", in(lr) x); | ^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:172:26 + --> $DIR/bad-reg.rs:174:26 | LL | asm!("/* {} */", out(lr) _); | ^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:176:18 + --> $DIR/bad-reg.rs:178:18 | LL | asm!("", in("xer") x); | ^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:179:18 + --> $DIR/bad-reg.rs:181:18 | LL | asm!("", out("xer") x); | ^^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:182:26 + --> $DIR/bad-reg.rs:184:26 | LL | asm!("/* {} */", in(xer) x); | ^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:185:26 + --> $DIR/bad-reg.rs:187:26 | LL | asm!("/* {} */", out(xer) _); | ^^^^^^^^^^ error: register `cr0` conflicts with register `cr` - --> $DIR/bad-reg.rs:189:31 + --> $DIR/bad-reg.rs:191:31 | LL | asm!("", out("cr") _, out("cr0") _); | ----------- ^^^^^^^^^^^^ register `cr0` @@ -133,7 +133,7 @@ LL | asm!("", out("cr") _, out("cr0") _); | register `cr` error: register `cr1` conflicts with register `cr` - --> $DIR/bad-reg.rs:191:31 + --> $DIR/bad-reg.rs:193:31 | LL | asm!("", out("cr") _, out("cr1") _); | ----------- ^^^^^^^^^^^^ register `cr1` @@ -141,7 +141,7 @@ LL | asm!("", out("cr") _, out("cr1") _); | register `cr` error: register `cr2` conflicts with register `cr` - --> $DIR/bad-reg.rs:193:31 + --> $DIR/bad-reg.rs:195:31 | LL | asm!("", out("cr") _, out("cr2") _); | ----------- ^^^^^^^^^^^^ register `cr2` @@ -149,7 +149,7 @@ LL | asm!("", out("cr") _, out("cr2") _); | register `cr` error: register `cr3` conflicts with register `cr` - --> $DIR/bad-reg.rs:195:31 + --> $DIR/bad-reg.rs:197:31 | LL | asm!("", out("cr") _, out("cr3") _); | ----------- ^^^^^^^^^^^^ register `cr3` @@ -157,7 +157,7 @@ LL | asm!("", out("cr") _, out("cr3") _); | register `cr` error: register `cr4` conflicts with register `cr` - --> $DIR/bad-reg.rs:197:31 + --> $DIR/bad-reg.rs:199:31 | LL | asm!("", out("cr") _, out("cr4") _); | ----------- ^^^^^^^^^^^^ register `cr4` @@ -165,7 +165,7 @@ LL | asm!("", out("cr") _, out("cr4") _); | register `cr` error: register `cr5` conflicts with register `cr` - --> $DIR/bad-reg.rs:199:31 + --> $DIR/bad-reg.rs:201:31 | LL | asm!("", out("cr") _, out("cr5") _); | ----------- ^^^^^^^^^^^^ register `cr5` @@ -173,7 +173,7 @@ LL | asm!("", out("cr") _, out("cr5") _); | register `cr` error: register `cr6` conflicts with register `cr` - --> $DIR/bad-reg.rs:201:31 + --> $DIR/bad-reg.rs:203:31 | LL | asm!("", out("cr") _, out("cr6") _); | ----------- ^^^^^^^^^^^^ register `cr6` @@ -181,7 +181,7 @@ LL | asm!("", out("cr") _, out("cr6") _); | register `cr` error: register `cr7` conflicts with register `cr` - --> $DIR/bad-reg.rs:203:31 + --> $DIR/bad-reg.rs:205:31 | LL | asm!("", out("cr") _, out("cr7") _); | ----------- ^^^^^^^^^^^^ register `cr7` @@ -189,7 +189,7 @@ LL | asm!("", out("cr") _, out("cr7") _); | register `cr` error: register `vs0` conflicts with register `f0` - --> $DIR/bad-reg.rs:206:31 + --> $DIR/bad-reg.rs:208:31 | LL | asm!("", out("f0") _, out("vs0") _); | ----------- ^^^^^^^^^^^^ register `vs0` @@ -197,7 +197,7 @@ LL | asm!("", out("f0") _, out("vs0") _); | register `f0` error: register `vs1` conflicts with register `f1` - --> $DIR/bad-reg.rs:208:31 + --> $DIR/bad-reg.rs:210:31 | LL | asm!("", out("f1") _, out("vs1") _); | ----------- ^^^^^^^^^^^^ register `vs1` @@ -205,7 +205,7 @@ LL | asm!("", out("f1") _, out("vs1") _); | register `f1` error: register `vs2` conflicts with register `f2` - --> $DIR/bad-reg.rs:210:31 + --> $DIR/bad-reg.rs:212:31 | LL | asm!("", out("f2") _, out("vs2") _); | ----------- ^^^^^^^^^^^^ register `vs2` @@ -213,7 +213,7 @@ LL | asm!("", out("f2") _, out("vs2") _); | register `f2` error: register `vs3` conflicts with register `f3` - --> $DIR/bad-reg.rs:212:31 + --> $DIR/bad-reg.rs:214:31 | LL | asm!("", out("f3") _, out("vs3") _); | ----------- ^^^^^^^^^^^^ register `vs3` @@ -221,7 +221,7 @@ LL | asm!("", out("f3") _, out("vs3") _); | register `f3` error: register `vs4` conflicts with register `f4` - --> $DIR/bad-reg.rs:214:31 + --> $DIR/bad-reg.rs:216:31 | LL | asm!("", out("f4") _, out("vs4") _); | ----------- ^^^^^^^^^^^^ register `vs4` @@ -229,7 +229,7 @@ LL | asm!("", out("f4") _, out("vs4") _); | register `f4` error: register `vs5` conflicts with register `f5` - --> $DIR/bad-reg.rs:216:31 + --> $DIR/bad-reg.rs:218:31 | LL | asm!("", out("f5") _, out("vs5") _); | ----------- ^^^^^^^^^^^^ register `vs5` @@ -237,7 +237,7 @@ LL | asm!("", out("f5") _, out("vs5") _); | register `f5` error: register `vs6` conflicts with register `f6` - --> $DIR/bad-reg.rs:218:31 + --> $DIR/bad-reg.rs:220:31 | LL | asm!("", out("f6") _, out("vs6") _); | ----------- ^^^^^^^^^^^^ register `vs6` @@ -245,7 +245,7 @@ LL | asm!("", out("f6") _, out("vs6") _); | register `f6` error: register `vs7` conflicts with register `f7` - --> $DIR/bad-reg.rs:220:31 + --> $DIR/bad-reg.rs:222:31 | LL | asm!("", out("f7") _, out("vs7") _); | ----------- ^^^^^^^^^^^^ register `vs7` @@ -253,7 +253,7 @@ LL | asm!("", out("f7") _, out("vs7") _); | register `f7` error: register `vs8` conflicts with register `f8` - --> $DIR/bad-reg.rs:222:31 + --> $DIR/bad-reg.rs:224:31 | LL | asm!("", out("f8") _, out("vs8") _); | ----------- ^^^^^^^^^^^^ register `vs8` @@ -261,7 +261,7 @@ LL | asm!("", out("f8") _, out("vs8") _); | register `f8` error: register `vs9` conflicts with register `f9` - --> $DIR/bad-reg.rs:224:31 + --> $DIR/bad-reg.rs:226:31 | LL | asm!("", out("f9") _, out("vs9") _); | ----------- ^^^^^^^^^^^^ register `vs9` @@ -269,7 +269,7 @@ LL | asm!("", out("f9") _, out("vs9") _); | register `f9` error: register `vs10` conflicts with register `f10` - --> $DIR/bad-reg.rs:226:32 + --> $DIR/bad-reg.rs:228:32 | LL | asm!("", out("f10") _, out("vs10") _); | ------------ ^^^^^^^^^^^^^ register `vs10` @@ -277,7 +277,7 @@ LL | asm!("", out("f10") _, out("vs10") _); | register `f10` error: register `vs11` conflicts with register `f11` - --> $DIR/bad-reg.rs:228:32 + --> $DIR/bad-reg.rs:230:32 | LL | asm!("", out("f11") _, out("vs11") _); | ------------ ^^^^^^^^^^^^^ register `vs11` @@ -285,7 +285,7 @@ LL | asm!("", out("f11") _, out("vs11") _); | register `f11` error: register `vs12` conflicts with register `f12` - --> $DIR/bad-reg.rs:230:32 + --> $DIR/bad-reg.rs:232:32 | LL | asm!("", out("f12") _, out("vs12") _); | ------------ ^^^^^^^^^^^^^ register `vs12` @@ -293,7 +293,7 @@ LL | asm!("", out("f12") _, out("vs12") _); | register `f12` error: register `vs13` conflicts with register `f13` - --> $DIR/bad-reg.rs:232:32 + --> $DIR/bad-reg.rs:234:32 | LL | asm!("", out("f13") _, out("vs13") _); | ------------ ^^^^^^^^^^^^^ register `vs13` @@ -301,7 +301,7 @@ LL | asm!("", out("f13") _, out("vs13") _); | register `f13` error: register `vs14` conflicts with register `f14` - --> $DIR/bad-reg.rs:234:32 + --> $DIR/bad-reg.rs:236:32 | LL | asm!("", out("f14") _, out("vs14") _); | ------------ ^^^^^^^^^^^^^ register `vs14` @@ -309,7 +309,7 @@ LL | asm!("", out("f14") _, out("vs14") _); | register `f14` error: register `vs15` conflicts with register `f15` - --> $DIR/bad-reg.rs:236:32 + --> $DIR/bad-reg.rs:238:32 | LL | asm!("", out("f15") _, out("vs15") _); | ------------ ^^^^^^^^^^^^^ register `vs15` @@ -317,7 +317,7 @@ LL | asm!("", out("f15") _, out("vs15") _); | register `f15` error: register `vs16` conflicts with register `f16` - --> $DIR/bad-reg.rs:238:32 + --> $DIR/bad-reg.rs:240:32 | LL | asm!("", out("f16") _, out("vs16") _); | ------------ ^^^^^^^^^^^^^ register `vs16` @@ -325,7 +325,7 @@ LL | asm!("", out("f16") _, out("vs16") _); | register `f16` error: register `vs17` conflicts with register `f17` - --> $DIR/bad-reg.rs:240:32 + --> $DIR/bad-reg.rs:242:32 | LL | asm!("", out("f17") _, out("vs17") _); | ------------ ^^^^^^^^^^^^^ register `vs17` @@ -333,7 +333,7 @@ LL | asm!("", out("f17") _, out("vs17") _); | register `f17` error: register `vs18` conflicts with register `f18` - --> $DIR/bad-reg.rs:242:32 + --> $DIR/bad-reg.rs:244:32 | LL | asm!("", out("f18") _, out("vs18") _); | ------------ ^^^^^^^^^^^^^ register `vs18` @@ -341,7 +341,7 @@ LL | asm!("", out("f18") _, out("vs18") _); | register `f18` error: register `vs19` conflicts with register `f19` - --> $DIR/bad-reg.rs:244:32 + --> $DIR/bad-reg.rs:246:32 | LL | asm!("", out("f19") _, out("vs19") _); | ------------ ^^^^^^^^^^^^^ register `vs19` @@ -349,7 +349,7 @@ LL | asm!("", out("f19") _, out("vs19") _); | register `f19` error: register `vs20` conflicts with register `f20` - --> $DIR/bad-reg.rs:246:32 + --> $DIR/bad-reg.rs:248:32 | LL | asm!("", out("f20") _, out("vs20") _); | ------------ ^^^^^^^^^^^^^ register `vs20` @@ -357,7 +357,7 @@ LL | asm!("", out("f20") _, out("vs20") _); | register `f20` error: register `vs21` conflicts with register `f21` - --> $DIR/bad-reg.rs:248:32 + --> $DIR/bad-reg.rs:250:32 | LL | asm!("", out("f21") _, out("vs21") _); | ------------ ^^^^^^^^^^^^^ register `vs21` @@ -365,7 +365,7 @@ LL | asm!("", out("f21") _, out("vs21") _); | register `f21` error: register `vs22` conflicts with register `f22` - --> $DIR/bad-reg.rs:250:32 + --> $DIR/bad-reg.rs:252:32 | LL | asm!("", out("f22") _, out("vs22") _); | ------------ ^^^^^^^^^^^^^ register `vs22` @@ -373,7 +373,7 @@ LL | asm!("", out("f22") _, out("vs22") _); | register `f22` error: register `vs23` conflicts with register `f23` - --> $DIR/bad-reg.rs:252:32 + --> $DIR/bad-reg.rs:254:32 | LL | asm!("", out("f23") _, out("vs23") _); | ------------ ^^^^^^^^^^^^^ register `vs23` @@ -381,7 +381,7 @@ LL | asm!("", out("f23") _, out("vs23") _); | register `f23` error: register `vs24` conflicts with register `f24` - --> $DIR/bad-reg.rs:254:32 + --> $DIR/bad-reg.rs:256:32 | LL | asm!("", out("f24") _, out("vs24") _); | ------------ ^^^^^^^^^^^^^ register `vs24` @@ -389,7 +389,7 @@ LL | asm!("", out("f24") _, out("vs24") _); | register `f24` error: register `vs25` conflicts with register `f25` - --> $DIR/bad-reg.rs:256:32 + --> $DIR/bad-reg.rs:258:32 | LL | asm!("", out("f25") _, out("vs25") _); | ------------ ^^^^^^^^^^^^^ register `vs25` @@ -397,7 +397,7 @@ LL | asm!("", out("f25") _, out("vs25") _); | register `f25` error: register `vs26` conflicts with register `f26` - --> $DIR/bad-reg.rs:258:32 + --> $DIR/bad-reg.rs:260:32 | LL | asm!("", out("f26") _, out("vs26") _); | ------------ ^^^^^^^^^^^^^ register `vs26` @@ -405,7 +405,7 @@ LL | asm!("", out("f26") _, out("vs26") _); | register `f26` error: register `vs27` conflicts with register `f27` - --> $DIR/bad-reg.rs:260:32 + --> $DIR/bad-reg.rs:262:32 | LL | asm!("", out("f27") _, out("vs27") _); | ------------ ^^^^^^^^^^^^^ register `vs27` @@ -413,7 +413,7 @@ LL | asm!("", out("f27") _, out("vs27") _); | register `f27` error: register `vs28` conflicts with register `f28` - --> $DIR/bad-reg.rs:262:32 + --> $DIR/bad-reg.rs:264:32 | LL | asm!("", out("f28") _, out("vs28") _); | ------------ ^^^^^^^^^^^^^ register `vs28` @@ -421,7 +421,7 @@ LL | asm!("", out("f28") _, out("vs28") _); | register `f28` error: register `vs29` conflicts with register `f29` - --> $DIR/bad-reg.rs:264:32 + --> $DIR/bad-reg.rs:266:32 | LL | asm!("", out("f29") _, out("vs29") _); | ------------ ^^^^^^^^^^^^^ register `vs29` @@ -429,7 +429,7 @@ LL | asm!("", out("f29") _, out("vs29") _); | register `f29` error: register `vs30` conflicts with register `f30` - --> $DIR/bad-reg.rs:266:32 + --> $DIR/bad-reg.rs:268:32 | LL | asm!("", out("f30") _, out("vs30") _); | ------------ ^^^^^^^^^^^^^ register `vs30` @@ -437,7 +437,7 @@ LL | asm!("", out("f30") _, out("vs30") _); | register `f30` error: register `vs31` conflicts with register `f31` - --> $DIR/bad-reg.rs:268:32 + --> $DIR/bad-reg.rs:270:32 | LL | asm!("", out("f31") _, out("vs31") _); | ------------ ^^^^^^^^^^^^^ register `vs31` @@ -445,7 +445,7 @@ LL | asm!("", out("f31") _, out("vs31") _); | register `f31` error: register `v0` conflicts with register `vs32` - --> $DIR/bad-reg.rs:270:33 + --> $DIR/bad-reg.rs:272:33 | LL | asm!("", out("vs32") _, out("v0") _); | ------------- ^^^^^^^^^^^ register `v0` @@ -453,7 +453,7 @@ LL | asm!("", out("vs32") _, out("v0") _); | register `vs32` error: register `v1` conflicts with register `vs33` - --> $DIR/bad-reg.rs:272:33 + --> $DIR/bad-reg.rs:274:33 | LL | asm!("", out("vs33") _, out("v1") _); | ------------- ^^^^^^^^^^^ register `v1` @@ -461,7 +461,7 @@ LL | asm!("", out("vs33") _, out("v1") _); | register `vs33` error: register `v2` conflicts with register `vs34` - --> $DIR/bad-reg.rs:274:33 + --> $DIR/bad-reg.rs:276:33 | LL | asm!("", out("vs34") _, out("v2") _); | ------------- ^^^^^^^^^^^ register `v2` @@ -469,7 +469,7 @@ LL | asm!("", out("vs34") _, out("v2") _); | register `vs34` error: register `v3` conflicts with register `vs35` - --> $DIR/bad-reg.rs:276:33 + --> $DIR/bad-reg.rs:278:33 | LL | asm!("", out("vs35") _, out("v3") _); | ------------- ^^^^^^^^^^^ register `v3` @@ -477,7 +477,7 @@ LL | asm!("", out("vs35") _, out("v3") _); | register `vs35` error: register `v4` conflicts with register `vs36` - --> $DIR/bad-reg.rs:278:33 + --> $DIR/bad-reg.rs:280:33 | LL | asm!("", out("vs36") _, out("v4") _); | ------------- ^^^^^^^^^^^ register `v4` @@ -485,7 +485,7 @@ LL | asm!("", out("vs36") _, out("v4") _); | register `vs36` error: register `v5` conflicts with register `vs37` - --> $DIR/bad-reg.rs:280:33 + --> $DIR/bad-reg.rs:282:33 | LL | asm!("", out("vs37") _, out("v5") _); | ------------- ^^^^^^^^^^^ register `v5` @@ -493,7 +493,7 @@ LL | asm!("", out("vs37") _, out("v5") _); | register `vs37` error: register `v6` conflicts with register `vs38` - --> $DIR/bad-reg.rs:282:33 + --> $DIR/bad-reg.rs:284:33 | LL | asm!("", out("vs38") _, out("v6") _); | ------------- ^^^^^^^^^^^ register `v6` @@ -501,7 +501,7 @@ LL | asm!("", out("vs38") _, out("v6") _); | register `vs38` error: register `v7` conflicts with register `vs39` - --> $DIR/bad-reg.rs:284:33 + --> $DIR/bad-reg.rs:286:33 | LL | asm!("", out("vs39") _, out("v7") _); | ------------- ^^^^^^^^^^^ register `v7` @@ -509,7 +509,7 @@ LL | asm!("", out("vs39") _, out("v7") _); | register `vs39` error: register `v8` conflicts with register `vs40` - --> $DIR/bad-reg.rs:286:33 + --> $DIR/bad-reg.rs:288:33 | LL | asm!("", out("vs40") _, out("v8") _); | ------------- ^^^^^^^^^^^ register `v8` @@ -517,7 +517,7 @@ LL | asm!("", out("vs40") _, out("v8") _); | register `vs40` error: register `v9` conflicts with register `vs41` - --> $DIR/bad-reg.rs:288:33 + --> $DIR/bad-reg.rs:290:33 | LL | asm!("", out("vs41") _, out("v9") _); | ------------- ^^^^^^^^^^^ register `v9` @@ -525,7 +525,7 @@ LL | asm!("", out("vs41") _, out("v9") _); | register `vs41` error: register `v10` conflicts with register `vs42` - --> $DIR/bad-reg.rs:290:33 + --> $DIR/bad-reg.rs:292:33 | LL | asm!("", out("vs42") _, out("v10") _); | ------------- ^^^^^^^^^^^^ register `v10` @@ -533,7 +533,7 @@ LL | asm!("", out("vs42") _, out("v10") _); | register `vs42` error: register `v11` conflicts with register `vs43` - --> $DIR/bad-reg.rs:292:33 + --> $DIR/bad-reg.rs:294:33 | LL | asm!("", out("vs43") _, out("v11") _); | ------------- ^^^^^^^^^^^^ register `v11` @@ -541,7 +541,7 @@ LL | asm!("", out("vs43") _, out("v11") _); | register `vs43` error: register `v12` conflicts with register `vs44` - --> $DIR/bad-reg.rs:294:33 + --> $DIR/bad-reg.rs:296:33 | LL | asm!("", out("vs44") _, out("v12") _); | ------------- ^^^^^^^^^^^^ register `v12` @@ -549,7 +549,7 @@ LL | asm!("", out("vs44") _, out("v12") _); | register `vs44` error: register `v13` conflicts with register `vs45` - --> $DIR/bad-reg.rs:296:33 + --> $DIR/bad-reg.rs:298:33 | LL | asm!("", out("vs45") _, out("v13") _); | ------------- ^^^^^^^^^^^^ register `v13` @@ -557,7 +557,7 @@ LL | asm!("", out("vs45") _, out("v13") _); | register `vs45` error: register `v14` conflicts with register `vs46` - --> $DIR/bad-reg.rs:298:33 + --> $DIR/bad-reg.rs:300:33 | LL | asm!("", out("vs46") _, out("v14") _); | ------------- ^^^^^^^^^^^^ register `v14` @@ -565,7 +565,7 @@ LL | asm!("", out("vs46") _, out("v14") _); | register `vs46` error: register `v15` conflicts with register `vs47` - --> $DIR/bad-reg.rs:300:33 + --> $DIR/bad-reg.rs:302:33 | LL | asm!("", out("vs47") _, out("v15") _); | ------------- ^^^^^^^^^^^^ register `v15` @@ -573,7 +573,7 @@ LL | asm!("", out("vs47") _, out("v15") _); | register `vs47` error: register `v16` conflicts with register `vs48` - --> $DIR/bad-reg.rs:302:33 + --> $DIR/bad-reg.rs:304:33 | LL | asm!("", out("vs48") _, out("v16") _); | ------------- ^^^^^^^^^^^^ register `v16` @@ -581,7 +581,7 @@ LL | asm!("", out("vs48") _, out("v16") _); | register `vs48` error: register `v17` conflicts with register `vs49` - --> $DIR/bad-reg.rs:304:33 + --> $DIR/bad-reg.rs:306:33 | LL | asm!("", out("vs49") _, out("v17") _); | ------------- ^^^^^^^^^^^^ register `v17` @@ -589,7 +589,7 @@ LL | asm!("", out("vs49") _, out("v17") _); | register `vs49` error: register `v18` conflicts with register `vs50` - --> $DIR/bad-reg.rs:306:33 + --> $DIR/bad-reg.rs:308:33 | LL | asm!("", out("vs50") _, out("v18") _); | ------------- ^^^^^^^^^^^^ register `v18` @@ -597,7 +597,7 @@ LL | asm!("", out("vs50") _, out("v18") _); | register `vs50` error: register `v19` conflicts with register `vs51` - --> $DIR/bad-reg.rs:308:33 + --> $DIR/bad-reg.rs:310:33 | LL | asm!("", out("vs51") _, out("v19") _); | ------------- ^^^^^^^^^^^^ register `v19` @@ -605,7 +605,7 @@ LL | asm!("", out("vs51") _, out("v19") _); | register `vs51` error: register `v20` conflicts with register `vs52` - --> $DIR/bad-reg.rs:310:33 + --> $DIR/bad-reg.rs:312:33 | LL | asm!("", out("vs52") _, out("v20") _); | ------------- ^^^^^^^^^^^^ register `v20` @@ -613,7 +613,7 @@ LL | asm!("", out("vs52") _, out("v20") _); | register `vs52` error: register `v21` conflicts with register `vs53` - --> $DIR/bad-reg.rs:312:33 + --> $DIR/bad-reg.rs:314:33 | LL | asm!("", out("vs53") _, out("v21") _); | ------------- ^^^^^^^^^^^^ register `v21` @@ -621,7 +621,7 @@ LL | asm!("", out("vs53") _, out("v21") _); | register `vs53` error: register `v22` conflicts with register `vs54` - --> $DIR/bad-reg.rs:314:33 + --> $DIR/bad-reg.rs:316:33 | LL | asm!("", out("vs54") _, out("v22") _); | ------------- ^^^^^^^^^^^^ register `v22` @@ -629,7 +629,7 @@ LL | asm!("", out("vs54") _, out("v22") _); | register `vs54` error: register `v23` conflicts with register `vs55` - --> $DIR/bad-reg.rs:316:33 + --> $DIR/bad-reg.rs:318:33 | LL | asm!("", out("vs55") _, out("v23") _); | ------------- ^^^^^^^^^^^^ register `v23` @@ -637,7 +637,7 @@ LL | asm!("", out("vs55") _, out("v23") _); | register `vs55` error: register `v24` conflicts with register `vs56` - --> $DIR/bad-reg.rs:318:33 + --> $DIR/bad-reg.rs:320:33 | LL | asm!("", out("vs56") _, out("v24") _); | ------------- ^^^^^^^^^^^^ register `v24` @@ -645,7 +645,7 @@ LL | asm!("", out("vs56") _, out("v24") _); | register `vs56` error: register `v25` conflicts with register `vs57` - --> $DIR/bad-reg.rs:320:33 + --> $DIR/bad-reg.rs:322:33 | LL | asm!("", out("vs57") _, out("v25") _); | ------------- ^^^^^^^^^^^^ register `v25` @@ -653,7 +653,7 @@ LL | asm!("", out("vs57") _, out("v25") _); | register `vs57` error: register `v26` conflicts with register `vs58` - --> $DIR/bad-reg.rs:322:33 + --> $DIR/bad-reg.rs:324:33 | LL | asm!("", out("vs58") _, out("v26") _); | ------------- ^^^^^^^^^^^^ register `v26` @@ -661,7 +661,7 @@ LL | asm!("", out("vs58") _, out("v26") _); | register `vs58` error: register `v27` conflicts with register `vs59` - --> $DIR/bad-reg.rs:324:33 + --> $DIR/bad-reg.rs:326:33 | LL | asm!("", out("vs59") _, out("v27") _); | ------------- ^^^^^^^^^^^^ register `v27` @@ -669,7 +669,7 @@ LL | asm!("", out("vs59") _, out("v27") _); | register `vs59` error: register `v28` conflicts with register `vs60` - --> $DIR/bad-reg.rs:326:33 + --> $DIR/bad-reg.rs:328:33 | LL | asm!("", out("vs60") _, out("v28") _); | ------------- ^^^^^^^^^^^^ register `v28` @@ -677,7 +677,7 @@ LL | asm!("", out("vs60") _, out("v28") _); | register `vs60` error: register `v29` conflicts with register `vs61` - --> $DIR/bad-reg.rs:328:33 + --> $DIR/bad-reg.rs:330:33 | LL | asm!("", out("vs61") _, out("v29") _); | ------------- ^^^^^^^^^^^^ register `v29` @@ -685,7 +685,7 @@ LL | asm!("", out("vs61") _, out("v29") _); | register `vs61` error: register `v30` conflicts with register `vs62` - --> $DIR/bad-reg.rs:330:33 + --> $DIR/bad-reg.rs:332:33 | LL | asm!("", out("vs62") _, out("v30") _); | ------------- ^^^^^^^^^^^^ register `v30` @@ -693,21 +693,27 @@ LL | asm!("", out("vs62") _, out("v30") _); | register `vs62` error: register `v31` conflicts with register `vs63` - --> $DIR/bad-reg.rs:332:33 + --> $DIR/bad-reg.rs:334:33 | LL | asm!("", out("vs63") _, out("v31") _); | ------------- ^^^^^^^^^^^^ register `v31` | | | register `vs63` +error: register class `spe_acc` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:340:26 + | +LL | asm!("/* {} */", out(spe_acc) _); + | ^^^^^^^^^^^^^^ + error: cannot use register `r13`: r13 is a reserved register on this target - --> $DIR/bad-reg.rs:40:18 + --> $DIR/bad-reg.rs:42:18 | LL | asm!("", out("r13") _); | ^^^^^^^^^^^^ error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:63:27 + --> $DIR/bad-reg.rs:65:27 | LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available | ^ @@ -715,7 +721,7 @@ LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:66:28 + --> $DIR/bad-reg.rs:68:28 | LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available | ^ @@ -723,7 +729,7 @@ LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:74:35 + --> $DIR/bad-reg.rs:76:35 | LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available | ^ @@ -731,7 +737,7 @@ LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:104:28 + --> $DIR/bad-reg.rs:106:28 | LL | asm!("", in("vs0") x); // FIXME: should be ok if vsx is available | ^ @@ -739,7 +745,7 @@ LL | asm!("", in("vs0") x); // FIXME: should be ok if vsx is available = note: register class `vsreg` supports these types: f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:107:29 + --> $DIR/bad-reg.rs:109:29 | LL | asm!("", out("vs0") x); // FIXME: should be ok if vsx is available | ^ @@ -747,7 +753,7 @@ LL | asm!("", out("vs0") x); // FIXME: should be ok if vsx is available = note: register class `vsreg` supports these types: f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:114:36 + --> $DIR/bad-reg.rs:116:36 | LL | asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is available | ^ @@ -755,7 +761,7 @@ LL | asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is ava = note: register class `vsreg` supports these types: f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:137:27 + --> $DIR/bad-reg.rs:139:27 | LL | asm!("", in("cr") x); | ^ @@ -763,7 +769,7 @@ LL | asm!("", in("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:140:28 + --> $DIR/bad-reg.rs:142:28 | LL | asm!("", out("cr") x); | ^ @@ -771,7 +777,7 @@ LL | asm!("", out("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:143:33 + --> $DIR/bad-reg.rs:145:33 | LL | asm!("/* {} */", in(cr) x); | ^ @@ -779,7 +785,7 @@ LL | asm!("/* {} */", in(cr) x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:150:28 + --> $DIR/bad-reg.rs:152:28 | LL | asm!("", in("ctr") x); | ^ @@ -787,7 +793,7 @@ LL | asm!("", in("ctr") x); = note: register class `ctr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:153:29 + --> $DIR/bad-reg.rs:155:29 | LL | asm!("", out("ctr") x); | ^ @@ -795,7 +801,7 @@ LL | asm!("", out("ctr") x); = note: register class `ctr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:156:34 + --> $DIR/bad-reg.rs:158:34 | LL | asm!("/* {} */", in(ctr) x); | ^ @@ -803,7 +809,7 @@ LL | asm!("/* {} */", in(ctr) x); = note: register class `ctr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:163:27 + --> $DIR/bad-reg.rs:165:27 | LL | asm!("", in("lr") x); | ^ @@ -811,7 +817,7 @@ LL | asm!("", in("lr") x); = note: register class `lr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:166:28 + --> $DIR/bad-reg.rs:168:28 | LL | asm!("", out("lr") x); | ^ @@ -819,7 +825,7 @@ LL | asm!("", out("lr") x); = note: register class `lr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:169:33 + --> $DIR/bad-reg.rs:171:33 | LL | asm!("/* {} */", in(lr) x); | ^ @@ -827,7 +833,7 @@ LL | asm!("/* {} */", in(lr) x); = note: register class `lr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:176:28 + --> $DIR/bad-reg.rs:178:28 | LL | asm!("", in("xer") x); | ^ @@ -835,7 +841,7 @@ LL | asm!("", in("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:179:29 + --> $DIR/bad-reg.rs:181:29 | LL | asm!("", out("xer") x); | ^ @@ -843,12 +849,18 @@ LL | asm!("", out("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:182:34 + --> $DIR/bad-reg.rs:184:34 | LL | asm!("/* {} */", in(xer) x); | ^ | = note: register class `xer` supports these types: -error: aborting due to 112 previous errors +error: cannot use register `spe_acc`: spe_acc is only available on spe targets + --> $DIR/bad-reg.rs:338:18 + | +LL | asm!("", out("spe_acc") _); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 114 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr index 651e8cdfd3d5..5c4cd71c2d1a 100644 --- a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr +++ b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr @@ -1,131 +1,131 @@ error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:36:18 + --> $DIR/bad-reg.rs:38:18 | LL | asm!("", out("sp") _); | ^^^^^^^^^^^ error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:38:18 + --> $DIR/bad-reg.rs:40:18 | LL | asm!("", out("r2") _); | ^^^^^^^^^^^ error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:44:18 + --> $DIR/bad-reg.rs:46:18 | LL | asm!("", out("r30") _); | ^^^^^^^^^^^^ error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:46:18 + --> $DIR/bad-reg.rs:48:18 | LL | asm!("", out("fp") _); | ^^^^^^^^^^^ error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:48:18 + --> $DIR/bad-reg.rs:50:18 | LL | asm!("", out("vrsave") _); | ^^^^^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:137:18 + --> $DIR/bad-reg.rs:139:18 | LL | asm!("", in("cr") x); | ^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:140:18 + --> $DIR/bad-reg.rs:142:18 | LL | asm!("", out("cr") x); | ^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:143:26 + --> $DIR/bad-reg.rs:145:26 | LL | asm!("/* {} */", in(cr) x); | ^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:146:26 + --> $DIR/bad-reg.rs:148:26 | LL | asm!("/* {} */", out(cr) _); | ^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:150:18 + --> $DIR/bad-reg.rs:152:18 | LL | asm!("", in("ctr") x); | ^^^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:153:18 + --> $DIR/bad-reg.rs:155:18 | LL | asm!("", out("ctr") x); | ^^^^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:156:26 + --> $DIR/bad-reg.rs:158:26 | LL | asm!("/* {} */", in(ctr) x); | ^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:159:26 + --> $DIR/bad-reg.rs:161:26 | LL | asm!("/* {} */", out(ctr) _); | ^^^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:163:18 + --> $DIR/bad-reg.rs:165:18 | LL | asm!("", in("lr") x); | ^^^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:166:18 + --> $DIR/bad-reg.rs:168:18 | LL | asm!("", out("lr") x); | ^^^^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:169:26 + --> $DIR/bad-reg.rs:171:26 | LL | asm!("/* {} */", in(lr) x); | ^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:172:26 + --> $DIR/bad-reg.rs:174:26 | LL | asm!("/* {} */", out(lr) _); | ^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:176:18 + --> $DIR/bad-reg.rs:178:18 | LL | asm!("", in("xer") x); | ^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:179:18 + --> $DIR/bad-reg.rs:181:18 | LL | asm!("", out("xer") x); | ^^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:182:26 + --> $DIR/bad-reg.rs:184:26 | LL | asm!("/* {} */", in(xer) x); | ^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:185:26 + --> $DIR/bad-reg.rs:187:26 | LL | asm!("/* {} */", out(xer) _); | ^^^^^^^^^^ error: register `cr0` conflicts with register `cr` - --> $DIR/bad-reg.rs:189:31 + --> $DIR/bad-reg.rs:191:31 | LL | asm!("", out("cr") _, out("cr0") _); | ----------- ^^^^^^^^^^^^ register `cr0` @@ -133,7 +133,7 @@ LL | asm!("", out("cr") _, out("cr0") _); | register `cr` error: register `cr1` conflicts with register `cr` - --> $DIR/bad-reg.rs:191:31 + --> $DIR/bad-reg.rs:193:31 | LL | asm!("", out("cr") _, out("cr1") _); | ----------- ^^^^^^^^^^^^ register `cr1` @@ -141,7 +141,7 @@ LL | asm!("", out("cr") _, out("cr1") _); | register `cr` error: register `cr2` conflicts with register `cr` - --> $DIR/bad-reg.rs:193:31 + --> $DIR/bad-reg.rs:195:31 | LL | asm!("", out("cr") _, out("cr2") _); | ----------- ^^^^^^^^^^^^ register `cr2` @@ -149,7 +149,7 @@ LL | asm!("", out("cr") _, out("cr2") _); | register `cr` error: register `cr3` conflicts with register `cr` - --> $DIR/bad-reg.rs:195:31 + --> $DIR/bad-reg.rs:197:31 | LL | asm!("", out("cr") _, out("cr3") _); | ----------- ^^^^^^^^^^^^ register `cr3` @@ -157,7 +157,7 @@ LL | asm!("", out("cr") _, out("cr3") _); | register `cr` error: register `cr4` conflicts with register `cr` - --> $DIR/bad-reg.rs:197:31 + --> $DIR/bad-reg.rs:199:31 | LL | asm!("", out("cr") _, out("cr4") _); | ----------- ^^^^^^^^^^^^ register `cr4` @@ -165,7 +165,7 @@ LL | asm!("", out("cr") _, out("cr4") _); | register `cr` error: register `cr5` conflicts with register `cr` - --> $DIR/bad-reg.rs:199:31 + --> $DIR/bad-reg.rs:201:31 | LL | asm!("", out("cr") _, out("cr5") _); | ----------- ^^^^^^^^^^^^ register `cr5` @@ -173,7 +173,7 @@ LL | asm!("", out("cr") _, out("cr5") _); | register `cr` error: register `cr6` conflicts with register `cr` - --> $DIR/bad-reg.rs:201:31 + --> $DIR/bad-reg.rs:203:31 | LL | asm!("", out("cr") _, out("cr6") _); | ----------- ^^^^^^^^^^^^ register `cr6` @@ -181,7 +181,7 @@ LL | asm!("", out("cr") _, out("cr6") _); | register `cr` error: register `cr7` conflicts with register `cr` - --> $DIR/bad-reg.rs:203:31 + --> $DIR/bad-reg.rs:205:31 | LL | asm!("", out("cr") _, out("cr7") _); | ----------- ^^^^^^^^^^^^ register `cr7` @@ -189,7 +189,7 @@ LL | asm!("", out("cr") _, out("cr7") _); | register `cr` error: register `vs0` conflicts with register `f0` - --> $DIR/bad-reg.rs:206:31 + --> $DIR/bad-reg.rs:208:31 | LL | asm!("", out("f0") _, out("vs0") _); | ----------- ^^^^^^^^^^^^ register `vs0` @@ -197,7 +197,7 @@ LL | asm!("", out("f0") _, out("vs0") _); | register `f0` error: register `vs1` conflicts with register `f1` - --> $DIR/bad-reg.rs:208:31 + --> $DIR/bad-reg.rs:210:31 | LL | asm!("", out("f1") _, out("vs1") _); | ----------- ^^^^^^^^^^^^ register `vs1` @@ -205,7 +205,7 @@ LL | asm!("", out("f1") _, out("vs1") _); | register `f1` error: register `vs2` conflicts with register `f2` - --> $DIR/bad-reg.rs:210:31 + --> $DIR/bad-reg.rs:212:31 | LL | asm!("", out("f2") _, out("vs2") _); | ----------- ^^^^^^^^^^^^ register `vs2` @@ -213,7 +213,7 @@ LL | asm!("", out("f2") _, out("vs2") _); | register `f2` error: register `vs3` conflicts with register `f3` - --> $DIR/bad-reg.rs:212:31 + --> $DIR/bad-reg.rs:214:31 | LL | asm!("", out("f3") _, out("vs3") _); | ----------- ^^^^^^^^^^^^ register `vs3` @@ -221,7 +221,7 @@ LL | asm!("", out("f3") _, out("vs3") _); | register `f3` error: register `vs4` conflicts with register `f4` - --> $DIR/bad-reg.rs:214:31 + --> $DIR/bad-reg.rs:216:31 | LL | asm!("", out("f4") _, out("vs4") _); | ----------- ^^^^^^^^^^^^ register `vs4` @@ -229,7 +229,7 @@ LL | asm!("", out("f4") _, out("vs4") _); | register `f4` error: register `vs5` conflicts with register `f5` - --> $DIR/bad-reg.rs:216:31 + --> $DIR/bad-reg.rs:218:31 | LL | asm!("", out("f5") _, out("vs5") _); | ----------- ^^^^^^^^^^^^ register `vs5` @@ -237,7 +237,7 @@ LL | asm!("", out("f5") _, out("vs5") _); | register `f5` error: register `vs6` conflicts with register `f6` - --> $DIR/bad-reg.rs:218:31 + --> $DIR/bad-reg.rs:220:31 | LL | asm!("", out("f6") _, out("vs6") _); | ----------- ^^^^^^^^^^^^ register `vs6` @@ -245,7 +245,7 @@ LL | asm!("", out("f6") _, out("vs6") _); | register `f6` error: register `vs7` conflicts with register `f7` - --> $DIR/bad-reg.rs:220:31 + --> $DIR/bad-reg.rs:222:31 | LL | asm!("", out("f7") _, out("vs7") _); | ----------- ^^^^^^^^^^^^ register `vs7` @@ -253,7 +253,7 @@ LL | asm!("", out("f7") _, out("vs7") _); | register `f7` error: register `vs8` conflicts with register `f8` - --> $DIR/bad-reg.rs:222:31 + --> $DIR/bad-reg.rs:224:31 | LL | asm!("", out("f8") _, out("vs8") _); | ----------- ^^^^^^^^^^^^ register `vs8` @@ -261,7 +261,7 @@ LL | asm!("", out("f8") _, out("vs8") _); | register `f8` error: register `vs9` conflicts with register `f9` - --> $DIR/bad-reg.rs:224:31 + --> $DIR/bad-reg.rs:226:31 | LL | asm!("", out("f9") _, out("vs9") _); | ----------- ^^^^^^^^^^^^ register `vs9` @@ -269,7 +269,7 @@ LL | asm!("", out("f9") _, out("vs9") _); | register `f9` error: register `vs10` conflicts with register `f10` - --> $DIR/bad-reg.rs:226:32 + --> $DIR/bad-reg.rs:228:32 | LL | asm!("", out("f10") _, out("vs10") _); | ------------ ^^^^^^^^^^^^^ register `vs10` @@ -277,7 +277,7 @@ LL | asm!("", out("f10") _, out("vs10") _); | register `f10` error: register `vs11` conflicts with register `f11` - --> $DIR/bad-reg.rs:228:32 + --> $DIR/bad-reg.rs:230:32 | LL | asm!("", out("f11") _, out("vs11") _); | ------------ ^^^^^^^^^^^^^ register `vs11` @@ -285,7 +285,7 @@ LL | asm!("", out("f11") _, out("vs11") _); | register `f11` error: register `vs12` conflicts with register `f12` - --> $DIR/bad-reg.rs:230:32 + --> $DIR/bad-reg.rs:232:32 | LL | asm!("", out("f12") _, out("vs12") _); | ------------ ^^^^^^^^^^^^^ register `vs12` @@ -293,7 +293,7 @@ LL | asm!("", out("f12") _, out("vs12") _); | register `f12` error: register `vs13` conflicts with register `f13` - --> $DIR/bad-reg.rs:232:32 + --> $DIR/bad-reg.rs:234:32 | LL | asm!("", out("f13") _, out("vs13") _); | ------------ ^^^^^^^^^^^^^ register `vs13` @@ -301,7 +301,7 @@ LL | asm!("", out("f13") _, out("vs13") _); | register `f13` error: register `vs14` conflicts with register `f14` - --> $DIR/bad-reg.rs:234:32 + --> $DIR/bad-reg.rs:236:32 | LL | asm!("", out("f14") _, out("vs14") _); | ------------ ^^^^^^^^^^^^^ register `vs14` @@ -309,7 +309,7 @@ LL | asm!("", out("f14") _, out("vs14") _); | register `f14` error: register `vs15` conflicts with register `f15` - --> $DIR/bad-reg.rs:236:32 + --> $DIR/bad-reg.rs:238:32 | LL | asm!("", out("f15") _, out("vs15") _); | ------------ ^^^^^^^^^^^^^ register `vs15` @@ -317,7 +317,7 @@ LL | asm!("", out("f15") _, out("vs15") _); | register `f15` error: register `vs16` conflicts with register `f16` - --> $DIR/bad-reg.rs:238:32 + --> $DIR/bad-reg.rs:240:32 | LL | asm!("", out("f16") _, out("vs16") _); | ------------ ^^^^^^^^^^^^^ register `vs16` @@ -325,7 +325,7 @@ LL | asm!("", out("f16") _, out("vs16") _); | register `f16` error: register `vs17` conflicts with register `f17` - --> $DIR/bad-reg.rs:240:32 + --> $DIR/bad-reg.rs:242:32 | LL | asm!("", out("f17") _, out("vs17") _); | ------------ ^^^^^^^^^^^^^ register `vs17` @@ -333,7 +333,7 @@ LL | asm!("", out("f17") _, out("vs17") _); | register `f17` error: register `vs18` conflicts with register `f18` - --> $DIR/bad-reg.rs:242:32 + --> $DIR/bad-reg.rs:244:32 | LL | asm!("", out("f18") _, out("vs18") _); | ------------ ^^^^^^^^^^^^^ register `vs18` @@ -341,7 +341,7 @@ LL | asm!("", out("f18") _, out("vs18") _); | register `f18` error: register `vs19` conflicts with register `f19` - --> $DIR/bad-reg.rs:244:32 + --> $DIR/bad-reg.rs:246:32 | LL | asm!("", out("f19") _, out("vs19") _); | ------------ ^^^^^^^^^^^^^ register `vs19` @@ -349,7 +349,7 @@ LL | asm!("", out("f19") _, out("vs19") _); | register `f19` error: register `vs20` conflicts with register `f20` - --> $DIR/bad-reg.rs:246:32 + --> $DIR/bad-reg.rs:248:32 | LL | asm!("", out("f20") _, out("vs20") _); | ------------ ^^^^^^^^^^^^^ register `vs20` @@ -357,7 +357,7 @@ LL | asm!("", out("f20") _, out("vs20") _); | register `f20` error: register `vs21` conflicts with register `f21` - --> $DIR/bad-reg.rs:248:32 + --> $DIR/bad-reg.rs:250:32 | LL | asm!("", out("f21") _, out("vs21") _); | ------------ ^^^^^^^^^^^^^ register `vs21` @@ -365,7 +365,7 @@ LL | asm!("", out("f21") _, out("vs21") _); | register `f21` error: register `vs22` conflicts with register `f22` - --> $DIR/bad-reg.rs:250:32 + --> $DIR/bad-reg.rs:252:32 | LL | asm!("", out("f22") _, out("vs22") _); | ------------ ^^^^^^^^^^^^^ register `vs22` @@ -373,7 +373,7 @@ LL | asm!("", out("f22") _, out("vs22") _); | register `f22` error: register `vs23` conflicts with register `f23` - --> $DIR/bad-reg.rs:252:32 + --> $DIR/bad-reg.rs:254:32 | LL | asm!("", out("f23") _, out("vs23") _); | ------------ ^^^^^^^^^^^^^ register `vs23` @@ -381,7 +381,7 @@ LL | asm!("", out("f23") _, out("vs23") _); | register `f23` error: register `vs24` conflicts with register `f24` - --> $DIR/bad-reg.rs:254:32 + --> $DIR/bad-reg.rs:256:32 | LL | asm!("", out("f24") _, out("vs24") _); | ------------ ^^^^^^^^^^^^^ register `vs24` @@ -389,7 +389,7 @@ LL | asm!("", out("f24") _, out("vs24") _); | register `f24` error: register `vs25` conflicts with register `f25` - --> $DIR/bad-reg.rs:256:32 + --> $DIR/bad-reg.rs:258:32 | LL | asm!("", out("f25") _, out("vs25") _); | ------------ ^^^^^^^^^^^^^ register `vs25` @@ -397,7 +397,7 @@ LL | asm!("", out("f25") _, out("vs25") _); | register `f25` error: register `vs26` conflicts with register `f26` - --> $DIR/bad-reg.rs:258:32 + --> $DIR/bad-reg.rs:260:32 | LL | asm!("", out("f26") _, out("vs26") _); | ------------ ^^^^^^^^^^^^^ register `vs26` @@ -405,7 +405,7 @@ LL | asm!("", out("f26") _, out("vs26") _); | register `f26` error: register `vs27` conflicts with register `f27` - --> $DIR/bad-reg.rs:260:32 + --> $DIR/bad-reg.rs:262:32 | LL | asm!("", out("f27") _, out("vs27") _); | ------------ ^^^^^^^^^^^^^ register `vs27` @@ -413,7 +413,7 @@ LL | asm!("", out("f27") _, out("vs27") _); | register `f27` error: register `vs28` conflicts with register `f28` - --> $DIR/bad-reg.rs:262:32 + --> $DIR/bad-reg.rs:264:32 | LL | asm!("", out("f28") _, out("vs28") _); | ------------ ^^^^^^^^^^^^^ register `vs28` @@ -421,7 +421,7 @@ LL | asm!("", out("f28") _, out("vs28") _); | register `f28` error: register `vs29` conflicts with register `f29` - --> $DIR/bad-reg.rs:264:32 + --> $DIR/bad-reg.rs:266:32 | LL | asm!("", out("f29") _, out("vs29") _); | ------------ ^^^^^^^^^^^^^ register `vs29` @@ -429,7 +429,7 @@ LL | asm!("", out("f29") _, out("vs29") _); | register `f29` error: register `vs30` conflicts with register `f30` - --> $DIR/bad-reg.rs:266:32 + --> $DIR/bad-reg.rs:268:32 | LL | asm!("", out("f30") _, out("vs30") _); | ------------ ^^^^^^^^^^^^^ register `vs30` @@ -437,7 +437,7 @@ LL | asm!("", out("f30") _, out("vs30") _); | register `f30` error: register `vs31` conflicts with register `f31` - --> $DIR/bad-reg.rs:268:32 + --> $DIR/bad-reg.rs:270:32 | LL | asm!("", out("f31") _, out("vs31") _); | ------------ ^^^^^^^^^^^^^ register `vs31` @@ -445,7 +445,7 @@ LL | asm!("", out("f31") _, out("vs31") _); | register `f31` error: register `v0` conflicts with register `vs32` - --> $DIR/bad-reg.rs:270:33 + --> $DIR/bad-reg.rs:272:33 | LL | asm!("", out("vs32") _, out("v0") _); | ------------- ^^^^^^^^^^^ register `v0` @@ -453,7 +453,7 @@ LL | asm!("", out("vs32") _, out("v0") _); | register `vs32` error: register `v1` conflicts with register `vs33` - --> $DIR/bad-reg.rs:272:33 + --> $DIR/bad-reg.rs:274:33 | LL | asm!("", out("vs33") _, out("v1") _); | ------------- ^^^^^^^^^^^ register `v1` @@ -461,7 +461,7 @@ LL | asm!("", out("vs33") _, out("v1") _); | register `vs33` error: register `v2` conflicts with register `vs34` - --> $DIR/bad-reg.rs:274:33 + --> $DIR/bad-reg.rs:276:33 | LL | asm!("", out("vs34") _, out("v2") _); | ------------- ^^^^^^^^^^^ register `v2` @@ -469,7 +469,7 @@ LL | asm!("", out("vs34") _, out("v2") _); | register `vs34` error: register `v3` conflicts with register `vs35` - --> $DIR/bad-reg.rs:276:33 + --> $DIR/bad-reg.rs:278:33 | LL | asm!("", out("vs35") _, out("v3") _); | ------------- ^^^^^^^^^^^ register `v3` @@ -477,7 +477,7 @@ LL | asm!("", out("vs35") _, out("v3") _); | register `vs35` error: register `v4` conflicts with register `vs36` - --> $DIR/bad-reg.rs:278:33 + --> $DIR/bad-reg.rs:280:33 | LL | asm!("", out("vs36") _, out("v4") _); | ------------- ^^^^^^^^^^^ register `v4` @@ -485,7 +485,7 @@ LL | asm!("", out("vs36") _, out("v4") _); | register `vs36` error: register `v5` conflicts with register `vs37` - --> $DIR/bad-reg.rs:280:33 + --> $DIR/bad-reg.rs:282:33 | LL | asm!("", out("vs37") _, out("v5") _); | ------------- ^^^^^^^^^^^ register `v5` @@ -493,7 +493,7 @@ LL | asm!("", out("vs37") _, out("v5") _); | register `vs37` error: register `v6` conflicts with register `vs38` - --> $DIR/bad-reg.rs:282:33 + --> $DIR/bad-reg.rs:284:33 | LL | asm!("", out("vs38") _, out("v6") _); | ------------- ^^^^^^^^^^^ register `v6` @@ -501,7 +501,7 @@ LL | asm!("", out("vs38") _, out("v6") _); | register `vs38` error: register `v7` conflicts with register `vs39` - --> $DIR/bad-reg.rs:284:33 + --> $DIR/bad-reg.rs:286:33 | LL | asm!("", out("vs39") _, out("v7") _); | ------------- ^^^^^^^^^^^ register `v7` @@ -509,7 +509,7 @@ LL | asm!("", out("vs39") _, out("v7") _); | register `vs39` error: register `v8` conflicts with register `vs40` - --> $DIR/bad-reg.rs:286:33 + --> $DIR/bad-reg.rs:288:33 | LL | asm!("", out("vs40") _, out("v8") _); | ------------- ^^^^^^^^^^^ register `v8` @@ -517,7 +517,7 @@ LL | asm!("", out("vs40") _, out("v8") _); | register `vs40` error: register `v9` conflicts with register `vs41` - --> $DIR/bad-reg.rs:288:33 + --> $DIR/bad-reg.rs:290:33 | LL | asm!("", out("vs41") _, out("v9") _); | ------------- ^^^^^^^^^^^ register `v9` @@ -525,7 +525,7 @@ LL | asm!("", out("vs41") _, out("v9") _); | register `vs41` error: register `v10` conflicts with register `vs42` - --> $DIR/bad-reg.rs:290:33 + --> $DIR/bad-reg.rs:292:33 | LL | asm!("", out("vs42") _, out("v10") _); | ------------- ^^^^^^^^^^^^ register `v10` @@ -533,7 +533,7 @@ LL | asm!("", out("vs42") _, out("v10") _); | register `vs42` error: register `v11` conflicts with register `vs43` - --> $DIR/bad-reg.rs:292:33 + --> $DIR/bad-reg.rs:294:33 | LL | asm!("", out("vs43") _, out("v11") _); | ------------- ^^^^^^^^^^^^ register `v11` @@ -541,7 +541,7 @@ LL | asm!("", out("vs43") _, out("v11") _); | register `vs43` error: register `v12` conflicts with register `vs44` - --> $DIR/bad-reg.rs:294:33 + --> $DIR/bad-reg.rs:296:33 | LL | asm!("", out("vs44") _, out("v12") _); | ------------- ^^^^^^^^^^^^ register `v12` @@ -549,7 +549,7 @@ LL | asm!("", out("vs44") _, out("v12") _); | register `vs44` error: register `v13` conflicts with register `vs45` - --> $DIR/bad-reg.rs:296:33 + --> $DIR/bad-reg.rs:298:33 | LL | asm!("", out("vs45") _, out("v13") _); | ------------- ^^^^^^^^^^^^ register `v13` @@ -557,7 +557,7 @@ LL | asm!("", out("vs45") _, out("v13") _); | register `vs45` error: register `v14` conflicts with register `vs46` - --> $DIR/bad-reg.rs:298:33 + --> $DIR/bad-reg.rs:300:33 | LL | asm!("", out("vs46") _, out("v14") _); | ------------- ^^^^^^^^^^^^ register `v14` @@ -565,7 +565,7 @@ LL | asm!("", out("vs46") _, out("v14") _); | register `vs46` error: register `v15` conflicts with register `vs47` - --> $DIR/bad-reg.rs:300:33 + --> $DIR/bad-reg.rs:302:33 | LL | asm!("", out("vs47") _, out("v15") _); | ------------- ^^^^^^^^^^^^ register `v15` @@ -573,7 +573,7 @@ LL | asm!("", out("vs47") _, out("v15") _); | register `vs47` error: register `v16` conflicts with register `vs48` - --> $DIR/bad-reg.rs:302:33 + --> $DIR/bad-reg.rs:304:33 | LL | asm!("", out("vs48") _, out("v16") _); | ------------- ^^^^^^^^^^^^ register `v16` @@ -581,7 +581,7 @@ LL | asm!("", out("vs48") _, out("v16") _); | register `vs48` error: register `v17` conflicts with register `vs49` - --> $DIR/bad-reg.rs:304:33 + --> $DIR/bad-reg.rs:306:33 | LL | asm!("", out("vs49") _, out("v17") _); | ------------- ^^^^^^^^^^^^ register `v17` @@ -589,7 +589,7 @@ LL | asm!("", out("vs49") _, out("v17") _); | register `vs49` error: register `v18` conflicts with register `vs50` - --> $DIR/bad-reg.rs:306:33 + --> $DIR/bad-reg.rs:308:33 | LL | asm!("", out("vs50") _, out("v18") _); | ------------- ^^^^^^^^^^^^ register `v18` @@ -597,7 +597,7 @@ LL | asm!("", out("vs50") _, out("v18") _); | register `vs50` error: register `v19` conflicts with register `vs51` - --> $DIR/bad-reg.rs:308:33 + --> $DIR/bad-reg.rs:310:33 | LL | asm!("", out("vs51") _, out("v19") _); | ------------- ^^^^^^^^^^^^ register `v19` @@ -605,7 +605,7 @@ LL | asm!("", out("vs51") _, out("v19") _); | register `vs51` error: register `v20` conflicts with register `vs52` - --> $DIR/bad-reg.rs:310:33 + --> $DIR/bad-reg.rs:312:33 | LL | asm!("", out("vs52") _, out("v20") _); | ------------- ^^^^^^^^^^^^ register `v20` @@ -613,7 +613,7 @@ LL | asm!("", out("vs52") _, out("v20") _); | register `vs52` error: register `v21` conflicts with register `vs53` - --> $DIR/bad-reg.rs:312:33 + --> $DIR/bad-reg.rs:314:33 | LL | asm!("", out("vs53") _, out("v21") _); | ------------- ^^^^^^^^^^^^ register `v21` @@ -621,7 +621,7 @@ LL | asm!("", out("vs53") _, out("v21") _); | register `vs53` error: register `v22` conflicts with register `vs54` - --> $DIR/bad-reg.rs:314:33 + --> $DIR/bad-reg.rs:316:33 | LL | asm!("", out("vs54") _, out("v22") _); | ------------- ^^^^^^^^^^^^ register `v22` @@ -629,7 +629,7 @@ LL | asm!("", out("vs54") _, out("v22") _); | register `vs54` error: register `v23` conflicts with register `vs55` - --> $DIR/bad-reg.rs:316:33 + --> $DIR/bad-reg.rs:318:33 | LL | asm!("", out("vs55") _, out("v23") _); | ------------- ^^^^^^^^^^^^ register `v23` @@ -637,7 +637,7 @@ LL | asm!("", out("vs55") _, out("v23") _); | register `vs55` error: register `v24` conflicts with register `vs56` - --> $DIR/bad-reg.rs:318:33 + --> $DIR/bad-reg.rs:320:33 | LL | asm!("", out("vs56") _, out("v24") _); | ------------- ^^^^^^^^^^^^ register `v24` @@ -645,7 +645,7 @@ LL | asm!("", out("vs56") _, out("v24") _); | register `vs56` error: register `v25` conflicts with register `vs57` - --> $DIR/bad-reg.rs:320:33 + --> $DIR/bad-reg.rs:322:33 | LL | asm!("", out("vs57") _, out("v25") _); | ------------- ^^^^^^^^^^^^ register `v25` @@ -653,7 +653,7 @@ LL | asm!("", out("vs57") _, out("v25") _); | register `vs57` error: register `v26` conflicts with register `vs58` - --> $DIR/bad-reg.rs:322:33 + --> $DIR/bad-reg.rs:324:33 | LL | asm!("", out("vs58") _, out("v26") _); | ------------- ^^^^^^^^^^^^ register `v26` @@ -661,7 +661,7 @@ LL | asm!("", out("vs58") _, out("v26") _); | register `vs58` error: register `v27` conflicts with register `vs59` - --> $DIR/bad-reg.rs:324:33 + --> $DIR/bad-reg.rs:326:33 | LL | asm!("", out("vs59") _, out("v27") _); | ------------- ^^^^^^^^^^^^ register `v27` @@ -669,7 +669,7 @@ LL | asm!("", out("vs59") _, out("v27") _); | register `vs59` error: register `v28` conflicts with register `vs60` - --> $DIR/bad-reg.rs:326:33 + --> $DIR/bad-reg.rs:328:33 | LL | asm!("", out("vs60") _, out("v28") _); | ------------- ^^^^^^^^^^^^ register `v28` @@ -677,7 +677,7 @@ LL | asm!("", out("vs60") _, out("v28") _); | register `vs60` error: register `v29` conflicts with register `vs61` - --> $DIR/bad-reg.rs:328:33 + --> $DIR/bad-reg.rs:330:33 | LL | asm!("", out("vs61") _, out("v29") _); | ------------- ^^^^^^^^^^^^ register `v29` @@ -685,7 +685,7 @@ LL | asm!("", out("vs61") _, out("v29") _); | register `vs61` error: register `v30` conflicts with register `vs62` - --> $DIR/bad-reg.rs:330:33 + --> $DIR/bad-reg.rs:332:33 | LL | asm!("", out("vs62") _, out("v30") _); | ------------- ^^^^^^^^^^^^ register `v30` @@ -693,147 +693,153 @@ LL | asm!("", out("vs62") _, out("v30") _); | register `vs62` error: register `v31` conflicts with register `vs63` - --> $DIR/bad-reg.rs:332:33 + --> $DIR/bad-reg.rs:334:33 | LL | asm!("", out("vs63") _, out("v31") _); | ------------- ^^^^^^^^^^^^ register `v31` | | | register `vs63` +error: register class `spe_acc` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:340:26 + | +LL | asm!("/* {} */", out(spe_acc) _); + | ^^^^^^^^^^^^^^ + error: cannot use register `r13`: r13 is a reserved register on this target - --> $DIR/bad-reg.rs:40:18 + --> $DIR/bad-reg.rs:42:18 | LL | asm!("", out("r13") _); | ^^^^^^^^^^^^ error: cannot use register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:42:18 + --> $DIR/bad-reg.rs:44:18 | LL | asm!("", out("r29") _); | ^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:53:18 + --> $DIR/bad-reg.rs:55:18 | LL | asm!("", in("v0") v32x4); // requires altivec | ^^^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:55:18 + --> $DIR/bad-reg.rs:57:18 | LL | asm!("", out("v0") v32x4); // requires altivec | ^^^^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:57:18 + --> $DIR/bad-reg.rs:59:18 | LL | asm!("", in("v0") v64x2); // requires vsx | ^^^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:60:18 + --> $DIR/bad-reg.rs:62:18 | LL | asm!("", out("v0") v64x2); // requires vsx | ^^^^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:63:18 + --> $DIR/bad-reg.rs:65:18 | LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available | ^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:66:18 + --> $DIR/bad-reg.rs:68:18 | LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available | ^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:69:26 + --> $DIR/bad-reg.rs:71:26 | LL | asm!("/* {} */", in(vreg) v32x4); // requires altivec | ^^^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:71:26 + --> $DIR/bad-reg.rs:73:26 | LL | asm!("/* {} */", in(vreg) v64x2); // requires vsx | ^^^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:74:26 + --> $DIR/bad-reg.rs:76:26 | LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available | ^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:77:26 + --> $DIR/bad-reg.rs:79:26 | LL | asm!("/* {} */", out(vreg) _); // requires altivec | ^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:96:18 + --> $DIR/bad-reg.rs:98:18 | LL | asm!("", in("vs0") v32x4); // requires vsx | ^^^^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:98:18 + --> $DIR/bad-reg.rs:100:18 | LL | asm!("", out("vs0") v32x4); // requires vsx | ^^^^^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:100:18 + --> $DIR/bad-reg.rs:102:18 | LL | asm!("", in("vs0") v64x2); // requires vsx | ^^^^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:102:18 + --> $DIR/bad-reg.rs:104:18 | LL | asm!("", out("vs0") v64x2); // requires vsx | ^^^^^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:104:18 + --> $DIR/bad-reg.rs:106:18 | LL | asm!("", in("vs0") x); // FIXME: should be ok if vsx is available | ^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:107:18 + --> $DIR/bad-reg.rs:109:18 | LL | asm!("", out("vs0") x); // FIXME: should be ok if vsx is available | ^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:110:26 + --> $DIR/bad-reg.rs:112:26 | LL | asm!("/* {} */", in(vsreg) v32x4); // requires vsx | ^^^^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:112:26 + --> $DIR/bad-reg.rs:114:26 | LL | asm!("/* {} */", in(vsreg) v64x2); // requires vsx | ^^^^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:114:26 + --> $DIR/bad-reg.rs:116:26 | LL | asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is available | ^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:117:26 + --> $DIR/bad-reg.rs:119:26 | LL | asm!("/* {} */", out(vsreg) _); // requires vsx | ^^^^^^^^^^^^ error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:137:27 + --> $DIR/bad-reg.rs:139:27 | LL | asm!("", in("cr") x); | ^ @@ -841,7 +847,7 @@ LL | asm!("", in("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:140:28 + --> $DIR/bad-reg.rs:142:28 | LL | asm!("", out("cr") x); | ^ @@ -849,7 +855,7 @@ LL | asm!("", out("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:143:33 + --> $DIR/bad-reg.rs:145:33 | LL | asm!("/* {} */", in(cr) x); | ^ @@ -857,7 +863,7 @@ LL | asm!("/* {} */", in(cr) x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:150:28 + --> $DIR/bad-reg.rs:152:28 | LL | asm!("", in("ctr") x); | ^ @@ -865,7 +871,7 @@ LL | asm!("", in("ctr") x); = note: register class `ctr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:153:29 + --> $DIR/bad-reg.rs:155:29 | LL | asm!("", out("ctr") x); | ^ @@ -873,7 +879,7 @@ LL | asm!("", out("ctr") x); = note: register class `ctr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:156:34 + --> $DIR/bad-reg.rs:158:34 | LL | asm!("/* {} */", in(ctr) x); | ^ @@ -881,7 +887,7 @@ LL | asm!("/* {} */", in(ctr) x); = note: register class `ctr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:163:27 + --> $DIR/bad-reg.rs:165:27 | LL | asm!("", in("lr") x); | ^ @@ -889,7 +895,7 @@ LL | asm!("", in("lr") x); = note: register class `lr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:166:28 + --> $DIR/bad-reg.rs:168:28 | LL | asm!("", out("lr") x); | ^ @@ -897,7 +903,7 @@ LL | asm!("", out("lr") x); = note: register class `lr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:169:33 + --> $DIR/bad-reg.rs:171:33 | LL | asm!("/* {} */", in(lr) x); | ^ @@ -905,7 +911,7 @@ LL | asm!("/* {} */", in(lr) x); = note: register class `lr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:176:28 + --> $DIR/bad-reg.rs:178:28 | LL | asm!("", in("xer") x); | ^ @@ -913,7 +919,7 @@ LL | asm!("", in("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:179:29 + --> $DIR/bad-reg.rs:181:29 | LL | asm!("", out("xer") x); | ^ @@ -921,12 +927,18 @@ LL | asm!("", out("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:182:34 + --> $DIR/bad-reg.rs:184:34 | LL | asm!("/* {} */", in(xer) x); | ^ | = note: register class `xer` supports these types: -error: aborting due to 127 previous errors +error: cannot use register `spe_acc`: spe_acc is only available on spe targets + --> $DIR/bad-reg.rs:338:18 + | +LL | asm!("", out("spe_acc") _); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 129 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr index 552fb0504b8d..151bb5682e03 100644 --- a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr +++ b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr @@ -1,131 +1,131 @@ error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:36:18 + --> $DIR/bad-reg.rs:38:18 | LL | asm!("", out("sp") _); | ^^^^^^^^^^^ error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:38:18 + --> $DIR/bad-reg.rs:40:18 | LL | asm!("", out("r2") _); | ^^^^^^^^^^^ error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:44:18 + --> $DIR/bad-reg.rs:46:18 | LL | asm!("", out("r30") _); | ^^^^^^^^^^^^ error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:46:18 + --> $DIR/bad-reg.rs:48:18 | LL | asm!("", out("fp") _); | ^^^^^^^^^^^ error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:48:18 + --> $DIR/bad-reg.rs:50:18 | LL | asm!("", out("vrsave") _); | ^^^^^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:137:18 + --> $DIR/bad-reg.rs:139:18 | LL | asm!("", in("cr") x); | ^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:140:18 + --> $DIR/bad-reg.rs:142:18 | LL | asm!("", out("cr") x); | ^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:143:26 + --> $DIR/bad-reg.rs:145:26 | LL | asm!("/* {} */", in(cr) x); | ^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:146:26 + --> $DIR/bad-reg.rs:148:26 | LL | asm!("/* {} */", out(cr) _); | ^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:150:18 + --> $DIR/bad-reg.rs:152:18 | LL | asm!("", in("ctr") x); | ^^^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:153:18 + --> $DIR/bad-reg.rs:155:18 | LL | asm!("", out("ctr") x); | ^^^^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:156:26 + --> $DIR/bad-reg.rs:158:26 | LL | asm!("/* {} */", in(ctr) x); | ^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:159:26 + --> $DIR/bad-reg.rs:161:26 | LL | asm!("/* {} */", out(ctr) _); | ^^^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:163:18 + --> $DIR/bad-reg.rs:165:18 | LL | asm!("", in("lr") x); | ^^^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:166:18 + --> $DIR/bad-reg.rs:168:18 | LL | asm!("", out("lr") x); | ^^^^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:169:26 + --> $DIR/bad-reg.rs:171:26 | LL | asm!("/* {} */", in(lr) x); | ^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:172:26 + --> $DIR/bad-reg.rs:174:26 | LL | asm!("/* {} */", out(lr) _); | ^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:176:18 + --> $DIR/bad-reg.rs:178:18 | LL | asm!("", in("xer") x); | ^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:179:18 + --> $DIR/bad-reg.rs:181:18 | LL | asm!("", out("xer") x); | ^^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:182:26 + --> $DIR/bad-reg.rs:184:26 | LL | asm!("/* {} */", in(xer) x); | ^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:185:26 + --> $DIR/bad-reg.rs:187:26 | LL | asm!("/* {} */", out(xer) _); | ^^^^^^^^^^ error: register `cr0` conflicts with register `cr` - --> $DIR/bad-reg.rs:189:31 + --> $DIR/bad-reg.rs:191:31 | LL | asm!("", out("cr") _, out("cr0") _); | ----------- ^^^^^^^^^^^^ register `cr0` @@ -133,7 +133,7 @@ LL | asm!("", out("cr") _, out("cr0") _); | register `cr` error: register `cr1` conflicts with register `cr` - --> $DIR/bad-reg.rs:191:31 + --> $DIR/bad-reg.rs:193:31 | LL | asm!("", out("cr") _, out("cr1") _); | ----------- ^^^^^^^^^^^^ register `cr1` @@ -141,7 +141,7 @@ LL | asm!("", out("cr") _, out("cr1") _); | register `cr` error: register `cr2` conflicts with register `cr` - --> $DIR/bad-reg.rs:193:31 + --> $DIR/bad-reg.rs:195:31 | LL | asm!("", out("cr") _, out("cr2") _); | ----------- ^^^^^^^^^^^^ register `cr2` @@ -149,7 +149,7 @@ LL | asm!("", out("cr") _, out("cr2") _); | register `cr` error: register `cr3` conflicts with register `cr` - --> $DIR/bad-reg.rs:195:31 + --> $DIR/bad-reg.rs:197:31 | LL | asm!("", out("cr") _, out("cr3") _); | ----------- ^^^^^^^^^^^^ register `cr3` @@ -157,7 +157,7 @@ LL | asm!("", out("cr") _, out("cr3") _); | register `cr` error: register `cr4` conflicts with register `cr` - --> $DIR/bad-reg.rs:197:31 + --> $DIR/bad-reg.rs:199:31 | LL | asm!("", out("cr") _, out("cr4") _); | ----------- ^^^^^^^^^^^^ register `cr4` @@ -165,7 +165,7 @@ LL | asm!("", out("cr") _, out("cr4") _); | register `cr` error: register `cr5` conflicts with register `cr` - --> $DIR/bad-reg.rs:199:31 + --> $DIR/bad-reg.rs:201:31 | LL | asm!("", out("cr") _, out("cr5") _); | ----------- ^^^^^^^^^^^^ register `cr5` @@ -173,7 +173,7 @@ LL | asm!("", out("cr") _, out("cr5") _); | register `cr` error: register `cr6` conflicts with register `cr` - --> $DIR/bad-reg.rs:201:31 + --> $DIR/bad-reg.rs:203:31 | LL | asm!("", out("cr") _, out("cr6") _); | ----------- ^^^^^^^^^^^^ register `cr6` @@ -181,7 +181,7 @@ LL | asm!("", out("cr") _, out("cr6") _); | register `cr` error: register `cr7` conflicts with register `cr` - --> $DIR/bad-reg.rs:203:31 + --> $DIR/bad-reg.rs:205:31 | LL | asm!("", out("cr") _, out("cr7") _); | ----------- ^^^^^^^^^^^^ register `cr7` @@ -189,7 +189,7 @@ LL | asm!("", out("cr") _, out("cr7") _); | register `cr` error: register `vs0` conflicts with register `f0` - --> $DIR/bad-reg.rs:206:31 + --> $DIR/bad-reg.rs:208:31 | LL | asm!("", out("f0") _, out("vs0") _); | ----------- ^^^^^^^^^^^^ register `vs0` @@ -197,7 +197,7 @@ LL | asm!("", out("f0") _, out("vs0") _); | register `f0` error: register `vs1` conflicts with register `f1` - --> $DIR/bad-reg.rs:208:31 + --> $DIR/bad-reg.rs:210:31 | LL | asm!("", out("f1") _, out("vs1") _); | ----------- ^^^^^^^^^^^^ register `vs1` @@ -205,7 +205,7 @@ LL | asm!("", out("f1") _, out("vs1") _); | register `f1` error: register `vs2` conflicts with register `f2` - --> $DIR/bad-reg.rs:210:31 + --> $DIR/bad-reg.rs:212:31 | LL | asm!("", out("f2") _, out("vs2") _); | ----------- ^^^^^^^^^^^^ register `vs2` @@ -213,7 +213,7 @@ LL | asm!("", out("f2") _, out("vs2") _); | register `f2` error: register `vs3` conflicts with register `f3` - --> $DIR/bad-reg.rs:212:31 + --> $DIR/bad-reg.rs:214:31 | LL | asm!("", out("f3") _, out("vs3") _); | ----------- ^^^^^^^^^^^^ register `vs3` @@ -221,7 +221,7 @@ LL | asm!("", out("f3") _, out("vs3") _); | register `f3` error: register `vs4` conflicts with register `f4` - --> $DIR/bad-reg.rs:214:31 + --> $DIR/bad-reg.rs:216:31 | LL | asm!("", out("f4") _, out("vs4") _); | ----------- ^^^^^^^^^^^^ register `vs4` @@ -229,7 +229,7 @@ LL | asm!("", out("f4") _, out("vs4") _); | register `f4` error: register `vs5` conflicts with register `f5` - --> $DIR/bad-reg.rs:216:31 + --> $DIR/bad-reg.rs:218:31 | LL | asm!("", out("f5") _, out("vs5") _); | ----------- ^^^^^^^^^^^^ register `vs5` @@ -237,7 +237,7 @@ LL | asm!("", out("f5") _, out("vs5") _); | register `f5` error: register `vs6` conflicts with register `f6` - --> $DIR/bad-reg.rs:218:31 + --> $DIR/bad-reg.rs:220:31 | LL | asm!("", out("f6") _, out("vs6") _); | ----------- ^^^^^^^^^^^^ register `vs6` @@ -245,7 +245,7 @@ LL | asm!("", out("f6") _, out("vs6") _); | register `f6` error: register `vs7` conflicts with register `f7` - --> $DIR/bad-reg.rs:220:31 + --> $DIR/bad-reg.rs:222:31 | LL | asm!("", out("f7") _, out("vs7") _); | ----------- ^^^^^^^^^^^^ register `vs7` @@ -253,7 +253,7 @@ LL | asm!("", out("f7") _, out("vs7") _); | register `f7` error: register `vs8` conflicts with register `f8` - --> $DIR/bad-reg.rs:222:31 + --> $DIR/bad-reg.rs:224:31 | LL | asm!("", out("f8") _, out("vs8") _); | ----------- ^^^^^^^^^^^^ register `vs8` @@ -261,7 +261,7 @@ LL | asm!("", out("f8") _, out("vs8") _); | register `f8` error: register `vs9` conflicts with register `f9` - --> $DIR/bad-reg.rs:224:31 + --> $DIR/bad-reg.rs:226:31 | LL | asm!("", out("f9") _, out("vs9") _); | ----------- ^^^^^^^^^^^^ register `vs9` @@ -269,7 +269,7 @@ LL | asm!("", out("f9") _, out("vs9") _); | register `f9` error: register `vs10` conflicts with register `f10` - --> $DIR/bad-reg.rs:226:32 + --> $DIR/bad-reg.rs:228:32 | LL | asm!("", out("f10") _, out("vs10") _); | ------------ ^^^^^^^^^^^^^ register `vs10` @@ -277,7 +277,7 @@ LL | asm!("", out("f10") _, out("vs10") _); | register `f10` error: register `vs11` conflicts with register `f11` - --> $DIR/bad-reg.rs:228:32 + --> $DIR/bad-reg.rs:230:32 | LL | asm!("", out("f11") _, out("vs11") _); | ------------ ^^^^^^^^^^^^^ register `vs11` @@ -285,7 +285,7 @@ LL | asm!("", out("f11") _, out("vs11") _); | register `f11` error: register `vs12` conflicts with register `f12` - --> $DIR/bad-reg.rs:230:32 + --> $DIR/bad-reg.rs:232:32 | LL | asm!("", out("f12") _, out("vs12") _); | ------------ ^^^^^^^^^^^^^ register `vs12` @@ -293,7 +293,7 @@ LL | asm!("", out("f12") _, out("vs12") _); | register `f12` error: register `vs13` conflicts with register `f13` - --> $DIR/bad-reg.rs:232:32 + --> $DIR/bad-reg.rs:234:32 | LL | asm!("", out("f13") _, out("vs13") _); | ------------ ^^^^^^^^^^^^^ register `vs13` @@ -301,7 +301,7 @@ LL | asm!("", out("f13") _, out("vs13") _); | register `f13` error: register `vs14` conflicts with register `f14` - --> $DIR/bad-reg.rs:234:32 + --> $DIR/bad-reg.rs:236:32 | LL | asm!("", out("f14") _, out("vs14") _); | ------------ ^^^^^^^^^^^^^ register `vs14` @@ -309,7 +309,7 @@ LL | asm!("", out("f14") _, out("vs14") _); | register `f14` error: register `vs15` conflicts with register `f15` - --> $DIR/bad-reg.rs:236:32 + --> $DIR/bad-reg.rs:238:32 | LL | asm!("", out("f15") _, out("vs15") _); | ------------ ^^^^^^^^^^^^^ register `vs15` @@ -317,7 +317,7 @@ LL | asm!("", out("f15") _, out("vs15") _); | register `f15` error: register `vs16` conflicts with register `f16` - --> $DIR/bad-reg.rs:238:32 + --> $DIR/bad-reg.rs:240:32 | LL | asm!("", out("f16") _, out("vs16") _); | ------------ ^^^^^^^^^^^^^ register `vs16` @@ -325,7 +325,7 @@ LL | asm!("", out("f16") _, out("vs16") _); | register `f16` error: register `vs17` conflicts with register `f17` - --> $DIR/bad-reg.rs:240:32 + --> $DIR/bad-reg.rs:242:32 | LL | asm!("", out("f17") _, out("vs17") _); | ------------ ^^^^^^^^^^^^^ register `vs17` @@ -333,7 +333,7 @@ LL | asm!("", out("f17") _, out("vs17") _); | register `f17` error: register `vs18` conflicts with register `f18` - --> $DIR/bad-reg.rs:242:32 + --> $DIR/bad-reg.rs:244:32 | LL | asm!("", out("f18") _, out("vs18") _); | ------------ ^^^^^^^^^^^^^ register `vs18` @@ -341,7 +341,7 @@ LL | asm!("", out("f18") _, out("vs18") _); | register `f18` error: register `vs19` conflicts with register `f19` - --> $DIR/bad-reg.rs:244:32 + --> $DIR/bad-reg.rs:246:32 | LL | asm!("", out("f19") _, out("vs19") _); | ------------ ^^^^^^^^^^^^^ register `vs19` @@ -349,7 +349,7 @@ LL | asm!("", out("f19") _, out("vs19") _); | register `f19` error: register `vs20` conflicts with register `f20` - --> $DIR/bad-reg.rs:246:32 + --> $DIR/bad-reg.rs:248:32 | LL | asm!("", out("f20") _, out("vs20") _); | ------------ ^^^^^^^^^^^^^ register `vs20` @@ -357,7 +357,7 @@ LL | asm!("", out("f20") _, out("vs20") _); | register `f20` error: register `vs21` conflicts with register `f21` - --> $DIR/bad-reg.rs:248:32 + --> $DIR/bad-reg.rs:250:32 | LL | asm!("", out("f21") _, out("vs21") _); | ------------ ^^^^^^^^^^^^^ register `vs21` @@ -365,7 +365,7 @@ LL | asm!("", out("f21") _, out("vs21") _); | register `f21` error: register `vs22` conflicts with register `f22` - --> $DIR/bad-reg.rs:250:32 + --> $DIR/bad-reg.rs:252:32 | LL | asm!("", out("f22") _, out("vs22") _); | ------------ ^^^^^^^^^^^^^ register `vs22` @@ -373,7 +373,7 @@ LL | asm!("", out("f22") _, out("vs22") _); | register `f22` error: register `vs23` conflicts with register `f23` - --> $DIR/bad-reg.rs:252:32 + --> $DIR/bad-reg.rs:254:32 | LL | asm!("", out("f23") _, out("vs23") _); | ------------ ^^^^^^^^^^^^^ register `vs23` @@ -381,7 +381,7 @@ LL | asm!("", out("f23") _, out("vs23") _); | register `f23` error: register `vs24` conflicts with register `f24` - --> $DIR/bad-reg.rs:254:32 + --> $DIR/bad-reg.rs:256:32 | LL | asm!("", out("f24") _, out("vs24") _); | ------------ ^^^^^^^^^^^^^ register `vs24` @@ -389,7 +389,7 @@ LL | asm!("", out("f24") _, out("vs24") _); | register `f24` error: register `vs25` conflicts with register `f25` - --> $DIR/bad-reg.rs:256:32 + --> $DIR/bad-reg.rs:258:32 | LL | asm!("", out("f25") _, out("vs25") _); | ------------ ^^^^^^^^^^^^^ register `vs25` @@ -397,7 +397,7 @@ LL | asm!("", out("f25") _, out("vs25") _); | register `f25` error: register `vs26` conflicts with register `f26` - --> $DIR/bad-reg.rs:258:32 + --> $DIR/bad-reg.rs:260:32 | LL | asm!("", out("f26") _, out("vs26") _); | ------------ ^^^^^^^^^^^^^ register `vs26` @@ -405,7 +405,7 @@ LL | asm!("", out("f26") _, out("vs26") _); | register `f26` error: register `vs27` conflicts with register `f27` - --> $DIR/bad-reg.rs:260:32 + --> $DIR/bad-reg.rs:262:32 | LL | asm!("", out("f27") _, out("vs27") _); | ------------ ^^^^^^^^^^^^^ register `vs27` @@ -413,7 +413,7 @@ LL | asm!("", out("f27") _, out("vs27") _); | register `f27` error: register `vs28` conflicts with register `f28` - --> $DIR/bad-reg.rs:262:32 + --> $DIR/bad-reg.rs:264:32 | LL | asm!("", out("f28") _, out("vs28") _); | ------------ ^^^^^^^^^^^^^ register `vs28` @@ -421,7 +421,7 @@ LL | asm!("", out("f28") _, out("vs28") _); | register `f28` error: register `vs29` conflicts with register `f29` - --> $DIR/bad-reg.rs:264:32 + --> $DIR/bad-reg.rs:266:32 | LL | asm!("", out("f29") _, out("vs29") _); | ------------ ^^^^^^^^^^^^^ register `vs29` @@ -429,7 +429,7 @@ LL | asm!("", out("f29") _, out("vs29") _); | register `f29` error: register `vs30` conflicts with register `f30` - --> $DIR/bad-reg.rs:266:32 + --> $DIR/bad-reg.rs:268:32 | LL | asm!("", out("f30") _, out("vs30") _); | ------------ ^^^^^^^^^^^^^ register `vs30` @@ -437,7 +437,7 @@ LL | asm!("", out("f30") _, out("vs30") _); | register `f30` error: register `vs31` conflicts with register `f31` - --> $DIR/bad-reg.rs:268:32 + --> $DIR/bad-reg.rs:270:32 | LL | asm!("", out("f31") _, out("vs31") _); | ------------ ^^^^^^^^^^^^^ register `vs31` @@ -445,7 +445,7 @@ LL | asm!("", out("f31") _, out("vs31") _); | register `f31` error: register `v0` conflicts with register `vs32` - --> $DIR/bad-reg.rs:270:33 + --> $DIR/bad-reg.rs:272:33 | LL | asm!("", out("vs32") _, out("v0") _); | ------------- ^^^^^^^^^^^ register `v0` @@ -453,7 +453,7 @@ LL | asm!("", out("vs32") _, out("v0") _); | register `vs32` error: register `v1` conflicts with register `vs33` - --> $DIR/bad-reg.rs:272:33 + --> $DIR/bad-reg.rs:274:33 | LL | asm!("", out("vs33") _, out("v1") _); | ------------- ^^^^^^^^^^^ register `v1` @@ -461,7 +461,7 @@ LL | asm!("", out("vs33") _, out("v1") _); | register `vs33` error: register `v2` conflicts with register `vs34` - --> $DIR/bad-reg.rs:274:33 + --> $DIR/bad-reg.rs:276:33 | LL | asm!("", out("vs34") _, out("v2") _); | ------------- ^^^^^^^^^^^ register `v2` @@ -469,7 +469,7 @@ LL | asm!("", out("vs34") _, out("v2") _); | register `vs34` error: register `v3` conflicts with register `vs35` - --> $DIR/bad-reg.rs:276:33 + --> $DIR/bad-reg.rs:278:33 | LL | asm!("", out("vs35") _, out("v3") _); | ------------- ^^^^^^^^^^^ register `v3` @@ -477,7 +477,7 @@ LL | asm!("", out("vs35") _, out("v3") _); | register `vs35` error: register `v4` conflicts with register `vs36` - --> $DIR/bad-reg.rs:278:33 + --> $DIR/bad-reg.rs:280:33 | LL | asm!("", out("vs36") _, out("v4") _); | ------------- ^^^^^^^^^^^ register `v4` @@ -485,7 +485,7 @@ LL | asm!("", out("vs36") _, out("v4") _); | register `vs36` error: register `v5` conflicts with register `vs37` - --> $DIR/bad-reg.rs:280:33 + --> $DIR/bad-reg.rs:282:33 | LL | asm!("", out("vs37") _, out("v5") _); | ------------- ^^^^^^^^^^^ register `v5` @@ -493,7 +493,7 @@ LL | asm!("", out("vs37") _, out("v5") _); | register `vs37` error: register `v6` conflicts with register `vs38` - --> $DIR/bad-reg.rs:282:33 + --> $DIR/bad-reg.rs:284:33 | LL | asm!("", out("vs38") _, out("v6") _); | ------------- ^^^^^^^^^^^ register `v6` @@ -501,7 +501,7 @@ LL | asm!("", out("vs38") _, out("v6") _); | register `vs38` error: register `v7` conflicts with register `vs39` - --> $DIR/bad-reg.rs:284:33 + --> $DIR/bad-reg.rs:286:33 | LL | asm!("", out("vs39") _, out("v7") _); | ------------- ^^^^^^^^^^^ register `v7` @@ -509,7 +509,7 @@ LL | asm!("", out("vs39") _, out("v7") _); | register `vs39` error: register `v8` conflicts with register `vs40` - --> $DIR/bad-reg.rs:286:33 + --> $DIR/bad-reg.rs:288:33 | LL | asm!("", out("vs40") _, out("v8") _); | ------------- ^^^^^^^^^^^ register `v8` @@ -517,7 +517,7 @@ LL | asm!("", out("vs40") _, out("v8") _); | register `vs40` error: register `v9` conflicts with register `vs41` - --> $DIR/bad-reg.rs:288:33 + --> $DIR/bad-reg.rs:290:33 | LL | asm!("", out("vs41") _, out("v9") _); | ------------- ^^^^^^^^^^^ register `v9` @@ -525,7 +525,7 @@ LL | asm!("", out("vs41") _, out("v9") _); | register `vs41` error: register `v10` conflicts with register `vs42` - --> $DIR/bad-reg.rs:290:33 + --> $DIR/bad-reg.rs:292:33 | LL | asm!("", out("vs42") _, out("v10") _); | ------------- ^^^^^^^^^^^^ register `v10` @@ -533,7 +533,7 @@ LL | asm!("", out("vs42") _, out("v10") _); | register `vs42` error: register `v11` conflicts with register `vs43` - --> $DIR/bad-reg.rs:292:33 + --> $DIR/bad-reg.rs:294:33 | LL | asm!("", out("vs43") _, out("v11") _); | ------------- ^^^^^^^^^^^^ register `v11` @@ -541,7 +541,7 @@ LL | asm!("", out("vs43") _, out("v11") _); | register `vs43` error: register `v12` conflicts with register `vs44` - --> $DIR/bad-reg.rs:294:33 + --> $DIR/bad-reg.rs:296:33 | LL | asm!("", out("vs44") _, out("v12") _); | ------------- ^^^^^^^^^^^^ register `v12` @@ -549,7 +549,7 @@ LL | asm!("", out("vs44") _, out("v12") _); | register `vs44` error: register `v13` conflicts with register `vs45` - --> $DIR/bad-reg.rs:296:33 + --> $DIR/bad-reg.rs:298:33 | LL | asm!("", out("vs45") _, out("v13") _); | ------------- ^^^^^^^^^^^^ register `v13` @@ -557,7 +557,7 @@ LL | asm!("", out("vs45") _, out("v13") _); | register `vs45` error: register `v14` conflicts with register `vs46` - --> $DIR/bad-reg.rs:298:33 + --> $DIR/bad-reg.rs:300:33 | LL | asm!("", out("vs46") _, out("v14") _); | ------------- ^^^^^^^^^^^^ register `v14` @@ -565,7 +565,7 @@ LL | asm!("", out("vs46") _, out("v14") _); | register `vs46` error: register `v15` conflicts with register `vs47` - --> $DIR/bad-reg.rs:300:33 + --> $DIR/bad-reg.rs:302:33 | LL | asm!("", out("vs47") _, out("v15") _); | ------------- ^^^^^^^^^^^^ register `v15` @@ -573,7 +573,7 @@ LL | asm!("", out("vs47") _, out("v15") _); | register `vs47` error: register `v16` conflicts with register `vs48` - --> $DIR/bad-reg.rs:302:33 + --> $DIR/bad-reg.rs:304:33 | LL | asm!("", out("vs48") _, out("v16") _); | ------------- ^^^^^^^^^^^^ register `v16` @@ -581,7 +581,7 @@ LL | asm!("", out("vs48") _, out("v16") _); | register `vs48` error: register `v17` conflicts with register `vs49` - --> $DIR/bad-reg.rs:304:33 + --> $DIR/bad-reg.rs:306:33 | LL | asm!("", out("vs49") _, out("v17") _); | ------------- ^^^^^^^^^^^^ register `v17` @@ -589,7 +589,7 @@ LL | asm!("", out("vs49") _, out("v17") _); | register `vs49` error: register `v18` conflicts with register `vs50` - --> $DIR/bad-reg.rs:306:33 + --> $DIR/bad-reg.rs:308:33 | LL | asm!("", out("vs50") _, out("v18") _); | ------------- ^^^^^^^^^^^^ register `v18` @@ -597,7 +597,7 @@ LL | asm!("", out("vs50") _, out("v18") _); | register `vs50` error: register `v19` conflicts with register `vs51` - --> $DIR/bad-reg.rs:308:33 + --> $DIR/bad-reg.rs:310:33 | LL | asm!("", out("vs51") _, out("v19") _); | ------------- ^^^^^^^^^^^^ register `v19` @@ -605,7 +605,7 @@ LL | asm!("", out("vs51") _, out("v19") _); | register `vs51` error: register `v20` conflicts with register `vs52` - --> $DIR/bad-reg.rs:310:33 + --> $DIR/bad-reg.rs:312:33 | LL | asm!("", out("vs52") _, out("v20") _); | ------------- ^^^^^^^^^^^^ register `v20` @@ -613,7 +613,7 @@ LL | asm!("", out("vs52") _, out("v20") _); | register `vs52` error: register `v21` conflicts with register `vs53` - --> $DIR/bad-reg.rs:312:33 + --> $DIR/bad-reg.rs:314:33 | LL | asm!("", out("vs53") _, out("v21") _); | ------------- ^^^^^^^^^^^^ register `v21` @@ -621,7 +621,7 @@ LL | asm!("", out("vs53") _, out("v21") _); | register `vs53` error: register `v22` conflicts with register `vs54` - --> $DIR/bad-reg.rs:314:33 + --> $DIR/bad-reg.rs:316:33 | LL | asm!("", out("vs54") _, out("v22") _); | ------------- ^^^^^^^^^^^^ register `v22` @@ -629,7 +629,7 @@ LL | asm!("", out("vs54") _, out("v22") _); | register `vs54` error: register `v23` conflicts with register `vs55` - --> $DIR/bad-reg.rs:316:33 + --> $DIR/bad-reg.rs:318:33 | LL | asm!("", out("vs55") _, out("v23") _); | ------------- ^^^^^^^^^^^^ register `v23` @@ -637,7 +637,7 @@ LL | asm!("", out("vs55") _, out("v23") _); | register `vs55` error: register `v24` conflicts with register `vs56` - --> $DIR/bad-reg.rs:318:33 + --> $DIR/bad-reg.rs:320:33 | LL | asm!("", out("vs56") _, out("v24") _); | ------------- ^^^^^^^^^^^^ register `v24` @@ -645,7 +645,7 @@ LL | asm!("", out("vs56") _, out("v24") _); | register `vs56` error: register `v25` conflicts with register `vs57` - --> $DIR/bad-reg.rs:320:33 + --> $DIR/bad-reg.rs:322:33 | LL | asm!("", out("vs57") _, out("v25") _); | ------------- ^^^^^^^^^^^^ register `v25` @@ -653,7 +653,7 @@ LL | asm!("", out("vs57") _, out("v25") _); | register `vs57` error: register `v26` conflicts with register `vs58` - --> $DIR/bad-reg.rs:322:33 + --> $DIR/bad-reg.rs:324:33 | LL | asm!("", out("vs58") _, out("v26") _); | ------------- ^^^^^^^^^^^^ register `v26` @@ -661,7 +661,7 @@ LL | asm!("", out("vs58") _, out("v26") _); | register `vs58` error: register `v27` conflicts with register `vs59` - --> $DIR/bad-reg.rs:324:33 + --> $DIR/bad-reg.rs:326:33 | LL | asm!("", out("vs59") _, out("v27") _); | ------------- ^^^^^^^^^^^^ register `v27` @@ -669,7 +669,7 @@ LL | asm!("", out("vs59") _, out("v27") _); | register `vs59` error: register `v28` conflicts with register `vs60` - --> $DIR/bad-reg.rs:326:33 + --> $DIR/bad-reg.rs:328:33 | LL | asm!("", out("vs60") _, out("v28") _); | ------------- ^^^^^^^^^^^^ register `v28` @@ -677,7 +677,7 @@ LL | asm!("", out("vs60") _, out("v28") _); | register `vs60` error: register `v29` conflicts with register `vs61` - --> $DIR/bad-reg.rs:328:33 + --> $DIR/bad-reg.rs:330:33 | LL | asm!("", out("vs61") _, out("v29") _); | ------------- ^^^^^^^^^^^^ register `v29` @@ -685,7 +685,7 @@ LL | asm!("", out("vs61") _, out("v29") _); | register `vs61` error: register `v30` conflicts with register `vs62` - --> $DIR/bad-reg.rs:330:33 + --> $DIR/bad-reg.rs:332:33 | LL | asm!("", out("vs62") _, out("v30") _); | ------------- ^^^^^^^^^^^^ register `v30` @@ -693,21 +693,27 @@ LL | asm!("", out("vs62") _, out("v30") _); | register `vs62` error: register `v31` conflicts with register `vs63` - --> $DIR/bad-reg.rs:332:33 + --> $DIR/bad-reg.rs:334:33 | LL | asm!("", out("vs63") _, out("v31") _); | ------------- ^^^^^^^^^^^^ register `v31` | | | register `vs63` +error: register class `spe_acc` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:340:26 + | +LL | asm!("/* {} */", out(spe_acc) _); + | ^^^^^^^^^^^^^^ + error: cannot use register `r13`: r13 is a reserved register on this target - --> $DIR/bad-reg.rs:40:18 + --> $DIR/bad-reg.rs:42:18 | LL | asm!("", out("r13") _); | ^^^^^^^^^^^^ error: `vsx` target feature is not enabled - --> $DIR/bad-reg.rs:57:27 + --> $DIR/bad-reg.rs:59:27 | LL | asm!("", in("v0") v64x2); // requires vsx | ^^^^^ @@ -715,7 +721,7 @@ LL | asm!("", in("v0") v64x2); // requires vsx = note: this is required to use type `i64x2` with register class `vreg` error: `vsx` target feature is not enabled - --> $DIR/bad-reg.rs:60:28 + --> $DIR/bad-reg.rs:62:28 | LL | asm!("", out("v0") v64x2); // requires vsx | ^^^^^ @@ -723,7 +729,7 @@ LL | asm!("", out("v0") v64x2); // requires vsx = note: this is required to use type `i64x2` with register class `vreg` error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:63:27 + --> $DIR/bad-reg.rs:65:27 | LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available | ^ @@ -731,7 +737,7 @@ LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:66:28 + --> $DIR/bad-reg.rs:68:28 | LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available | ^ @@ -739,7 +745,7 @@ LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: `vsx` target feature is not enabled - --> $DIR/bad-reg.rs:71:35 + --> $DIR/bad-reg.rs:73:35 | LL | asm!("/* {} */", in(vreg) v64x2); // requires vsx | ^^^^^ @@ -747,7 +753,7 @@ LL | asm!("/* {} */", in(vreg) v64x2); // requires vsx = note: this is required to use type `i64x2` with register class `vreg` error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:74:35 + --> $DIR/bad-reg.rs:76:35 | LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available | ^ @@ -755,67 +761,67 @@ LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:96:18 + --> $DIR/bad-reg.rs:98:18 | LL | asm!("", in("vs0") v32x4); // requires vsx | ^^^^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:98:18 + --> $DIR/bad-reg.rs:100:18 | LL | asm!("", out("vs0") v32x4); // requires vsx | ^^^^^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:100:18 + --> $DIR/bad-reg.rs:102:18 | LL | asm!("", in("vs0") v64x2); // requires vsx | ^^^^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:102:18 + --> $DIR/bad-reg.rs:104:18 | LL | asm!("", out("vs0") v64x2); // requires vsx | ^^^^^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:104:18 + --> $DIR/bad-reg.rs:106:18 | LL | asm!("", in("vs0") x); // FIXME: should be ok if vsx is available | ^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:107:18 + --> $DIR/bad-reg.rs:109:18 | LL | asm!("", out("vs0") x); // FIXME: should be ok if vsx is available | ^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:110:26 + --> $DIR/bad-reg.rs:112:26 | LL | asm!("/* {} */", in(vsreg) v32x4); // requires vsx | ^^^^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:112:26 + --> $DIR/bad-reg.rs:114:26 | LL | asm!("/* {} */", in(vsreg) v64x2); // requires vsx | ^^^^^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:114:26 + --> $DIR/bad-reg.rs:116:26 | LL | asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is available | ^^^^^^^^^^^ error: register class `vsreg` requires the `vsx` target feature - --> $DIR/bad-reg.rs:117:26 + --> $DIR/bad-reg.rs:119:26 | LL | asm!("/* {} */", out(vsreg) _); // requires vsx | ^^^^^^^^^^^^ error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:137:27 + --> $DIR/bad-reg.rs:139:27 | LL | asm!("", in("cr") x); | ^ @@ -823,7 +829,7 @@ LL | asm!("", in("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:140:28 + --> $DIR/bad-reg.rs:142:28 | LL | asm!("", out("cr") x); | ^ @@ -831,7 +837,7 @@ LL | asm!("", out("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:143:33 + --> $DIR/bad-reg.rs:145:33 | LL | asm!("/* {} */", in(cr) x); | ^ @@ -839,7 +845,7 @@ LL | asm!("/* {} */", in(cr) x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:150:28 + --> $DIR/bad-reg.rs:152:28 | LL | asm!("", in("ctr") x); | ^ @@ -847,7 +853,7 @@ LL | asm!("", in("ctr") x); = note: register class `ctr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:153:29 + --> $DIR/bad-reg.rs:155:29 | LL | asm!("", out("ctr") x); | ^ @@ -855,7 +861,7 @@ LL | asm!("", out("ctr") x); = note: register class `ctr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:156:34 + --> $DIR/bad-reg.rs:158:34 | LL | asm!("/* {} */", in(ctr) x); | ^ @@ -863,7 +869,7 @@ LL | asm!("/* {} */", in(ctr) x); = note: register class `ctr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:163:27 + --> $DIR/bad-reg.rs:165:27 | LL | asm!("", in("lr") x); | ^ @@ -871,7 +877,7 @@ LL | asm!("", in("lr") x); = note: register class `lr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:166:28 + --> $DIR/bad-reg.rs:168:28 | LL | asm!("", out("lr") x); | ^ @@ -879,7 +885,7 @@ LL | asm!("", out("lr") x); = note: register class `lr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:169:33 + --> $DIR/bad-reg.rs:171:33 | LL | asm!("/* {} */", in(lr) x); | ^ @@ -887,7 +893,7 @@ LL | asm!("/* {} */", in(lr) x); = note: register class `lr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:176:28 + --> $DIR/bad-reg.rs:178:28 | LL | asm!("", in("xer") x); | ^ @@ -895,7 +901,7 @@ LL | asm!("", in("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:179:29 + --> $DIR/bad-reg.rs:181:29 | LL | asm!("", out("xer") x); | ^ @@ -903,12 +909,18 @@ LL | asm!("", out("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:182:34 + --> $DIR/bad-reg.rs:184:34 | LL | asm!("/* {} */", in(xer) x); | ^ | = note: register class `xer` supports these types: -error: aborting due to 122 previous errors +error: cannot use register `spe_acc`: spe_acc is only available on spe targets + --> $DIR/bad-reg.rs:338:18 + | +LL | asm!("", out("spe_acc") _); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 124 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr index 4490053215b5..c7373780e382 100644 --- a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr +++ b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr @@ -1,131 +1,131 @@ error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:36:18 + --> $DIR/bad-reg.rs:38:18 | LL | asm!("", out("sp") _); | ^^^^^^^^^^^ error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:38:18 + --> $DIR/bad-reg.rs:40:18 | LL | asm!("", out("r2") _); | ^^^^^^^^^^^ error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:44:18 + --> $DIR/bad-reg.rs:46:18 | LL | asm!("", out("r30") _); | ^^^^^^^^^^^^ error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:46:18 + --> $DIR/bad-reg.rs:48:18 | LL | asm!("", out("fp") _); | ^^^^^^^^^^^ error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:48:18 + --> $DIR/bad-reg.rs:50:18 | LL | asm!("", out("vrsave") _); | ^^^^^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:137:18 + --> $DIR/bad-reg.rs:139:18 | LL | asm!("", in("cr") x); | ^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:140:18 + --> $DIR/bad-reg.rs:142:18 | LL | asm!("", out("cr") x); | ^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:143:26 + --> $DIR/bad-reg.rs:145:26 | LL | asm!("/* {} */", in(cr) x); | ^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:146:26 + --> $DIR/bad-reg.rs:148:26 | LL | asm!("/* {} */", out(cr) _); | ^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:150:18 + --> $DIR/bad-reg.rs:152:18 | LL | asm!("", in("ctr") x); | ^^^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:153:18 + --> $DIR/bad-reg.rs:155:18 | LL | asm!("", out("ctr") x); | ^^^^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:156:26 + --> $DIR/bad-reg.rs:158:26 | LL | asm!("/* {} */", in(ctr) x); | ^^^^^^^^^ error: register class `ctr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:159:26 + --> $DIR/bad-reg.rs:161:26 | LL | asm!("/* {} */", out(ctr) _); | ^^^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:163:18 + --> $DIR/bad-reg.rs:165:18 | LL | asm!("", in("lr") x); | ^^^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:166:18 + --> $DIR/bad-reg.rs:168:18 | LL | asm!("", out("lr") x); | ^^^^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:169:26 + --> $DIR/bad-reg.rs:171:26 | LL | asm!("/* {} */", in(lr) x); | ^^^^^^^^ error: register class `lr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:172:26 + --> $DIR/bad-reg.rs:174:26 | LL | asm!("/* {} */", out(lr) _); | ^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:176:18 + --> $DIR/bad-reg.rs:178:18 | LL | asm!("", in("xer") x); | ^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:179:18 + --> $DIR/bad-reg.rs:181:18 | LL | asm!("", out("xer") x); | ^^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:182:26 + --> $DIR/bad-reg.rs:184:26 | LL | asm!("/* {} */", in(xer) x); | ^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:185:26 + --> $DIR/bad-reg.rs:187:26 | LL | asm!("/* {} */", out(xer) _); | ^^^^^^^^^^ error: register `cr0` conflicts with register `cr` - --> $DIR/bad-reg.rs:189:31 + --> $DIR/bad-reg.rs:191:31 | LL | asm!("", out("cr") _, out("cr0") _); | ----------- ^^^^^^^^^^^^ register `cr0` @@ -133,7 +133,7 @@ LL | asm!("", out("cr") _, out("cr0") _); | register `cr` error: register `cr1` conflicts with register `cr` - --> $DIR/bad-reg.rs:191:31 + --> $DIR/bad-reg.rs:193:31 | LL | asm!("", out("cr") _, out("cr1") _); | ----------- ^^^^^^^^^^^^ register `cr1` @@ -141,7 +141,7 @@ LL | asm!("", out("cr") _, out("cr1") _); | register `cr` error: register `cr2` conflicts with register `cr` - --> $DIR/bad-reg.rs:193:31 + --> $DIR/bad-reg.rs:195:31 | LL | asm!("", out("cr") _, out("cr2") _); | ----------- ^^^^^^^^^^^^ register `cr2` @@ -149,7 +149,7 @@ LL | asm!("", out("cr") _, out("cr2") _); | register `cr` error: register `cr3` conflicts with register `cr` - --> $DIR/bad-reg.rs:195:31 + --> $DIR/bad-reg.rs:197:31 | LL | asm!("", out("cr") _, out("cr3") _); | ----------- ^^^^^^^^^^^^ register `cr3` @@ -157,7 +157,7 @@ LL | asm!("", out("cr") _, out("cr3") _); | register `cr` error: register `cr4` conflicts with register `cr` - --> $DIR/bad-reg.rs:197:31 + --> $DIR/bad-reg.rs:199:31 | LL | asm!("", out("cr") _, out("cr4") _); | ----------- ^^^^^^^^^^^^ register `cr4` @@ -165,7 +165,7 @@ LL | asm!("", out("cr") _, out("cr4") _); | register `cr` error: register `cr5` conflicts with register `cr` - --> $DIR/bad-reg.rs:199:31 + --> $DIR/bad-reg.rs:201:31 | LL | asm!("", out("cr") _, out("cr5") _); | ----------- ^^^^^^^^^^^^ register `cr5` @@ -173,7 +173,7 @@ LL | asm!("", out("cr") _, out("cr5") _); | register `cr` error: register `cr6` conflicts with register `cr` - --> $DIR/bad-reg.rs:201:31 + --> $DIR/bad-reg.rs:203:31 | LL | asm!("", out("cr") _, out("cr6") _); | ----------- ^^^^^^^^^^^^ register `cr6` @@ -181,7 +181,7 @@ LL | asm!("", out("cr") _, out("cr6") _); | register `cr` error: register `cr7` conflicts with register `cr` - --> $DIR/bad-reg.rs:203:31 + --> $DIR/bad-reg.rs:205:31 | LL | asm!("", out("cr") _, out("cr7") _); | ----------- ^^^^^^^^^^^^ register `cr7` @@ -189,7 +189,7 @@ LL | asm!("", out("cr") _, out("cr7") _); | register `cr` error: register `vs0` conflicts with register `f0` - --> $DIR/bad-reg.rs:206:31 + --> $DIR/bad-reg.rs:208:31 | LL | asm!("", out("f0") _, out("vs0") _); | ----------- ^^^^^^^^^^^^ register `vs0` @@ -197,7 +197,7 @@ LL | asm!("", out("f0") _, out("vs0") _); | register `f0` error: register `vs1` conflicts with register `f1` - --> $DIR/bad-reg.rs:208:31 + --> $DIR/bad-reg.rs:210:31 | LL | asm!("", out("f1") _, out("vs1") _); | ----------- ^^^^^^^^^^^^ register `vs1` @@ -205,7 +205,7 @@ LL | asm!("", out("f1") _, out("vs1") _); | register `f1` error: register `vs2` conflicts with register `f2` - --> $DIR/bad-reg.rs:210:31 + --> $DIR/bad-reg.rs:212:31 | LL | asm!("", out("f2") _, out("vs2") _); | ----------- ^^^^^^^^^^^^ register `vs2` @@ -213,7 +213,7 @@ LL | asm!("", out("f2") _, out("vs2") _); | register `f2` error: register `vs3` conflicts with register `f3` - --> $DIR/bad-reg.rs:212:31 + --> $DIR/bad-reg.rs:214:31 | LL | asm!("", out("f3") _, out("vs3") _); | ----------- ^^^^^^^^^^^^ register `vs3` @@ -221,7 +221,7 @@ LL | asm!("", out("f3") _, out("vs3") _); | register `f3` error: register `vs4` conflicts with register `f4` - --> $DIR/bad-reg.rs:214:31 + --> $DIR/bad-reg.rs:216:31 | LL | asm!("", out("f4") _, out("vs4") _); | ----------- ^^^^^^^^^^^^ register `vs4` @@ -229,7 +229,7 @@ LL | asm!("", out("f4") _, out("vs4") _); | register `f4` error: register `vs5` conflicts with register `f5` - --> $DIR/bad-reg.rs:216:31 + --> $DIR/bad-reg.rs:218:31 | LL | asm!("", out("f5") _, out("vs5") _); | ----------- ^^^^^^^^^^^^ register `vs5` @@ -237,7 +237,7 @@ LL | asm!("", out("f5") _, out("vs5") _); | register `f5` error: register `vs6` conflicts with register `f6` - --> $DIR/bad-reg.rs:218:31 + --> $DIR/bad-reg.rs:220:31 | LL | asm!("", out("f6") _, out("vs6") _); | ----------- ^^^^^^^^^^^^ register `vs6` @@ -245,7 +245,7 @@ LL | asm!("", out("f6") _, out("vs6") _); | register `f6` error: register `vs7` conflicts with register `f7` - --> $DIR/bad-reg.rs:220:31 + --> $DIR/bad-reg.rs:222:31 | LL | asm!("", out("f7") _, out("vs7") _); | ----------- ^^^^^^^^^^^^ register `vs7` @@ -253,7 +253,7 @@ LL | asm!("", out("f7") _, out("vs7") _); | register `f7` error: register `vs8` conflicts with register `f8` - --> $DIR/bad-reg.rs:222:31 + --> $DIR/bad-reg.rs:224:31 | LL | asm!("", out("f8") _, out("vs8") _); | ----------- ^^^^^^^^^^^^ register `vs8` @@ -261,7 +261,7 @@ LL | asm!("", out("f8") _, out("vs8") _); | register `f8` error: register `vs9` conflicts with register `f9` - --> $DIR/bad-reg.rs:224:31 + --> $DIR/bad-reg.rs:226:31 | LL | asm!("", out("f9") _, out("vs9") _); | ----------- ^^^^^^^^^^^^ register `vs9` @@ -269,7 +269,7 @@ LL | asm!("", out("f9") _, out("vs9") _); | register `f9` error: register `vs10` conflicts with register `f10` - --> $DIR/bad-reg.rs:226:32 + --> $DIR/bad-reg.rs:228:32 | LL | asm!("", out("f10") _, out("vs10") _); | ------------ ^^^^^^^^^^^^^ register `vs10` @@ -277,7 +277,7 @@ LL | asm!("", out("f10") _, out("vs10") _); | register `f10` error: register `vs11` conflicts with register `f11` - --> $DIR/bad-reg.rs:228:32 + --> $DIR/bad-reg.rs:230:32 | LL | asm!("", out("f11") _, out("vs11") _); | ------------ ^^^^^^^^^^^^^ register `vs11` @@ -285,7 +285,7 @@ LL | asm!("", out("f11") _, out("vs11") _); | register `f11` error: register `vs12` conflicts with register `f12` - --> $DIR/bad-reg.rs:230:32 + --> $DIR/bad-reg.rs:232:32 | LL | asm!("", out("f12") _, out("vs12") _); | ------------ ^^^^^^^^^^^^^ register `vs12` @@ -293,7 +293,7 @@ LL | asm!("", out("f12") _, out("vs12") _); | register `f12` error: register `vs13` conflicts with register `f13` - --> $DIR/bad-reg.rs:232:32 + --> $DIR/bad-reg.rs:234:32 | LL | asm!("", out("f13") _, out("vs13") _); | ------------ ^^^^^^^^^^^^^ register `vs13` @@ -301,7 +301,7 @@ LL | asm!("", out("f13") _, out("vs13") _); | register `f13` error: register `vs14` conflicts with register `f14` - --> $DIR/bad-reg.rs:234:32 + --> $DIR/bad-reg.rs:236:32 | LL | asm!("", out("f14") _, out("vs14") _); | ------------ ^^^^^^^^^^^^^ register `vs14` @@ -309,7 +309,7 @@ LL | asm!("", out("f14") _, out("vs14") _); | register `f14` error: register `vs15` conflicts with register `f15` - --> $DIR/bad-reg.rs:236:32 + --> $DIR/bad-reg.rs:238:32 | LL | asm!("", out("f15") _, out("vs15") _); | ------------ ^^^^^^^^^^^^^ register `vs15` @@ -317,7 +317,7 @@ LL | asm!("", out("f15") _, out("vs15") _); | register `f15` error: register `vs16` conflicts with register `f16` - --> $DIR/bad-reg.rs:238:32 + --> $DIR/bad-reg.rs:240:32 | LL | asm!("", out("f16") _, out("vs16") _); | ------------ ^^^^^^^^^^^^^ register `vs16` @@ -325,7 +325,7 @@ LL | asm!("", out("f16") _, out("vs16") _); | register `f16` error: register `vs17` conflicts with register `f17` - --> $DIR/bad-reg.rs:240:32 + --> $DIR/bad-reg.rs:242:32 | LL | asm!("", out("f17") _, out("vs17") _); | ------------ ^^^^^^^^^^^^^ register `vs17` @@ -333,7 +333,7 @@ LL | asm!("", out("f17") _, out("vs17") _); | register `f17` error: register `vs18` conflicts with register `f18` - --> $DIR/bad-reg.rs:242:32 + --> $DIR/bad-reg.rs:244:32 | LL | asm!("", out("f18") _, out("vs18") _); | ------------ ^^^^^^^^^^^^^ register `vs18` @@ -341,7 +341,7 @@ LL | asm!("", out("f18") _, out("vs18") _); | register `f18` error: register `vs19` conflicts with register `f19` - --> $DIR/bad-reg.rs:244:32 + --> $DIR/bad-reg.rs:246:32 | LL | asm!("", out("f19") _, out("vs19") _); | ------------ ^^^^^^^^^^^^^ register `vs19` @@ -349,7 +349,7 @@ LL | asm!("", out("f19") _, out("vs19") _); | register `f19` error: register `vs20` conflicts with register `f20` - --> $DIR/bad-reg.rs:246:32 + --> $DIR/bad-reg.rs:248:32 | LL | asm!("", out("f20") _, out("vs20") _); | ------------ ^^^^^^^^^^^^^ register `vs20` @@ -357,7 +357,7 @@ LL | asm!("", out("f20") _, out("vs20") _); | register `f20` error: register `vs21` conflicts with register `f21` - --> $DIR/bad-reg.rs:248:32 + --> $DIR/bad-reg.rs:250:32 | LL | asm!("", out("f21") _, out("vs21") _); | ------------ ^^^^^^^^^^^^^ register `vs21` @@ -365,7 +365,7 @@ LL | asm!("", out("f21") _, out("vs21") _); | register `f21` error: register `vs22` conflicts with register `f22` - --> $DIR/bad-reg.rs:250:32 + --> $DIR/bad-reg.rs:252:32 | LL | asm!("", out("f22") _, out("vs22") _); | ------------ ^^^^^^^^^^^^^ register `vs22` @@ -373,7 +373,7 @@ LL | asm!("", out("f22") _, out("vs22") _); | register `f22` error: register `vs23` conflicts with register `f23` - --> $DIR/bad-reg.rs:252:32 + --> $DIR/bad-reg.rs:254:32 | LL | asm!("", out("f23") _, out("vs23") _); | ------------ ^^^^^^^^^^^^^ register `vs23` @@ -381,7 +381,7 @@ LL | asm!("", out("f23") _, out("vs23") _); | register `f23` error: register `vs24` conflicts with register `f24` - --> $DIR/bad-reg.rs:254:32 + --> $DIR/bad-reg.rs:256:32 | LL | asm!("", out("f24") _, out("vs24") _); | ------------ ^^^^^^^^^^^^^ register `vs24` @@ -389,7 +389,7 @@ LL | asm!("", out("f24") _, out("vs24") _); | register `f24` error: register `vs25` conflicts with register `f25` - --> $DIR/bad-reg.rs:256:32 + --> $DIR/bad-reg.rs:258:32 | LL | asm!("", out("f25") _, out("vs25") _); | ------------ ^^^^^^^^^^^^^ register `vs25` @@ -397,7 +397,7 @@ LL | asm!("", out("f25") _, out("vs25") _); | register `f25` error: register `vs26` conflicts with register `f26` - --> $DIR/bad-reg.rs:258:32 + --> $DIR/bad-reg.rs:260:32 | LL | asm!("", out("f26") _, out("vs26") _); | ------------ ^^^^^^^^^^^^^ register `vs26` @@ -405,7 +405,7 @@ LL | asm!("", out("f26") _, out("vs26") _); | register `f26` error: register `vs27` conflicts with register `f27` - --> $DIR/bad-reg.rs:260:32 + --> $DIR/bad-reg.rs:262:32 | LL | asm!("", out("f27") _, out("vs27") _); | ------------ ^^^^^^^^^^^^^ register `vs27` @@ -413,7 +413,7 @@ LL | asm!("", out("f27") _, out("vs27") _); | register `f27` error: register `vs28` conflicts with register `f28` - --> $DIR/bad-reg.rs:262:32 + --> $DIR/bad-reg.rs:264:32 | LL | asm!("", out("f28") _, out("vs28") _); | ------------ ^^^^^^^^^^^^^ register `vs28` @@ -421,7 +421,7 @@ LL | asm!("", out("f28") _, out("vs28") _); | register `f28` error: register `vs29` conflicts with register `f29` - --> $DIR/bad-reg.rs:264:32 + --> $DIR/bad-reg.rs:266:32 | LL | asm!("", out("f29") _, out("vs29") _); | ------------ ^^^^^^^^^^^^^ register `vs29` @@ -429,7 +429,7 @@ LL | asm!("", out("f29") _, out("vs29") _); | register `f29` error: register `vs30` conflicts with register `f30` - --> $DIR/bad-reg.rs:266:32 + --> $DIR/bad-reg.rs:268:32 | LL | asm!("", out("f30") _, out("vs30") _); | ------------ ^^^^^^^^^^^^^ register `vs30` @@ -437,7 +437,7 @@ LL | asm!("", out("f30") _, out("vs30") _); | register `f30` error: register `vs31` conflicts with register `f31` - --> $DIR/bad-reg.rs:268:32 + --> $DIR/bad-reg.rs:270:32 | LL | asm!("", out("f31") _, out("vs31") _); | ------------ ^^^^^^^^^^^^^ register `vs31` @@ -445,7 +445,7 @@ LL | asm!("", out("f31") _, out("vs31") _); | register `f31` error: register `v0` conflicts with register `vs32` - --> $DIR/bad-reg.rs:270:33 + --> $DIR/bad-reg.rs:272:33 | LL | asm!("", out("vs32") _, out("v0") _); | ------------- ^^^^^^^^^^^ register `v0` @@ -453,7 +453,7 @@ LL | asm!("", out("vs32") _, out("v0") _); | register `vs32` error: register `v1` conflicts with register `vs33` - --> $DIR/bad-reg.rs:272:33 + --> $DIR/bad-reg.rs:274:33 | LL | asm!("", out("vs33") _, out("v1") _); | ------------- ^^^^^^^^^^^ register `v1` @@ -461,7 +461,7 @@ LL | asm!("", out("vs33") _, out("v1") _); | register `vs33` error: register `v2` conflicts with register `vs34` - --> $DIR/bad-reg.rs:274:33 + --> $DIR/bad-reg.rs:276:33 | LL | asm!("", out("vs34") _, out("v2") _); | ------------- ^^^^^^^^^^^ register `v2` @@ -469,7 +469,7 @@ LL | asm!("", out("vs34") _, out("v2") _); | register `vs34` error: register `v3` conflicts with register `vs35` - --> $DIR/bad-reg.rs:276:33 + --> $DIR/bad-reg.rs:278:33 | LL | asm!("", out("vs35") _, out("v3") _); | ------------- ^^^^^^^^^^^ register `v3` @@ -477,7 +477,7 @@ LL | asm!("", out("vs35") _, out("v3") _); | register `vs35` error: register `v4` conflicts with register `vs36` - --> $DIR/bad-reg.rs:278:33 + --> $DIR/bad-reg.rs:280:33 | LL | asm!("", out("vs36") _, out("v4") _); | ------------- ^^^^^^^^^^^ register `v4` @@ -485,7 +485,7 @@ LL | asm!("", out("vs36") _, out("v4") _); | register `vs36` error: register `v5` conflicts with register `vs37` - --> $DIR/bad-reg.rs:280:33 + --> $DIR/bad-reg.rs:282:33 | LL | asm!("", out("vs37") _, out("v5") _); | ------------- ^^^^^^^^^^^ register `v5` @@ -493,7 +493,7 @@ LL | asm!("", out("vs37") _, out("v5") _); | register `vs37` error: register `v6` conflicts with register `vs38` - --> $DIR/bad-reg.rs:282:33 + --> $DIR/bad-reg.rs:284:33 | LL | asm!("", out("vs38") _, out("v6") _); | ------------- ^^^^^^^^^^^ register `v6` @@ -501,7 +501,7 @@ LL | asm!("", out("vs38") _, out("v6") _); | register `vs38` error: register `v7` conflicts with register `vs39` - --> $DIR/bad-reg.rs:284:33 + --> $DIR/bad-reg.rs:286:33 | LL | asm!("", out("vs39") _, out("v7") _); | ------------- ^^^^^^^^^^^ register `v7` @@ -509,7 +509,7 @@ LL | asm!("", out("vs39") _, out("v7") _); | register `vs39` error: register `v8` conflicts with register `vs40` - --> $DIR/bad-reg.rs:286:33 + --> $DIR/bad-reg.rs:288:33 | LL | asm!("", out("vs40") _, out("v8") _); | ------------- ^^^^^^^^^^^ register `v8` @@ -517,7 +517,7 @@ LL | asm!("", out("vs40") _, out("v8") _); | register `vs40` error: register `v9` conflicts with register `vs41` - --> $DIR/bad-reg.rs:288:33 + --> $DIR/bad-reg.rs:290:33 | LL | asm!("", out("vs41") _, out("v9") _); | ------------- ^^^^^^^^^^^ register `v9` @@ -525,7 +525,7 @@ LL | asm!("", out("vs41") _, out("v9") _); | register `vs41` error: register `v10` conflicts with register `vs42` - --> $DIR/bad-reg.rs:290:33 + --> $DIR/bad-reg.rs:292:33 | LL | asm!("", out("vs42") _, out("v10") _); | ------------- ^^^^^^^^^^^^ register `v10` @@ -533,7 +533,7 @@ LL | asm!("", out("vs42") _, out("v10") _); | register `vs42` error: register `v11` conflicts with register `vs43` - --> $DIR/bad-reg.rs:292:33 + --> $DIR/bad-reg.rs:294:33 | LL | asm!("", out("vs43") _, out("v11") _); | ------------- ^^^^^^^^^^^^ register `v11` @@ -541,7 +541,7 @@ LL | asm!("", out("vs43") _, out("v11") _); | register `vs43` error: register `v12` conflicts with register `vs44` - --> $DIR/bad-reg.rs:294:33 + --> $DIR/bad-reg.rs:296:33 | LL | asm!("", out("vs44") _, out("v12") _); | ------------- ^^^^^^^^^^^^ register `v12` @@ -549,7 +549,7 @@ LL | asm!("", out("vs44") _, out("v12") _); | register `vs44` error: register `v13` conflicts with register `vs45` - --> $DIR/bad-reg.rs:296:33 + --> $DIR/bad-reg.rs:298:33 | LL | asm!("", out("vs45") _, out("v13") _); | ------------- ^^^^^^^^^^^^ register `v13` @@ -557,7 +557,7 @@ LL | asm!("", out("vs45") _, out("v13") _); | register `vs45` error: register `v14` conflicts with register `vs46` - --> $DIR/bad-reg.rs:298:33 + --> $DIR/bad-reg.rs:300:33 | LL | asm!("", out("vs46") _, out("v14") _); | ------------- ^^^^^^^^^^^^ register `v14` @@ -565,7 +565,7 @@ LL | asm!("", out("vs46") _, out("v14") _); | register `vs46` error: register `v15` conflicts with register `vs47` - --> $DIR/bad-reg.rs:300:33 + --> $DIR/bad-reg.rs:302:33 | LL | asm!("", out("vs47") _, out("v15") _); | ------------- ^^^^^^^^^^^^ register `v15` @@ -573,7 +573,7 @@ LL | asm!("", out("vs47") _, out("v15") _); | register `vs47` error: register `v16` conflicts with register `vs48` - --> $DIR/bad-reg.rs:302:33 + --> $DIR/bad-reg.rs:304:33 | LL | asm!("", out("vs48") _, out("v16") _); | ------------- ^^^^^^^^^^^^ register `v16` @@ -581,7 +581,7 @@ LL | asm!("", out("vs48") _, out("v16") _); | register `vs48` error: register `v17` conflicts with register `vs49` - --> $DIR/bad-reg.rs:304:33 + --> $DIR/bad-reg.rs:306:33 | LL | asm!("", out("vs49") _, out("v17") _); | ------------- ^^^^^^^^^^^^ register `v17` @@ -589,7 +589,7 @@ LL | asm!("", out("vs49") _, out("v17") _); | register `vs49` error: register `v18` conflicts with register `vs50` - --> $DIR/bad-reg.rs:306:33 + --> $DIR/bad-reg.rs:308:33 | LL | asm!("", out("vs50") _, out("v18") _); | ------------- ^^^^^^^^^^^^ register `v18` @@ -597,7 +597,7 @@ LL | asm!("", out("vs50") _, out("v18") _); | register `vs50` error: register `v19` conflicts with register `vs51` - --> $DIR/bad-reg.rs:308:33 + --> $DIR/bad-reg.rs:310:33 | LL | asm!("", out("vs51") _, out("v19") _); | ------------- ^^^^^^^^^^^^ register `v19` @@ -605,7 +605,7 @@ LL | asm!("", out("vs51") _, out("v19") _); | register `vs51` error: register `v20` conflicts with register `vs52` - --> $DIR/bad-reg.rs:310:33 + --> $DIR/bad-reg.rs:312:33 | LL | asm!("", out("vs52") _, out("v20") _); | ------------- ^^^^^^^^^^^^ register `v20` @@ -613,7 +613,7 @@ LL | asm!("", out("vs52") _, out("v20") _); | register `vs52` error: register `v21` conflicts with register `vs53` - --> $DIR/bad-reg.rs:312:33 + --> $DIR/bad-reg.rs:314:33 | LL | asm!("", out("vs53") _, out("v21") _); | ------------- ^^^^^^^^^^^^ register `v21` @@ -621,7 +621,7 @@ LL | asm!("", out("vs53") _, out("v21") _); | register `vs53` error: register `v22` conflicts with register `vs54` - --> $DIR/bad-reg.rs:314:33 + --> $DIR/bad-reg.rs:316:33 | LL | asm!("", out("vs54") _, out("v22") _); | ------------- ^^^^^^^^^^^^ register `v22` @@ -629,7 +629,7 @@ LL | asm!("", out("vs54") _, out("v22") _); | register `vs54` error: register `v23` conflicts with register `vs55` - --> $DIR/bad-reg.rs:316:33 + --> $DIR/bad-reg.rs:318:33 | LL | asm!("", out("vs55") _, out("v23") _); | ------------- ^^^^^^^^^^^^ register `v23` @@ -637,7 +637,7 @@ LL | asm!("", out("vs55") _, out("v23") _); | register `vs55` error: register `v24` conflicts with register `vs56` - --> $DIR/bad-reg.rs:318:33 + --> $DIR/bad-reg.rs:320:33 | LL | asm!("", out("vs56") _, out("v24") _); | ------------- ^^^^^^^^^^^^ register `v24` @@ -645,7 +645,7 @@ LL | asm!("", out("vs56") _, out("v24") _); | register `vs56` error: register `v25` conflicts with register `vs57` - --> $DIR/bad-reg.rs:320:33 + --> $DIR/bad-reg.rs:322:33 | LL | asm!("", out("vs57") _, out("v25") _); | ------------- ^^^^^^^^^^^^ register `v25` @@ -653,7 +653,7 @@ LL | asm!("", out("vs57") _, out("v25") _); | register `vs57` error: register `v26` conflicts with register `vs58` - --> $DIR/bad-reg.rs:322:33 + --> $DIR/bad-reg.rs:324:33 | LL | asm!("", out("vs58") _, out("v26") _); | ------------- ^^^^^^^^^^^^ register `v26` @@ -661,7 +661,7 @@ LL | asm!("", out("vs58") _, out("v26") _); | register `vs58` error: register `v27` conflicts with register `vs59` - --> $DIR/bad-reg.rs:324:33 + --> $DIR/bad-reg.rs:326:33 | LL | asm!("", out("vs59") _, out("v27") _); | ------------- ^^^^^^^^^^^^ register `v27` @@ -669,7 +669,7 @@ LL | asm!("", out("vs59") _, out("v27") _); | register `vs59` error: register `v28` conflicts with register `vs60` - --> $DIR/bad-reg.rs:326:33 + --> $DIR/bad-reg.rs:328:33 | LL | asm!("", out("vs60") _, out("v28") _); | ------------- ^^^^^^^^^^^^ register `v28` @@ -677,7 +677,7 @@ LL | asm!("", out("vs60") _, out("v28") _); | register `vs60` error: register `v29` conflicts with register `vs61` - --> $DIR/bad-reg.rs:328:33 + --> $DIR/bad-reg.rs:330:33 | LL | asm!("", out("vs61") _, out("v29") _); | ------------- ^^^^^^^^^^^^ register `v29` @@ -685,7 +685,7 @@ LL | asm!("", out("vs61") _, out("v29") _); | register `vs61` error: register `v30` conflicts with register `vs62` - --> $DIR/bad-reg.rs:330:33 + --> $DIR/bad-reg.rs:332:33 | LL | asm!("", out("vs62") _, out("v30") _); | ------------- ^^^^^^^^^^^^ register `v30` @@ -693,21 +693,27 @@ LL | asm!("", out("vs62") _, out("v30") _); | register `vs62` error: register `v31` conflicts with register `vs63` - --> $DIR/bad-reg.rs:332:33 + --> $DIR/bad-reg.rs:334:33 | LL | asm!("", out("vs63") _, out("v31") _); | ------------- ^^^^^^^^^^^^ register `v31` | | | register `vs63` +error: register class `spe_acc` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:340:26 + | +LL | asm!("/* {} */", out(spe_acc) _); + | ^^^^^^^^^^^^^^ + error: cannot use register `r13`: r13 is a reserved register on this target - --> $DIR/bad-reg.rs:40:18 + --> $DIR/bad-reg.rs:42:18 | LL | asm!("", out("r13") _); | ^^^^^^^^^^^^ error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:63:27 + --> $DIR/bad-reg.rs:65:27 | LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available | ^ @@ -715,7 +721,7 @@ LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:66:28 + --> $DIR/bad-reg.rs:68:28 | LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available | ^ @@ -723,7 +729,7 @@ LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:74:35 + --> $DIR/bad-reg.rs:76:35 | LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available | ^ @@ -731,7 +737,7 @@ LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:104:28 + --> $DIR/bad-reg.rs:106:28 | LL | asm!("", in("vs0") x); // FIXME: should be ok if vsx is available | ^ @@ -739,7 +745,7 @@ LL | asm!("", in("vs0") x); // FIXME: should be ok if vsx is available = note: register class `vsreg` supports these types: f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:107:29 + --> $DIR/bad-reg.rs:109:29 | LL | asm!("", out("vs0") x); // FIXME: should be ok if vsx is available | ^ @@ -747,7 +753,7 @@ LL | asm!("", out("vs0") x); // FIXME: should be ok if vsx is available = note: register class `vsreg` supports these types: f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:114:36 + --> $DIR/bad-reg.rs:116:36 | LL | asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is available | ^ @@ -755,7 +761,7 @@ LL | asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is ava = note: register class `vsreg` supports these types: f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:137:27 + --> $DIR/bad-reg.rs:139:27 | LL | asm!("", in("cr") x); | ^ @@ -763,7 +769,7 @@ LL | asm!("", in("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:140:28 + --> $DIR/bad-reg.rs:142:28 | LL | asm!("", out("cr") x); | ^ @@ -771,7 +777,7 @@ LL | asm!("", out("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:143:33 + --> $DIR/bad-reg.rs:145:33 | LL | asm!("/* {} */", in(cr) x); | ^ @@ -779,7 +785,7 @@ LL | asm!("/* {} */", in(cr) x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:150:28 + --> $DIR/bad-reg.rs:152:28 | LL | asm!("", in("ctr") x); | ^ @@ -787,7 +793,7 @@ LL | asm!("", in("ctr") x); = note: register class `ctr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:153:29 + --> $DIR/bad-reg.rs:155:29 | LL | asm!("", out("ctr") x); | ^ @@ -795,7 +801,7 @@ LL | asm!("", out("ctr") x); = note: register class `ctr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:156:34 + --> $DIR/bad-reg.rs:158:34 | LL | asm!("/* {} */", in(ctr) x); | ^ @@ -803,7 +809,7 @@ LL | asm!("/* {} */", in(ctr) x); = note: register class `ctr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:163:27 + --> $DIR/bad-reg.rs:165:27 | LL | asm!("", in("lr") x); | ^ @@ -811,7 +817,7 @@ LL | asm!("", in("lr") x); = note: register class `lr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:166:28 + --> $DIR/bad-reg.rs:168:28 | LL | asm!("", out("lr") x); | ^ @@ -819,7 +825,7 @@ LL | asm!("", out("lr") x); = note: register class `lr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:169:33 + --> $DIR/bad-reg.rs:171:33 | LL | asm!("/* {} */", in(lr) x); | ^ @@ -827,7 +833,7 @@ LL | asm!("/* {} */", in(lr) x); = note: register class `lr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:176:28 + --> $DIR/bad-reg.rs:178:28 | LL | asm!("", in("xer") x); | ^ @@ -835,7 +841,7 @@ LL | asm!("", in("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:179:29 + --> $DIR/bad-reg.rs:181:29 | LL | asm!("", out("xer") x); | ^ @@ -843,12 +849,18 @@ LL | asm!("", out("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:182:34 + --> $DIR/bad-reg.rs:184:34 | LL | asm!("/* {} */", in(xer) x); | ^ | = note: register class `xer` supports these types: -error: aborting due to 112 previous errors +error: cannot use register `spe_acc`: spe_acc is only available on spe targets + --> $DIR/bad-reg.rs:338:18 + | +LL | asm!("", out("spe_acc") _); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 114 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.powerpcspe.stderr b/tests/ui/asm/powerpc/bad-reg.powerpcspe.stderr new file mode 100644 index 000000000000..2b4657bf358e --- /dev/null +++ b/tests/ui/asm/powerpc/bad-reg.powerpcspe.stderr @@ -0,0 +1,938 @@ +error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:38:18 + | +LL | asm!("", out("sp") _); + | ^^^^^^^^^^^ + +error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:40:18 + | +LL | asm!("", out("r2") _); + | ^^^^^^^^^^^ + +error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:46:18 + | +LL | asm!("", out("r30") _); + | ^^^^^^^^^^^^ + +error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:48:18 + | +LL | asm!("", out("fp") _); + | ^^^^^^^^^^^ + +error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:50:18 + | +LL | asm!("", out("vrsave") _); + | ^^^^^^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:139:18 + | +LL | asm!("", in("cr") x); + | ^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:142:18 + | +LL | asm!("", out("cr") x); + | ^^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:145:26 + | +LL | asm!("/* {} */", in(cr) x); + | ^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:148:26 + | +LL | asm!("/* {} */", out(cr) _); + | ^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:152:18 + | +LL | asm!("", in("ctr") x); + | ^^^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:155:18 + | +LL | asm!("", out("ctr") x); + | ^^^^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:158:26 + | +LL | asm!("/* {} */", in(ctr) x); + | ^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:161:26 + | +LL | asm!("/* {} */", out(ctr) _); + | ^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:165:18 + | +LL | asm!("", in("lr") x); + | ^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:168:18 + | +LL | asm!("", out("lr") x); + | ^^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:171:26 + | +LL | asm!("/* {} */", in(lr) x); + | ^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:174:26 + | +LL | asm!("/* {} */", out(lr) _); + | ^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:178:18 + | +LL | asm!("", in("xer") x); + | ^^^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:181:18 + | +LL | asm!("", out("xer") x); + | ^^^^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:184:26 + | +LL | asm!("/* {} */", in(xer) x); + | ^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:187:26 + | +LL | asm!("/* {} */", out(xer) _); + | ^^^^^^^^^^ + +error: register `cr0` conflicts with register `cr` + --> $DIR/bad-reg.rs:191:31 + | +LL | asm!("", out("cr") _, out("cr0") _); + | ----------- ^^^^^^^^^^^^ register `cr0` + | | + | register `cr` + +error: register `cr1` conflicts with register `cr` + --> $DIR/bad-reg.rs:193:31 + | +LL | asm!("", out("cr") _, out("cr1") _); + | ----------- ^^^^^^^^^^^^ register `cr1` + | | + | register `cr` + +error: register `cr2` conflicts with register `cr` + --> $DIR/bad-reg.rs:195:31 + | +LL | asm!("", out("cr") _, out("cr2") _); + | ----------- ^^^^^^^^^^^^ register `cr2` + | | + | register `cr` + +error: register `cr3` conflicts with register `cr` + --> $DIR/bad-reg.rs:197:31 + | +LL | asm!("", out("cr") _, out("cr3") _); + | ----------- ^^^^^^^^^^^^ register `cr3` + | | + | register `cr` + +error: register `cr4` conflicts with register `cr` + --> $DIR/bad-reg.rs:199:31 + | +LL | asm!("", out("cr") _, out("cr4") _); + | ----------- ^^^^^^^^^^^^ register `cr4` + | | + | register `cr` + +error: register `cr5` conflicts with register `cr` + --> $DIR/bad-reg.rs:201:31 + | +LL | asm!("", out("cr") _, out("cr5") _); + | ----------- ^^^^^^^^^^^^ register `cr5` + | | + | register `cr` + +error: register `cr6` conflicts with register `cr` + --> $DIR/bad-reg.rs:203:31 + | +LL | asm!("", out("cr") _, out("cr6") _); + | ----------- ^^^^^^^^^^^^ register `cr6` + | | + | register `cr` + +error: register `cr7` conflicts with register `cr` + --> $DIR/bad-reg.rs:205:31 + | +LL | asm!("", out("cr") _, out("cr7") _); + | ----------- ^^^^^^^^^^^^ register `cr7` + | | + | register `cr` + +error: register `vs0` conflicts with register `f0` + --> $DIR/bad-reg.rs:208:31 + | +LL | asm!("", out("f0") _, out("vs0") _); + | ----------- ^^^^^^^^^^^^ register `vs0` + | | + | register `f0` + +error: register `vs1` conflicts with register `f1` + --> $DIR/bad-reg.rs:210:31 + | +LL | asm!("", out("f1") _, out("vs1") _); + | ----------- ^^^^^^^^^^^^ register `vs1` + | | + | register `f1` + +error: register `vs2` conflicts with register `f2` + --> $DIR/bad-reg.rs:212:31 + | +LL | asm!("", out("f2") _, out("vs2") _); + | ----------- ^^^^^^^^^^^^ register `vs2` + | | + | register `f2` + +error: register `vs3` conflicts with register `f3` + --> $DIR/bad-reg.rs:214:31 + | +LL | asm!("", out("f3") _, out("vs3") _); + | ----------- ^^^^^^^^^^^^ register `vs3` + | | + | register `f3` + +error: register `vs4` conflicts with register `f4` + --> $DIR/bad-reg.rs:216:31 + | +LL | asm!("", out("f4") _, out("vs4") _); + | ----------- ^^^^^^^^^^^^ register `vs4` + | | + | register `f4` + +error: register `vs5` conflicts with register `f5` + --> $DIR/bad-reg.rs:218:31 + | +LL | asm!("", out("f5") _, out("vs5") _); + | ----------- ^^^^^^^^^^^^ register `vs5` + | | + | register `f5` + +error: register `vs6` conflicts with register `f6` + --> $DIR/bad-reg.rs:220:31 + | +LL | asm!("", out("f6") _, out("vs6") _); + | ----------- ^^^^^^^^^^^^ register `vs6` + | | + | register `f6` + +error: register `vs7` conflicts with register `f7` + --> $DIR/bad-reg.rs:222:31 + | +LL | asm!("", out("f7") _, out("vs7") _); + | ----------- ^^^^^^^^^^^^ register `vs7` + | | + | register `f7` + +error: register `vs8` conflicts with register `f8` + --> $DIR/bad-reg.rs:224:31 + | +LL | asm!("", out("f8") _, out("vs8") _); + | ----------- ^^^^^^^^^^^^ register `vs8` + | | + | register `f8` + +error: register `vs9` conflicts with register `f9` + --> $DIR/bad-reg.rs:226:31 + | +LL | asm!("", out("f9") _, out("vs9") _); + | ----------- ^^^^^^^^^^^^ register `vs9` + | | + | register `f9` + +error: register `vs10` conflicts with register `f10` + --> $DIR/bad-reg.rs:228:32 + | +LL | asm!("", out("f10") _, out("vs10") _); + | ------------ ^^^^^^^^^^^^^ register `vs10` + | | + | register `f10` + +error: register `vs11` conflicts with register `f11` + --> $DIR/bad-reg.rs:230:32 + | +LL | asm!("", out("f11") _, out("vs11") _); + | ------------ ^^^^^^^^^^^^^ register `vs11` + | | + | register `f11` + +error: register `vs12` conflicts with register `f12` + --> $DIR/bad-reg.rs:232:32 + | +LL | asm!("", out("f12") _, out("vs12") _); + | ------------ ^^^^^^^^^^^^^ register `vs12` + | | + | register `f12` + +error: register `vs13` conflicts with register `f13` + --> $DIR/bad-reg.rs:234:32 + | +LL | asm!("", out("f13") _, out("vs13") _); + | ------------ ^^^^^^^^^^^^^ register `vs13` + | | + | register `f13` + +error: register `vs14` conflicts with register `f14` + --> $DIR/bad-reg.rs:236:32 + | +LL | asm!("", out("f14") _, out("vs14") _); + | ------------ ^^^^^^^^^^^^^ register `vs14` + | | + | register `f14` + +error: register `vs15` conflicts with register `f15` + --> $DIR/bad-reg.rs:238:32 + | +LL | asm!("", out("f15") _, out("vs15") _); + | ------------ ^^^^^^^^^^^^^ register `vs15` + | | + | register `f15` + +error: register `vs16` conflicts with register `f16` + --> $DIR/bad-reg.rs:240:32 + | +LL | asm!("", out("f16") _, out("vs16") _); + | ------------ ^^^^^^^^^^^^^ register `vs16` + | | + | register `f16` + +error: register `vs17` conflicts with register `f17` + --> $DIR/bad-reg.rs:242:32 + | +LL | asm!("", out("f17") _, out("vs17") _); + | ------------ ^^^^^^^^^^^^^ register `vs17` + | | + | register `f17` + +error: register `vs18` conflicts with register `f18` + --> $DIR/bad-reg.rs:244:32 + | +LL | asm!("", out("f18") _, out("vs18") _); + | ------------ ^^^^^^^^^^^^^ register `vs18` + | | + | register `f18` + +error: register `vs19` conflicts with register `f19` + --> $DIR/bad-reg.rs:246:32 + | +LL | asm!("", out("f19") _, out("vs19") _); + | ------------ ^^^^^^^^^^^^^ register `vs19` + | | + | register `f19` + +error: register `vs20` conflicts with register `f20` + --> $DIR/bad-reg.rs:248:32 + | +LL | asm!("", out("f20") _, out("vs20") _); + | ------------ ^^^^^^^^^^^^^ register `vs20` + | | + | register `f20` + +error: register `vs21` conflicts with register `f21` + --> $DIR/bad-reg.rs:250:32 + | +LL | asm!("", out("f21") _, out("vs21") _); + | ------------ ^^^^^^^^^^^^^ register `vs21` + | | + | register `f21` + +error: register `vs22` conflicts with register `f22` + --> $DIR/bad-reg.rs:252:32 + | +LL | asm!("", out("f22") _, out("vs22") _); + | ------------ ^^^^^^^^^^^^^ register `vs22` + | | + | register `f22` + +error: register `vs23` conflicts with register `f23` + --> $DIR/bad-reg.rs:254:32 + | +LL | asm!("", out("f23") _, out("vs23") _); + | ------------ ^^^^^^^^^^^^^ register `vs23` + | | + | register `f23` + +error: register `vs24` conflicts with register `f24` + --> $DIR/bad-reg.rs:256:32 + | +LL | asm!("", out("f24") _, out("vs24") _); + | ------------ ^^^^^^^^^^^^^ register `vs24` + | | + | register `f24` + +error: register `vs25` conflicts with register `f25` + --> $DIR/bad-reg.rs:258:32 + | +LL | asm!("", out("f25") _, out("vs25") _); + | ------------ ^^^^^^^^^^^^^ register `vs25` + | | + | register `f25` + +error: register `vs26` conflicts with register `f26` + --> $DIR/bad-reg.rs:260:32 + | +LL | asm!("", out("f26") _, out("vs26") _); + | ------------ ^^^^^^^^^^^^^ register `vs26` + | | + | register `f26` + +error: register `vs27` conflicts with register `f27` + --> $DIR/bad-reg.rs:262:32 + | +LL | asm!("", out("f27") _, out("vs27") _); + | ------------ ^^^^^^^^^^^^^ register `vs27` + | | + | register `f27` + +error: register `vs28` conflicts with register `f28` + --> $DIR/bad-reg.rs:264:32 + | +LL | asm!("", out("f28") _, out("vs28") _); + | ------------ ^^^^^^^^^^^^^ register `vs28` + | | + | register `f28` + +error: register `vs29` conflicts with register `f29` + --> $DIR/bad-reg.rs:266:32 + | +LL | asm!("", out("f29") _, out("vs29") _); + | ------------ ^^^^^^^^^^^^^ register `vs29` + | | + | register `f29` + +error: register `vs30` conflicts with register `f30` + --> $DIR/bad-reg.rs:268:32 + | +LL | asm!("", out("f30") _, out("vs30") _); + | ------------ ^^^^^^^^^^^^^ register `vs30` + | | + | register `f30` + +error: register `vs31` conflicts with register `f31` + --> $DIR/bad-reg.rs:270:32 + | +LL | asm!("", out("f31") _, out("vs31") _); + | ------------ ^^^^^^^^^^^^^ register `vs31` + | | + | register `f31` + +error: register `v0` conflicts with register `vs32` + --> $DIR/bad-reg.rs:272:33 + | +LL | asm!("", out("vs32") _, out("v0") _); + | ------------- ^^^^^^^^^^^ register `v0` + | | + | register `vs32` + +error: register `v1` conflicts with register `vs33` + --> $DIR/bad-reg.rs:274:33 + | +LL | asm!("", out("vs33") _, out("v1") _); + | ------------- ^^^^^^^^^^^ register `v1` + | | + | register `vs33` + +error: register `v2` conflicts with register `vs34` + --> $DIR/bad-reg.rs:276:33 + | +LL | asm!("", out("vs34") _, out("v2") _); + | ------------- ^^^^^^^^^^^ register `v2` + | | + | register `vs34` + +error: register `v3` conflicts with register `vs35` + --> $DIR/bad-reg.rs:278:33 + | +LL | asm!("", out("vs35") _, out("v3") _); + | ------------- ^^^^^^^^^^^ register `v3` + | | + | register `vs35` + +error: register `v4` conflicts with register `vs36` + --> $DIR/bad-reg.rs:280:33 + | +LL | asm!("", out("vs36") _, out("v4") _); + | ------------- ^^^^^^^^^^^ register `v4` + | | + | register `vs36` + +error: register `v5` conflicts with register `vs37` + --> $DIR/bad-reg.rs:282:33 + | +LL | asm!("", out("vs37") _, out("v5") _); + | ------------- ^^^^^^^^^^^ register `v5` + | | + | register `vs37` + +error: register `v6` conflicts with register `vs38` + --> $DIR/bad-reg.rs:284:33 + | +LL | asm!("", out("vs38") _, out("v6") _); + | ------------- ^^^^^^^^^^^ register `v6` + | | + | register `vs38` + +error: register `v7` conflicts with register `vs39` + --> $DIR/bad-reg.rs:286:33 + | +LL | asm!("", out("vs39") _, out("v7") _); + | ------------- ^^^^^^^^^^^ register `v7` + | | + | register `vs39` + +error: register `v8` conflicts with register `vs40` + --> $DIR/bad-reg.rs:288:33 + | +LL | asm!("", out("vs40") _, out("v8") _); + | ------------- ^^^^^^^^^^^ register `v8` + | | + | register `vs40` + +error: register `v9` conflicts with register `vs41` + --> $DIR/bad-reg.rs:290:33 + | +LL | asm!("", out("vs41") _, out("v9") _); + | ------------- ^^^^^^^^^^^ register `v9` + | | + | register `vs41` + +error: register `v10` conflicts with register `vs42` + --> $DIR/bad-reg.rs:292:33 + | +LL | asm!("", out("vs42") _, out("v10") _); + | ------------- ^^^^^^^^^^^^ register `v10` + | | + | register `vs42` + +error: register `v11` conflicts with register `vs43` + --> $DIR/bad-reg.rs:294:33 + | +LL | asm!("", out("vs43") _, out("v11") _); + | ------------- ^^^^^^^^^^^^ register `v11` + | | + | register `vs43` + +error: register `v12` conflicts with register `vs44` + --> $DIR/bad-reg.rs:296:33 + | +LL | asm!("", out("vs44") _, out("v12") _); + | ------------- ^^^^^^^^^^^^ register `v12` + | | + | register `vs44` + +error: register `v13` conflicts with register `vs45` + --> $DIR/bad-reg.rs:298:33 + | +LL | asm!("", out("vs45") _, out("v13") _); + | ------------- ^^^^^^^^^^^^ register `v13` + | | + | register `vs45` + +error: register `v14` conflicts with register `vs46` + --> $DIR/bad-reg.rs:300:33 + | +LL | asm!("", out("vs46") _, out("v14") _); + | ------------- ^^^^^^^^^^^^ register `v14` + | | + | register `vs46` + +error: register `v15` conflicts with register `vs47` + --> $DIR/bad-reg.rs:302:33 + | +LL | asm!("", out("vs47") _, out("v15") _); + | ------------- ^^^^^^^^^^^^ register `v15` + | | + | register `vs47` + +error: register `v16` conflicts with register `vs48` + --> $DIR/bad-reg.rs:304:33 + | +LL | asm!("", out("vs48") _, out("v16") _); + | ------------- ^^^^^^^^^^^^ register `v16` + | | + | register `vs48` + +error: register `v17` conflicts with register `vs49` + --> $DIR/bad-reg.rs:306:33 + | +LL | asm!("", out("vs49") _, out("v17") _); + | ------------- ^^^^^^^^^^^^ register `v17` + | | + | register `vs49` + +error: register `v18` conflicts with register `vs50` + --> $DIR/bad-reg.rs:308:33 + | +LL | asm!("", out("vs50") _, out("v18") _); + | ------------- ^^^^^^^^^^^^ register `v18` + | | + | register `vs50` + +error: register `v19` conflicts with register `vs51` + --> $DIR/bad-reg.rs:310:33 + | +LL | asm!("", out("vs51") _, out("v19") _); + | ------------- ^^^^^^^^^^^^ register `v19` + | | + | register `vs51` + +error: register `v20` conflicts with register `vs52` + --> $DIR/bad-reg.rs:312:33 + | +LL | asm!("", out("vs52") _, out("v20") _); + | ------------- ^^^^^^^^^^^^ register `v20` + | | + | register `vs52` + +error: register `v21` conflicts with register `vs53` + --> $DIR/bad-reg.rs:314:33 + | +LL | asm!("", out("vs53") _, out("v21") _); + | ------------- ^^^^^^^^^^^^ register `v21` + | | + | register `vs53` + +error: register `v22` conflicts with register `vs54` + --> $DIR/bad-reg.rs:316:33 + | +LL | asm!("", out("vs54") _, out("v22") _); + | ------------- ^^^^^^^^^^^^ register `v22` + | | + | register `vs54` + +error: register `v23` conflicts with register `vs55` + --> $DIR/bad-reg.rs:318:33 + | +LL | asm!("", out("vs55") _, out("v23") _); + | ------------- ^^^^^^^^^^^^ register `v23` + | | + | register `vs55` + +error: register `v24` conflicts with register `vs56` + --> $DIR/bad-reg.rs:320:33 + | +LL | asm!("", out("vs56") _, out("v24") _); + | ------------- ^^^^^^^^^^^^ register `v24` + | | + | register `vs56` + +error: register `v25` conflicts with register `vs57` + --> $DIR/bad-reg.rs:322:33 + | +LL | asm!("", out("vs57") _, out("v25") _); + | ------------- ^^^^^^^^^^^^ register `v25` + | | + | register `vs57` + +error: register `v26` conflicts with register `vs58` + --> $DIR/bad-reg.rs:324:33 + | +LL | asm!("", out("vs58") _, out("v26") _); + | ------------- ^^^^^^^^^^^^ register `v26` + | | + | register `vs58` + +error: register `v27` conflicts with register `vs59` + --> $DIR/bad-reg.rs:326:33 + | +LL | asm!("", out("vs59") _, out("v27") _); + | ------------- ^^^^^^^^^^^^ register `v27` + | | + | register `vs59` + +error: register `v28` conflicts with register `vs60` + --> $DIR/bad-reg.rs:328:33 + | +LL | asm!("", out("vs60") _, out("v28") _); + | ------------- ^^^^^^^^^^^^ register `v28` + | | + | register `vs60` + +error: register `v29` conflicts with register `vs61` + --> $DIR/bad-reg.rs:330:33 + | +LL | asm!("", out("vs61") _, out("v29") _); + | ------------- ^^^^^^^^^^^^ register `v29` + | | + | register `vs61` + +error: register `v30` conflicts with register `vs62` + --> $DIR/bad-reg.rs:332:33 + | +LL | asm!("", out("vs62") _, out("v30") _); + | ------------- ^^^^^^^^^^^^ register `v30` + | | + | register `vs62` + +error: register `v31` conflicts with register `vs63` + --> $DIR/bad-reg.rs:334:33 + | +LL | asm!("", out("vs63") _, out("v31") _); + | ------------- ^^^^^^^^^^^^ register `v31` + | | + | register `vs63` + +error: register class `spe_acc` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:340:26 + | +LL | asm!("/* {} */", out(spe_acc) _); + | ^^^^^^^^^^^^^^ + +error: cannot use register `r13`: r13 is a reserved register on this target + --> $DIR/bad-reg.rs:42:18 + | +LL | asm!("", out("r13") _); + | ^^^^^^^^^^^^ + +error: cannot use register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:44:18 + | +LL | asm!("", out("r29") _); + | ^^^^^^^^^^^^ + +error: register class `vreg` requires at least one of the following target features: altivec, vsx + --> $DIR/bad-reg.rs:55:18 + | +LL | asm!("", in("v0") v32x4); // requires altivec + | ^^^^^^^^^^^^^^ + +error: register class `vreg` requires at least one of the following target features: altivec, vsx + --> $DIR/bad-reg.rs:57:18 + | +LL | asm!("", out("v0") v32x4); // requires altivec + | ^^^^^^^^^^^^^^^ + +error: register class `vreg` requires at least one of the following target features: altivec, vsx + --> $DIR/bad-reg.rs:59:18 + | +LL | asm!("", in("v0") v64x2); // requires vsx + | ^^^^^^^^^^^^^^ + +error: register class `vreg` requires at least one of the following target features: altivec, vsx + --> $DIR/bad-reg.rs:62:18 + | +LL | asm!("", out("v0") v64x2); // requires vsx + | ^^^^^^^^^^^^^^^ + +error: register class `vreg` requires at least one of the following target features: altivec, vsx + --> $DIR/bad-reg.rs:65:18 + | +LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available + | ^^^^^^^^^^ + +error: register class `vreg` requires at least one of the following target features: altivec, vsx + --> $DIR/bad-reg.rs:68:18 + | +LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available + | ^^^^^^^^^^^ + +error: register class `vreg` requires at least one of the following target features: altivec, vsx + --> $DIR/bad-reg.rs:71:26 + | +LL | asm!("/* {} */", in(vreg) v32x4); // requires altivec + | ^^^^^^^^^^^^^^ + +error: register class `vreg` requires at least one of the following target features: altivec, vsx + --> $DIR/bad-reg.rs:73:26 + | +LL | asm!("/* {} */", in(vreg) v64x2); // requires vsx + | ^^^^^^^^^^^^^^ + +error: register class `vreg` requires at least one of the following target features: altivec, vsx + --> $DIR/bad-reg.rs:76:26 + | +LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available + | ^^^^^^^^^^ + +error: register class `vreg` requires at least one of the following target features: altivec, vsx + --> $DIR/bad-reg.rs:79:26 + | +LL | asm!("/* {} */", out(vreg) _); // requires altivec + | ^^^^^^^^^^^ + +error: register class `vsreg` requires the `vsx` target feature + --> $DIR/bad-reg.rs:98:18 + | +LL | asm!("", in("vs0") v32x4); // requires vsx + | ^^^^^^^^^^^^^^^ + +error: register class `vsreg` requires the `vsx` target feature + --> $DIR/bad-reg.rs:100:18 + | +LL | asm!("", out("vs0") v32x4); // requires vsx + | ^^^^^^^^^^^^^^^^ + +error: register class `vsreg` requires the `vsx` target feature + --> $DIR/bad-reg.rs:102:18 + | +LL | asm!("", in("vs0") v64x2); // requires vsx + | ^^^^^^^^^^^^^^^ + +error: register class `vsreg` requires the `vsx` target feature + --> $DIR/bad-reg.rs:104:18 + | +LL | asm!("", out("vs0") v64x2); // requires vsx + | ^^^^^^^^^^^^^^^^ + +error: register class `vsreg` requires the `vsx` target feature + --> $DIR/bad-reg.rs:106:18 + | +LL | asm!("", in("vs0") x); // FIXME: should be ok if vsx is available + | ^^^^^^^^^^^ + +error: register class `vsreg` requires the `vsx` target feature + --> $DIR/bad-reg.rs:109:18 + | +LL | asm!("", out("vs0") x); // FIXME: should be ok if vsx is available + | ^^^^^^^^^^^^ + +error: register class `vsreg` requires the `vsx` target feature + --> $DIR/bad-reg.rs:112:26 + | +LL | asm!("/* {} */", in(vsreg) v32x4); // requires vsx + | ^^^^^^^^^^^^^^^ + +error: register class `vsreg` requires the `vsx` target feature + --> $DIR/bad-reg.rs:114:26 + | +LL | asm!("/* {} */", in(vsreg) v64x2); // requires vsx + | ^^^^^^^^^^^^^^^ + +error: register class `vsreg` requires the `vsx` target feature + --> $DIR/bad-reg.rs:116:26 + | +LL | asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is available + | ^^^^^^^^^^^ + +error: register class `vsreg` requires the `vsx` target feature + --> $DIR/bad-reg.rs:119:26 + | +LL | asm!("/* {} */", out(vsreg) _); // requires vsx + | ^^^^^^^^^^^^ + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:139:27 + | +LL | asm!("", in("cr") x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:142:28 + | +LL | asm!("", out("cr") x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:145:33 + | +LL | asm!("/* {} */", in(cr) x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:152:28 + | +LL | asm!("", in("ctr") x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:155:29 + | +LL | asm!("", out("ctr") x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:158:34 + | +LL | asm!("/* {} */", in(ctr) x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:165:27 + | +LL | asm!("", in("lr") x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:168:28 + | +LL | asm!("", out("lr") x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:171:33 + | +LL | asm!("/* {} */", in(lr) x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:178:28 + | +LL | asm!("", in("xer") x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:181:29 + | +LL | asm!("", out("xer") x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:184:34 + | +LL | asm!("/* {} */", in(xer) x); + | ^ + | + = note: register class `xer` supports these types: + +error: aborting due to 128 previous errors + diff --git a/tests/ui/asm/powerpc/bad-reg.rs b/tests/ui/asm/powerpc/bad-reg.rs index 7ceae5c6d8d3..c06dcf668d1b 100644 --- a/tests/ui/asm/powerpc/bad-reg.rs +++ b/tests/ui/asm/powerpc/bad-reg.rs @@ -1,5 +1,5 @@ //@ add-minicore -//@ revisions: powerpc powerpc64 powerpc64le aix64 +//@ revisions: powerpc powerpc64 powerpc64le aix64 powerpcspe //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu //@[powerpc] needs-llvm-components: powerpc //@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu @@ -8,6 +8,8 @@ //@[powerpc64le] needs-llvm-components: powerpc //@[aix64] compile-flags: --target powerpc64-ibm-aix //@[aix64] needs-llvm-components: powerpc +//@[powerpcspe] compile-flags: --target powerpc-unknown-linux-gnuspe +//@[powerpcspe] needs-llvm-components: powerpc //@ ignore-backends: gcc // ignore-tidy-linelength @@ -40,7 +42,7 @@ fn f() { asm!("", out("r13") _); //~^ ERROR cannot use register `r13`: r13 is a reserved register on this target asm!("", out("r29") _); - //[powerpc]~^ ERROR cannot use register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm + //[powerpc,powerpcspe]~^ ERROR cannot use register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm asm!("", out("r30") _); //~^ ERROR invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm asm!("", out("fp") _); @@ -51,31 +53,31 @@ fn f() { // vreg asm!("", out("v0") _); // always ok asm!("", in("v0") v32x4); // requires altivec - //[powerpc]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx + //[powerpc,powerpcspe]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx asm!("", out("v0") v32x4); // requires altivec - //[powerpc]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx + //[powerpc,powerpcspe]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx asm!("", in("v0") v64x2); // requires vsx - //[powerpc]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx + //[powerpc,powerpcspe]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx //[powerpc64]~^^ ERROR `vsx` target feature is not enabled asm!("", out("v0") v64x2); // requires vsx - //[powerpc]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx + //[powerpc,powerpcspe]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx //[powerpc64]~^^ ERROR `vsx` target feature is not enabled asm!("", in("v0") x); // FIXME: should be ok if vsx is available - //[powerpc]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx + //[powerpc,powerpcspe]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx //[powerpc64,powerpc64le,aix64]~^^ ERROR type `i32` cannot be used with this register class asm!("", out("v0") x); // FIXME: should be ok if vsx is available - //[powerpc]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx + //[powerpc,powerpcspe]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx //[powerpc64,powerpc64le,aix64]~^^ ERROR type `i32` cannot be used with this register class asm!("/* {} */", in(vreg) v32x4); // requires altivec - //[powerpc]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx + //[powerpc,powerpcspe]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx asm!("/* {} */", in(vreg) v64x2); // requires vsx - //[powerpc]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx + //[powerpc,powerpcspe]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx //[powerpc64]~^^ ERROR `vsx` target feature is not enabled asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available - //[powerpc]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx + //[powerpc,powerpcspe]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx //[powerpc64,powerpc64le,aix64]~^^ ERROR type `i32` cannot be used with this register class asm!("/* {} */", out(vreg) _); // requires altivec - //[powerpc]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx + //[powerpc,powerpcspe]~^ ERROR register class `vreg` requires at least one of the following target features: altivec, vsx // v20-v31 (vs52-vs63) are reserved on AIX with vec-default ABI (this ABI is not currently used in Rust's builtin AIX targets). asm!("", out("v20") _); asm!("", out("v21") _); @@ -94,28 +96,28 @@ fn f() { // vsreg asm!("", out("vs0") _); // always ok asm!("", in("vs0") v32x4); // requires vsx - //[powerpc,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature + //[powerpc,powerpcspe,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature asm!("", out("vs0") v32x4); // requires vsx - //[powerpc,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature + //[powerpc,powerpcspe,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature asm!("", in("vs0") v64x2); // requires vsx - //[powerpc,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature + //[powerpc,powerpcspe,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature asm!("", out("vs0") v64x2); // requires vsx - //[powerpc,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature + //[powerpc,powerpcspe,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature asm!("", in("vs0") x); // FIXME: should be ok if vsx is available - //[powerpc,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature + //[powerpc,powerpcspe,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature //[powerpc64le,aix64]~^^ ERROR type `i32` cannot be used with this register class asm!("", out("vs0") x); // FIXME: should be ok if vsx is available - //[powerpc,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature + //[powerpc,powerpcspe,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature //[powerpc64le,aix64]~^^ ERROR type `i32` cannot be used with this register class asm!("/* {} */", in(vsreg) v32x4); // requires vsx - //[powerpc,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature + //[powerpc,powerpcspe,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature asm!("/* {} */", in(vsreg) v64x2); // requires vsx - //[powerpc,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature + //[powerpc,powerpcspe,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is available - //[powerpc,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature + //[powerpc,powerpcspe,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature //[powerpc64le,aix64]~^^ ERROR type `i32` cannot be used with this register class asm!("/* {} */", out(vsreg) _); // requires vsx - //[powerpc,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature + //[powerpc,powerpcspe,powerpc64]~^ ERROR register class `vsreg` requires the `vsx` target feature // v20-v31 (vs52-vs63) are reserved on AIX with vec-default ABI (this ABI is not currently used in Rust's builtin AIX targets). asm!("", out("vs52") _); @@ -331,5 +333,11 @@ fn f() { //~^ ERROR register `v30` conflicts with register `vs62` asm!("", out("vs63") _, out("v31") _); //~^ ERROR register `v31` conflicts with register `vs63` + + // powerpc-*spe target specific tests + asm!("", out("spe_acc") _); + //[aix64,powerpc,powerpc64,powerpc64le]~^ ERROR cannot use register `spe_acc`: spe_acc is only available on spe targets + asm!("/* {} */", out(spe_acc) _); + //~^ ERROR can only be used as a clobber } } From 76bee3a0444d67f4e89a5f0e3e713a3dcc1f8ba8 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 28 Nov 2025 14:16:56 -0500 Subject: [PATCH 335/585] Move the libgccjit.so file in a target directory Since GCC is not multi-target, we need multiple libgccjit.so. Our solution to have a directory per target so that we can have multiple libgccjit.so. --- compiler/rustc_codegen_gcc/src/lib.rs | 12 ++++++------ src/bootstrap/src/core/build_steps/gcc.rs | 11 +++++++---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index c1506ee6176f..1bdc62f7f29c 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -181,18 +181,18 @@ pub struct GccCodegenBackend { static LTO_SUPPORTED: AtomicBool = AtomicBool::new(false); -fn libgccjit_path(sysroot_path: &Path) -> PathBuf { +fn libgccjit_path(sysroot_path: &Path, target_triple: &str) -> PathBuf { let sysroot_lib_dir = sysroot_path.join("lib"); - sysroot_lib_dir.join("libgccjit.so") + sysroot_lib_dir.join(target_triple).join("libgccjit.so") } -fn load_libgccjit_if_needed(sysroot_path: &Path) { +fn load_libgccjit_if_needed(sysroot_path: &Path, target_triple: &str) { if gccjit::is_loaded() { // Do not load a libgccjit second time. return; } - let libgccjit_target_lib_file = libgccjit_path(sysroot_path); + let libgccjit_target_lib_file = libgccjit_path(sysroot_path, target_triple); let path = libgccjit_target_lib_file.to_str().expect("libgccjit path"); let string = CString::new(path).expect("string to libgccjit path"); @@ -216,9 +216,9 @@ fn init(&self, sess: &Session) { // invalid. // This is the case for instance in Rust for Linux where they specify --sysroot=/dev/null. for path in sess.opts.sysroot.all_paths() { - let libgccjit_target_lib_file = libgccjit_path(path); + let libgccjit_target_lib_file = libgccjit_path(path, &sess.target.llvm_target); if let Ok(true) = fs::exists(libgccjit_target_lib_file) { - load_libgccjit_if_needed(path); + load_libgccjit_if_needed(path, &sess.target.llvm_target); break; } } diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index def794c98a41..d638dd45f3ac 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -27,6 +27,7 @@ pub struct Gcc { #[derive(Clone)] pub struct GccOutput { pub libgccjit: PathBuf, + target: TargetSelection, } impl GccOutput { @@ -46,7 +47,9 @@ pub fn install_to(&self, builder: &Builder<'_>, directory: &Path) { format!("Cannot find libgccjit at {}", self.libgccjit.display()) ); - let dst = directory.join(target_filename); + let dest_dir = directory.join(self.target); + t!(fs::create_dir_all(&dest_dir)); + let dst = dest_dir.join(target_filename); builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); } } @@ -70,7 +73,7 @@ fn run(self, builder: &Builder<'_>) -> Self::Output { // If GCC has already been built, we avoid building it again. let metadata = match get_gcc_build_status(builder, target) { - GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: path }, + GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: path, target }, GccBuildStatus::ShouldBuild(m) => m, }; @@ -80,14 +83,14 @@ fn run(self, builder: &Builder<'_>) -> Self::Output { let libgccjit_path = libgccjit_built_path(&metadata.install_dir); if builder.config.dry_run() { - return GccOutput { libgccjit: libgccjit_path }; + return GccOutput { libgccjit: libgccjit_path, target }; } build_gcc(&metadata, builder, target); t!(metadata.stamp.write()); - GccOutput { libgccjit: libgccjit_path } + GccOutput { libgccjit: libgccjit_path, target } } } From ea0995a91a2e4b44d54e99480d117683016c120b Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 28 Nov 2025 15:17:35 -0500 Subject: [PATCH 336/585] Ignore failing GCC test --- tests/mir-opt/inline/inline_instruction_set.rs | 1 + tests/ui/check-cfg/values-target-json.rs | 1 + tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs | 1 + tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs | 1 + tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs | 1 + .../cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs | 1 + tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs | 1 + .../cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.rs | 1 + .../cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.rs | 1 + tests/ui/cmse-nonsecure/cmse-nonsecure-entry/c-variadic.rs | 1 + tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs | 1 + .../ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs | 1 + .../ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.rs | 1 + tests/ui/feature-gates/feature-gate-abi-msp430-interrupt.rs | 1 + tests/ui/force-inlining/asm.rs | 1 + tests/ui/issues/issue-37131.rs | 1 + tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs | 1 + tests/ui/print-request/supported-crate-types.rs | 2 ++ tests/ui/repr/repr_align_greater_usize.rs | 1 + .../abi-incompatible-target-feature-attribute-fcw.rs | 1 + tests/ui/target-feature/feature-hierarchy.rs | 1 + tests/ui/target-feature/no-llvm-leaks.rs | 1 + 22 files changed, 23 insertions(+) diff --git a/tests/mir-opt/inline/inline_instruction_set.rs b/tests/mir-opt/inline/inline_instruction_set.rs index fe2aaffa2a09..5baef21c6de7 100644 --- a/tests/mir-opt/inline/inline_instruction_set.rs +++ b/tests/mir-opt/inline/inline_instruction_set.rs @@ -4,6 +4,7 @@ // //@ compile-flags: --target thumbv4t-none-eabi //@ needs-llvm-components: arm +//@ ignore-backends: gcc #![crate_type = "lib"] #![feature(rustc_attrs)] diff --git a/tests/ui/check-cfg/values-target-json.rs b/tests/ui/check-cfg/values-target-json.rs index 2912c83b58de..defb286ed19b 100644 --- a/tests/ui/check-cfg/values-target-json.rs +++ b/tests/ui/check-cfg/values-target-json.rs @@ -5,6 +5,7 @@ //@ no-auto-check-cfg //@ needs-llvm-components: x86 //@ compile-flags: --crate-type=lib --check-cfg=cfg() --target={{src-base}}/check-cfg/my-awesome-platform.json +//@ ignore-backends: gcc #![feature(lang_items, no_core, auto_traits, rustc_attrs)] #![no_core] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs index fc5db3cd7543..7cf63352234d 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs @@ -1,6 +1,7 @@ //@ add-minicore //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm +//@ ignore-backends: gcc #![feature(abi_cmse_nonsecure_call, no_core, lang_items)] #![no_core] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs index e35138bf7cb8..8896235614e3 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs @@ -1,6 +1,7 @@ //@ add-minicore //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm +//@ ignore-backends: gcc #![feature(abi_cmse_nonsecure_call, no_core, lang_items)] #![no_core] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs index b9d9fc92c8e2..4565d89f0dc8 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs @@ -2,6 +2,7 @@ //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm //@ add-minicore +//@ ignore-backends: gcc #![feature(abi_cmse_nonsecure_call, no_core, lang_items)] #![no_core] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs index 1ed5df459c7b..2d6b71502fce 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs @@ -2,6 +2,7 @@ //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ incremental (required to trigger the bug) //@ needs-llvm-components: arm +//@ ignore-backends: gcc #![feature(abi_cmse_nonsecure_call, no_core)] #![no_core] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs index db9a51969a9f..5528865fc840 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs @@ -2,6 +2,7 @@ //@ build-pass //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm +//@ ignore-backends: gcc #![feature(abi_cmse_nonsecure_call, no_core, lang_items, intrinsics)] #![no_core] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.rs index 290688f8ed95..8bbce0d7948b 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.rs @@ -1,6 +1,7 @@ //@ add-minicore //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm +//@ ignore-backends: gcc #![feature(abi_cmse_nonsecure_call, lang_items, no_core)] #![no_core] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.rs index f23677e1ed71..3f99dcbdbb46 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.rs @@ -1,6 +1,7 @@ //@ add-minicore //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm +//@ ignore-backends: gcc #![feature(abi_cmse_nonsecure_call, lang_items, no_core)] #![no_core] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/c-variadic.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/c-variadic.rs index d4a6c1fa07c1..213b69b6fa20 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/c-variadic.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/c-variadic.rs @@ -2,6 +2,7 @@ //@ edition: 2018 //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm +//@ ignore-backends: gcc #![feature(cmse_nonsecure_entry, c_variadic, no_core, lang_items)] #![no_core] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs index 023f50d636bf..bcae7f0c47f1 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs @@ -1,6 +1,7 @@ //@ add-minicore //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm +//@ ignore-backends: gcc #![feature(cmse_nonsecure_entry, no_core, lang_items)] #![no_core] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs index 5326dd5765f1..53e98d2eb1bc 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs @@ -1,6 +1,7 @@ //@ add-minicore //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm +//@ ignore-backends: gcc #![feature(cmse_nonsecure_entry, no_core, lang_items)] #![no_core] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.rs index 19abd1740e65..bfc8ad458359 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.rs @@ -1,6 +1,7 @@ //@ add-minicore //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm +//@ ignore-backends: gcc #![feature(cmse_nonsecure_entry, no_core, lang_items)] #![no_core] diff --git a/tests/ui/feature-gates/feature-gate-abi-msp430-interrupt.rs b/tests/ui/feature-gates/feature-gate-abi-msp430-interrupt.rs index 4971fcb6cb5b..33276576385f 100644 --- a/tests/ui/feature-gates/feature-gate-abi-msp430-interrupt.rs +++ b/tests/ui/feature-gates/feature-gate-abi-msp430-interrupt.rs @@ -1,6 +1,7 @@ //@ add-minicore //@ needs-llvm-components: msp430 //@ compile-flags: --target=msp430-none-elf --crate-type=rlib +//@ ignore-backends: gcc #![no_core] #![feature(no_core, lang_items)] diff --git a/tests/ui/force-inlining/asm.rs b/tests/ui/force-inlining/asm.rs index d48af8253d83..d48b9fc01be6 100644 --- a/tests/ui/force-inlining/asm.rs +++ b/tests/ui/force-inlining/asm.rs @@ -2,6 +2,7 @@ //@ build-fail //@ compile-flags: --crate-type=lib --target thumbv4t-none-eabi //@ needs-llvm-components: arm +//@ ignore-backends: gcc // Checks that forced inlining won't mix asm with incompatible instruction sets. diff --git a/tests/ui/issues/issue-37131.rs b/tests/ui/issues/issue-37131.rs index e91c76e1390e..875495d08ed7 100644 --- a/tests/ui/issues/issue-37131.rs +++ b/tests/ui/issues/issue-37131.rs @@ -7,5 +7,6 @@ //@ compile-flags: --target=thumbv6m-none-eabi //@ ignore-arm //@ needs-llvm-components: arm +//@ ignore-backends: gcc fn main() { } diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs index 58f0a74e674d..e8d277e36d28 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs @@ -2,6 +2,7 @@ //@ compile-flags: --target x86_64-pc-windows-msvc //@ compile-flags: --crate-type lib --emit link //@ needs-llvm-components: x86 +//@ ignore-backends: gcc #![no_core] #![feature(no_core)] extern crate minicore; diff --git a/tests/ui/print-request/supported-crate-types.rs b/tests/ui/print-request/supported-crate-types.rs index 50185a231eeb..d816e33b413f 100644 --- a/tests/ui/print-request/supported-crate-types.rs +++ b/tests/ui/print-request/supported-crate-types.rs @@ -17,9 +17,11 @@ //@[wasm] compile-flags: --target=wasm32-unknown-unknown --print=supported-crate-types -Zunstable-options //@[wasm] needs-llvm-components: webassembly +//@[wasm] ignore-backends: gcc //@[musl] compile-flags: --target=x86_64-unknown-linux-musl --print=supported-crate-types -Zunstable-options //@[musl] needs-llvm-components: x86 +//@[musl] ignore-backends: gcc //@[linux] compile-flags: --target=x86_64-unknown-linux-gnu --print=supported-crate-types -Zunstable-options //@[linux] needs-llvm-components: x86 diff --git a/tests/ui/repr/repr_align_greater_usize.rs b/tests/ui/repr/repr_align_greater_usize.rs index d8eb03ef9525..52a4d23b1eca 100644 --- a/tests/ui/repr/repr_align_greater_usize.rs +++ b/tests/ui/repr/repr_align_greater_usize.rs @@ -5,6 +5,7 @@ //@[aarch32] build-pass //@[aarch32] needs-llvm-components: arm //@[aarch32] compile-flags: --target=thumbv7m-none-eabi +//@ ignore-backends: gcc // We should fail to compute alignment for types aligned higher than usize::MAX. // We can't handle alignments that require all 32 bits, so this only affects 16-bit. diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs index 8449b8ce0928..dba9e2366d9e 100644 --- a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs @@ -2,6 +2,7 @@ //@ compile-flags: --target=aarch64-unknown-none-softfloat //@ needs-llvm-components: aarch64 //@ add-minicore +//@ ignore-backends: gcc #![feature(no_core)] #![no_core] #![deny(aarch64_softfloat_neon)] diff --git a/tests/ui/target-feature/feature-hierarchy.rs b/tests/ui/target-feature/feature-hierarchy.rs index 2e10c0e6e690..a14af97d7234 100644 --- a/tests/ui/target-feature/feature-hierarchy.rs +++ b/tests/ui/target-feature/feature-hierarchy.rs @@ -5,6 +5,7 @@ //@ [aarch64-sve2] needs-llvm-components: aarch64 //@ build-pass //@ add-minicore +//@ ignore-backends: gcc #![no_core] #![crate_type = "rlib"] #![feature(intrinsics, rustc_attrs, no_core, staged_api)] diff --git a/tests/ui/target-feature/no-llvm-leaks.rs b/tests/ui/target-feature/no-llvm-leaks.rs index fa72c88ead02..e4d964497ef3 100644 --- a/tests/ui/target-feature/no-llvm-leaks.rs +++ b/tests/ui/target-feature/no-llvm-leaks.rs @@ -2,6 +2,7 @@ //@ revisions: aarch64 x86-64 //@ [aarch64] compile-flags: -Ctarget-feature=+neon,+fp16,+fhm --target=aarch64-unknown-linux-gnu //@ [aarch64] needs-llvm-components: aarch64 +//@ [aarch64] ignore-backends: gcc //@ [x86-64] compile-flags: -Ctarget-feature=+sse4.2,+rdrand --target=x86_64-unknown-linux-gnu //@ [x86-64] needs-llvm-components: x86 //@ build-pass From 2a88ea189261650700564bde7f84fc1f06468d27 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 29 Nov 2025 09:50:03 -0500 Subject: [PATCH 337/585] Bless tests --- .../cmse-nonsecure-call/generics.stderr | 24 ++++++++--------- .../cmse-nonsecure-call/infer.rs | 1 + .../cmse-nonsecure-call/infer.stderr | 8 +++--- .../params-via-stack.stderr | 10 +++---- .../return-via-stack.stderr | 18 ++++++------- .../undeclared-lifetime.stderr | 2 +- .../wrong-abi-location-1.stderr | 2 +- .../wrong-abi-location-2.stderr | 2 +- .../cmse-nonsecure-entry/c-variadic.stderr | 8 +++--- .../cmse-nonsecure-entry/generics.stderr | 26 +++++++++---------- .../cmse-nonsecure-entry/infer.rs | 1 + .../cmse-nonsecure-entry/infer.stderr | 8 +++--- .../params-via-stack.stderr | 10 +++---- .../return-via-stack.stderr | 18 ++++++------- .../feature-gate-abi-msp430-interrupt.stderr | 14 +++++----- tests/ui/force-inlining/asm.stderr | 8 +++--- .../raw-dylib/windows/unsupported-abi.stderr | 4 +-- .../repr_align_greater_usize.msp430.stderr | 4 +-- ...atible-target-feature-attribute-fcw.stderr | 8 +++--- 19 files changed, 89 insertions(+), 87 deletions(-) diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr index a3848182ef14..64dbcd42033d 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr @@ -1,11 +1,11 @@ error: function pointer types may not have generic parameters - --> $DIR/generics.rs:14:40 + --> $DIR/generics.rs:15:40 | LL | f1: extern "cmse-nonsecure-call" fn(U, u32, u32, u32) -> u64, | ^^^^^^^^^ error[E0425]: cannot find type `U` in this scope - --> $DIR/generics.rs:14:50 + --> $DIR/generics.rs:15:50 | LL | struct Test { | - similarly named type parameter `T` defined here @@ -23,7 +23,7 @@ LL | struct Test { | +++ error[E0562]: `impl Trait` is not allowed in `fn` pointer parameters - --> $DIR/generics.rs:17:41 + --> $DIR/generics.rs:18:41 | LL | f2: extern "cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> impl Copy, | ^^^^^^^^^ @@ -31,7 +31,7 @@ LL | f2: extern "cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> impl C = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in `fn` pointer return types - --> $DIR/generics.rs:17:70 + --> $DIR/generics.rs:18:70 | LL | f2: extern "cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> impl Copy, | ^^^^^^^^^ @@ -39,7 +39,7 @@ LL | f2: extern "cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> impl C = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in `fn` pointer parameters - --> $DIR/generics.rs:20:42 + --> $DIR/generics.rs:21:42 | LL | f3: extern "cmse-nonsecure-call" fn((impl Copy, u32), u32, u32, u32) -> (impl Copy, u32), | ^^^^^^^^^ @@ -47,7 +47,7 @@ LL | f3: extern "cmse-nonsecure-call" fn((impl Copy, u32), u32, u32, u32) -> = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in `fn` pointer return types - --> $DIR/generics.rs:20:78 + --> $DIR/generics.rs:21:78 | LL | f3: extern "cmse-nonsecure-call" fn((impl Copy, u32), u32, u32, u32) -> (impl Copy, u32), | ^^^^^^^^^ @@ -55,19 +55,19 @@ LL | f3: extern "cmse-nonsecure-call" fn((impl Copy, u32), u32, u32, u32) -> = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0798]: generics are not allowed in `extern "cmse-nonsecure-call"` signatures - --> $DIR/generics.rs:23:41 + --> $DIR/generics.rs:24:41 | LL | f4: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, | ^ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-call"` signatures - --> $DIR/generics.rs:24:41 + --> $DIR/generics.rs:25:41 | LL | f5: extern "cmse-nonsecure-call" fn(Wrapper, u32, u32, u32) -> u64, | ^^^^^^^^^^ error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/generics.rs:30:71 + --> $DIR/generics.rs:31:71 | LL | type WithTraitObject = extern "cmse-nonsecure-call" fn(&dyn Trait) -> &dyn Trait; | ^^^^^^^^^^ this type doesn't fit in the available registers @@ -76,7 +76,7 @@ LL | type WithTraitObject = extern "cmse-nonsecure-call" fn(&dyn Trait) -> &dyn = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/generics.rs:34:60 + --> $DIR/generics.rs:35:60 | LL | extern "cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Trait; | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -85,7 +85,7 @@ LL | extern "cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Tra = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/generics.rs:41:60 + --> $DIR/generics.rs:42:60 | LL | extern "cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTransparent; | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -94,7 +94,7 @@ LL | extern "cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTranspare = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0045]: C-variadic functions with the "cmse-nonsecure-call" calling convention are not supported - --> $DIR/generics.rs:44:20 + --> $DIR/generics.rs:45:20 | LL | type WithVarArgs = extern "cmse-nonsecure-call" fn(u32, ...); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.rs index 3452dc268e59..231a21cd874b 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.rs @@ -1,6 +1,7 @@ //@ add-minicore //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm +//@ ignore-backends: gcc #![feature(abi_cmse_nonsecure_call, no_core, lang_items)] #![no_core] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.stderr index aab314c1ff25..398236b089b4 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.stderr @@ -1,23 +1,23 @@ error[E0282]: type annotations needed - --> $DIR/infer.rs:16:13 + --> $DIR/infer.rs:17:13 | LL | let _ = mem::transmute:: _, extern "cmse-nonsecure-call" fn() -> _>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` error[E0282]: type annotations needed - --> $DIR/infer.rs:21:13 + --> $DIR/infer.rs:22:13 | LL | let _ = mem::transmute:: (i32, _), extern "cmse-nonsecure-call" fn() -> (i32, _)>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` error[E0282]: type annotations needed - --> $DIR/infer.rs:26:13 + --> $DIR/infer.rs:27:13 | LL | let _ = mem::transmute:: (), extern "cmse-nonsecure-call" fn(_: _) -> ()>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` error[E0282]: type annotations needed - --> $DIR/infer.rs:32:9 + --> $DIR/infer.rs:33:9 | LL | mem::transmute:: (), extern "cmse-nonsecure-call" fn(_: (i32, _)) -> ()>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr index 5a059e4df7b1..a3201844035c 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr @@ -1,5 +1,5 @@ error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/params-via-stack.rs:16:64 + --> $DIR/params-via-stack.rs:17:64 | LL | f1: extern "cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: u32), | ^^^ ^^^ does not fit in the available registers @@ -9,7 +9,7 @@ LL | f1: extern "cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: u32) = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/params-via-stack.rs:17:61 + --> $DIR/params-via-stack.rs:18:61 | LL | f2: extern "cmse-nonsecure-call" fn(u32, u32, u32, u16, u16), | ^^^ does not fit in the available registers @@ -17,7 +17,7 @@ LL | f2: extern "cmse-nonsecure-call" fn(u32, u32, u32, u16, u16), = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/params-via-stack.rs:18:51 + --> $DIR/params-via-stack.rs:19:51 | LL | f3: extern "cmse-nonsecure-call" fn(u32, u64, u32), | ^^^ does not fit in the available registers @@ -25,7 +25,7 @@ LL | f3: extern "cmse-nonsecure-call" fn(u32, u64, u32), = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/params-via-stack.rs:19:56 + --> $DIR/params-via-stack.rs:20:56 | LL | f4: extern "cmse-nonsecure-call" fn(AlignRelevant, u32), | ^^^ does not fit in the available registers @@ -33,7 +33,7 @@ LL | f4: extern "cmse-nonsecure-call" fn(AlignRelevant, u32), = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/params-via-stack.rs:20:41 + --> $DIR/params-via-stack.rs:21:41 | LL | f5: extern "cmse-nonsecure-call" fn([u32; 5]), | ^^^^^^^^ does not fit in the available registers diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr index ddf969c1bce1..4351444225b5 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr @@ -1,5 +1,5 @@ error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:36:48 + --> $DIR/return-via-stack.rs:37:48 | LL | u128: extern "cmse-nonsecure-call" fn() -> u128, | ^^^^ this type doesn't fit in the available registers @@ -8,7 +8,7 @@ LL | u128: extern "cmse-nonsecure-call" fn() -> u128, = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:37:48 + --> $DIR/return-via-stack.rs:38:48 | LL | i128: extern "cmse-nonsecure-call" fn() -> i128, | ^^^^ this type doesn't fit in the available registers @@ -17,7 +17,7 @@ LL | i128: extern "cmse-nonsecure-call" fn() -> i128, = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:26:46 + --> $DIR/return-via-stack.rs:27:46 | LL | f1: extern "cmse-nonsecure-call" fn() -> ReprCU64, | ^^^^^^^^ this type doesn't fit in the available registers @@ -26,7 +26,7 @@ LL | f1: extern "cmse-nonsecure-call" fn() -> ReprCU64, = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:27:46 + --> $DIR/return-via-stack.rs:28:46 | LL | f2: extern "cmse-nonsecure-call" fn() -> ReprCBytes, | ^^^^^^^^^^ this type doesn't fit in the available registers @@ -35,7 +35,7 @@ LL | f2: extern "cmse-nonsecure-call" fn() -> ReprCBytes, = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:28:46 + --> $DIR/return-via-stack.rs:29:46 | LL | f3: extern "cmse-nonsecure-call" fn() -> U64Compound, | ^^^^^^^^^^^ this type doesn't fit in the available registers @@ -44,7 +44,7 @@ LL | f3: extern "cmse-nonsecure-call" fn() -> U64Compound, = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:29:46 + --> $DIR/return-via-stack.rs:30:46 | LL | f4: extern "cmse-nonsecure-call" fn() -> ReprCAlign16, | ^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -53,7 +53,7 @@ LL | f4: extern "cmse-nonsecure-call" fn() -> ReprCAlign16, = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:30:46 + --> $DIR/return-via-stack.rs:31:46 | LL | f5: extern "cmse-nonsecure-call" fn() -> [u8; 5], | ^^^^^^^ this type doesn't fit in the available registers @@ -62,7 +62,7 @@ LL | f5: extern "cmse-nonsecure-call" fn() -> [u8; 5], = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:52:46 + --> $DIR/return-via-stack.rs:53:46 | LL | f1: extern "cmse-nonsecure-call" fn() -> ReprRustUnionU64, | ^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -71,7 +71,7 @@ LL | f1: extern "cmse-nonsecure-call" fn() -> ReprRustUnionU64, = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:53:46 + --> $DIR/return-via-stack.rs:54:46 | LL | f2: extern "cmse-nonsecure-call" fn() -> ReprCUnionU64, | ^^^^^^^^^^^^^ this type doesn't fit in the available registers diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr index 7300bdb72cdd..99255e9f22b1 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/undeclared-lifetime.rs:15:43 + --> $DIR/undeclared-lifetime.rs:16:43 | LL | id::(PhantomData); | ^^ undeclared lifetime diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr index b9cccecc64bf..2ed3a6569719 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr @@ -1,5 +1,5 @@ error[E0781]: the `"cmse-nonsecure-call"` ABI is only allowed on function pointers - --> $DIR/wrong-abi-location-1.rs:10:1 + --> $DIR/wrong-abi-location-1.rs:11:1 | LL | pub extern "cmse-nonsecure-call" fn test() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr index 437d7b80b1fd..0fe8341b8d7d 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr @@ -1,5 +1,5 @@ error[E0781]: the `"cmse-nonsecure-call"` ABI is only allowed on function pointers - --> $DIR/wrong-abi-location-2.rs:10:1 + --> $DIR/wrong-abi-location-2.rs:11:1 | LL | / extern "cmse-nonsecure-call" { LL | | fn test(); diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/c-variadic.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/c-variadic.stderr index 5b0924d6f2af..c8f4ef98c124 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/c-variadic.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/c-variadic.stderr @@ -1,5 +1,5 @@ error: `...` is not supported for `extern "cmse-nonsecure-entry"` functions - --> $DIR/c-variadic.rs:14:60 + --> $DIR/c-variadic.rs:15:60 | LL | unsafe extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { | ----------------------------- ^^^^^^ @@ -9,13 +9,13 @@ LL | unsafe extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list error: functions cannot be both `async` and C-variadic - --> $DIR/c-variadic.rs:19:1 + --> $DIR/c-variadic.rs:20:1 | LL | async unsafe extern "cmse-nonsecure-entry" fn async_and_c_variadic(_: ...) { | ^^^^^ `async` because of this ^^^^^^ C-variadic because of this error: `...` is not supported for `extern "cmse-nonsecure-entry"` functions - --> $DIR/c-variadic.rs:19:68 + --> $DIR/c-variadic.rs:20:68 | LL | async unsafe extern "cmse-nonsecure-entry" fn async_and_c_variadic(_: ...) { | ----------------------------- ^^^^^^ @@ -25,7 +25,7 @@ LL | async unsafe extern "cmse-nonsecure-entry" fn async_and_c_variadic(_: ...) = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list error[E0798]: `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/c-variadic.rs:25:1 + --> $DIR/c-variadic.rs:26:1 | LL | async unsafe extern "cmse-nonsecure-entry" fn async_is_not_allowed() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr index 5ddd29883f86..653e8f73012b 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr @@ -1,53 +1,53 @@ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:31:8 + --> $DIR/generics.rs:32:8 | LL | _: U, | ^ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:64:48 + --> $DIR/generics.rs:65:48 | LL | extern "cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 { | ^^^^^^^^^ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:79:57 + --> $DIR/generics.rs:80:57 | LL | extern "cmse-nonsecure-entry" fn identity_impl_trait(v: impl Copy) -> impl Copy { | ^^^^^^^^^ error[E0798]: `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:79:71 + --> $DIR/generics.rs:80:71 | LL | extern "cmse-nonsecure-entry" fn identity_impl_trait(v: impl Copy) -> impl Copy { | ^^^^^^^^^ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:86:8 + --> $DIR/generics.rs:87:8 | LL | v: (impl Copy, i32), | ^^^^^^^^^^^^^^^^ error[E0798]: `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:88:6 + --> $DIR/generics.rs:89:6 | LL | ) -> (impl Copy, i32) { | ^^^^^^^^^^^^^^^^ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:14:57 + --> $DIR/generics.rs:15:57 | LL | extern "cmse-nonsecure-entry" fn ambient_generic(_: T, _: u32, _: u32, _: u32) -> u64 { | ^ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:20:12 + --> $DIR/generics.rs:21:12 | LL | _: Wrapper, | ^^^^^^^^^^ error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/generics.rs:46:65 + --> $DIR/generics.rs:47:65 | LL | extern "cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait { | ^^^^^^^^^^ this type doesn't fit in the available registers @@ -56,7 +56,7 @@ LL | extern "cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/generics.rs:51:80 + --> $DIR/generics.rs:52:80 | LL | extern "cmse-nonsecure-entry" fn static_trait_object(x: &'static dyn Trait) -> &'static dyn Trait { | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -65,7 +65,7 @@ LL | extern "cmse-nonsecure-entry" fn static_trait_object(x: &'static dyn Trait) = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/generics.rs:59:81 + --> $DIR/generics.rs:60:81 | LL | extern "cmse-nonsecure-entry" fn wrapped_trait_object(x: WrapperTransparent) -> WrapperTransparent { | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -74,13 +74,13 @@ LL | extern "cmse-nonsecure-entry" fn wrapped_trait_object(x: WrapperTransparent = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:69:57 + --> $DIR/generics.rs:70:57 | LL | extern "cmse-nonsecure-entry" fn return_impl_trait() -> impl Copy { | ^^^^^^^^^ error[E0798]: `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:74:64 + --> $DIR/generics.rs:75:64 | LL | extern "cmse-nonsecure-entry" fn return_impl_trait_nested() -> (impl Copy, i32) { | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.rs index 75a08ff40356..ceb09c8ad6f7 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.rs @@ -1,6 +1,7 @@ //@ add-minicore //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm +//@ ignore-backends: gcc #![feature(cmse_nonsecure_entry, no_core, lang_items)] #![no_core] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.stderr index 4243771c3e67..f9352a8a2fbf 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.stderr @@ -1,23 +1,23 @@ error[E0282]: type annotations needed - --> $DIR/infer.rs:16:13 + --> $DIR/infer.rs:17:13 | LL | let _ = mem::transmute:: _, extern "cmse-nonsecure-entry" fn() -> _>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` error[E0282]: type annotations needed - --> $DIR/infer.rs:21:13 + --> $DIR/infer.rs:22:13 | LL | let _ = mem::transmute:: (i32, _), extern "cmse-nonsecure-entry" fn() -> (i32, _)>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` error[E0282]: type annotations needed - --> $DIR/infer.rs:26:13 + --> $DIR/infer.rs:27:13 | LL | let _ = mem::transmute:: (), extern "cmse-nonsecure-entry" fn(_: _) -> ()>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` error[E0282]: type annotations needed - --> $DIR/infer.rs:31:13 + --> $DIR/infer.rs:32:13 | LL | let _ = mem::transmute::< | _____________^ diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr index 3d523fc7be67..af8277d314ba 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr @@ -1,5 +1,5 @@ error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/params-via-stack.rs:15:76 + --> $DIR/params-via-stack.rs:16:76 | LL | pub extern "cmse-nonsecure-entry" fn f1(_: u32, _: u32, _: u32, _: u32, _: u32, _: u32) {} | ^^^ ^^^ does not fit in the available registers @@ -9,7 +9,7 @@ LL | pub extern "cmse-nonsecure-entry" fn f1(_: u32, _: u32, _: u32, _: u32, _: = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/params-via-stack.rs:17:76 + --> $DIR/params-via-stack.rs:18:76 | LL | pub extern "cmse-nonsecure-entry" fn f2(_: u32, _: u32, _: u32, _: u16, _: u16) {} | ^^^ does not fit in the available registers @@ -17,7 +17,7 @@ LL | pub extern "cmse-nonsecure-entry" fn f2(_: u32, _: u32, _: u32, _: u16, _: = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/params-via-stack.rs:19:60 + --> $DIR/params-via-stack.rs:20:60 | LL | pub extern "cmse-nonsecure-entry" fn f3(_: u32, _: u64, _: u32) {} | ^^^ does not fit in the available registers @@ -25,7 +25,7 @@ LL | pub extern "cmse-nonsecure-entry" fn f3(_: u32, _: u64, _: u32) {} = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/params-via-stack.rs:21:62 + --> $DIR/params-via-stack.rs:22:62 | LL | pub extern "cmse-nonsecure-entry" fn f4(_: AlignRelevant, _: u32) {} | ^^^ does not fit in the available registers @@ -33,7 +33,7 @@ LL | pub extern "cmse-nonsecure-entry" fn f4(_: AlignRelevant, _: u32) {} = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/params-via-stack.rs:25:44 + --> $DIR/params-via-stack.rs:26:44 | LL | pub extern "cmse-nonsecure-entry" fn f5(_: [u32; 5]) {} | ^^^^^^^^ does not fit in the available registers diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.stderr index 07ee31bef23c..c5effed92ae9 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.stderr @@ -1,5 +1,5 @@ error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:24:46 + --> $DIR/return-via-stack.rs:25:46 | LL | pub extern "cmse-nonsecure-entry" fn f1() -> ReprCU64 { | ^^^^^^^^ this type doesn't fit in the available registers @@ -8,7 +8,7 @@ LL | pub extern "cmse-nonsecure-entry" fn f1() -> ReprCU64 { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:29:46 + --> $DIR/return-via-stack.rs:30:46 | LL | pub extern "cmse-nonsecure-entry" fn f2() -> ReprCBytes { | ^^^^^^^^^^ this type doesn't fit in the available registers @@ -17,7 +17,7 @@ LL | pub extern "cmse-nonsecure-entry" fn f2() -> ReprCBytes { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:34:46 + --> $DIR/return-via-stack.rs:35:46 | LL | pub extern "cmse-nonsecure-entry" fn f3() -> U64Compound { | ^^^^^^^^^^^ this type doesn't fit in the available registers @@ -26,7 +26,7 @@ LL | pub extern "cmse-nonsecure-entry" fn f3() -> U64Compound { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:39:46 + --> $DIR/return-via-stack.rs:40:46 | LL | pub extern "cmse-nonsecure-entry" fn f4() -> ReprCAlign16 { | ^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -35,7 +35,7 @@ LL | pub extern "cmse-nonsecure-entry" fn f4() -> ReprCAlign16 { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:46:46 + --> $DIR/return-via-stack.rs:47:46 | LL | pub extern "cmse-nonsecure-entry" fn f5() -> [u8; 5] { | ^^^^^^^ this type doesn't fit in the available registers @@ -44,7 +44,7 @@ LL | pub extern "cmse-nonsecure-entry" fn f5() -> [u8; 5] { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:52:48 + --> $DIR/return-via-stack.rs:53:48 | LL | pub extern "cmse-nonsecure-entry" fn u128() -> u128 { | ^^^^ this type doesn't fit in the available registers @@ -53,7 +53,7 @@ LL | pub extern "cmse-nonsecure-entry" fn u128() -> u128 { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:58:48 + --> $DIR/return-via-stack.rs:59:48 | LL | pub extern "cmse-nonsecure-entry" fn i128() -> i128 { | ^^^^ this type doesn't fit in the available registers @@ -62,7 +62,7 @@ LL | pub extern "cmse-nonsecure-entry" fn i128() -> i128 { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:75:54 + --> $DIR/return-via-stack.rs:76:54 | LL | pub extern "cmse-nonsecure-entry" fn union_rust() -> ReprRustUnionU64 { | ^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -71,7 +71,7 @@ LL | pub extern "cmse-nonsecure-entry" fn union_rust() -> ReprRustUnionU64 { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:80:51 + --> $DIR/return-via-stack.rs:81:51 | LL | pub extern "cmse-nonsecure-entry" fn union_c() -> ReprCUnionU64 { | ^^^^^^^^^^^^^ this type doesn't fit in the available registers diff --git a/tests/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr b/tests/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr index 4a995b4efa6f..f90918a64b38 100644 --- a/tests/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr +++ b/tests/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr @@ -1,5 +1,5 @@ error[E0658]: the extern "msp430-interrupt" ABI is experimental and subject to change - --> $DIR/feature-gate-abi-msp430-interrupt.rs:10:8 + --> $DIR/feature-gate-abi-msp430-interrupt.rs:11:8 | LL | extern "msp430-interrupt" fn f() {} | ^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | extern "msp430-interrupt" fn f() {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "msp430-interrupt" ABI is experimental and subject to change - --> $DIR/feature-gate-abi-msp430-interrupt.rs:14:12 + --> $DIR/feature-gate-abi-msp430-interrupt.rs:15:12 | LL | extern "msp430-interrupt" fn m(); | ^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | extern "msp430-interrupt" fn m(); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "msp430-interrupt" ABI is experimental and subject to change - --> $DIR/feature-gate-abi-msp430-interrupt.rs:17:12 + --> $DIR/feature-gate-abi-msp430-interrupt.rs:18:12 | LL | extern "msp430-interrupt" fn dm() {} | ^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | extern "msp430-interrupt" fn dm() {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "msp430-interrupt" ABI is experimental and subject to change - --> $DIR/feature-gate-abi-msp430-interrupt.rs:23:12 + --> $DIR/feature-gate-abi-msp430-interrupt.rs:24:12 | LL | extern "msp430-interrupt" fn m() {} | ^^^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | extern "msp430-interrupt" fn m() {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "msp430-interrupt" ABI is experimental and subject to change - --> $DIR/feature-gate-abi-msp430-interrupt.rs:28:12 + --> $DIR/feature-gate-abi-msp430-interrupt.rs:29:12 | LL | extern "msp430-interrupt" fn im() {} | ^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | extern "msp430-interrupt" fn im() {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "msp430-interrupt" ABI is experimental and subject to change - --> $DIR/feature-gate-abi-msp430-interrupt.rs:32:18 + --> $DIR/feature-gate-abi-msp430-interrupt.rs:33:18 | LL | type TA = extern "msp430-interrupt" fn(); | ^^^^^^^^^^^^^^^^^^ @@ -59,7 +59,7 @@ LL | type TA = extern "msp430-interrupt" fn(); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "msp430-interrupt" ABI is experimental and subject to change - --> $DIR/feature-gate-abi-msp430-interrupt.rs:35:8 + --> $DIR/feature-gate-abi-msp430-interrupt.rs:36:8 | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/force-inlining/asm.stderr b/tests/ui/force-inlining/asm.stderr index 1744c0215bb4..a73b3f665ae2 100644 --- a/tests/ui/force-inlining/asm.stderr +++ b/tests/ui/force-inlining/asm.stderr @@ -1,5 +1,5 @@ error: `instruction_set_a32` could not be inlined into `t32` but is required to be inlined - --> $DIR/asm.rs:45:5 + --> $DIR/asm.rs:46:5 | LL | instruction_set_a32(); | ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_a32` called here @@ -7,7 +7,7 @@ LL | instruction_set_a32(); = note: could not be inlined due to: incompatible instruction set error: `inline_always_and_using_inline_asm` could not be inlined into `t32` but is required to be inlined - --> $DIR/asm.rs:49:5 + --> $DIR/asm.rs:50:5 | LL | inline_always_and_using_inline_asm(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...`inline_always_and_using_inline_asm` called here @@ -15,7 +15,7 @@ LL | inline_always_and_using_inline_asm(); = note: could not be inlined due to: cannot move inline-asm across instruction sets error: `instruction_set_a32` could not be inlined into `default` but is required to be inlined - --> $DIR/asm.rs:54:5 + --> $DIR/asm.rs:55:5 | LL | instruction_set_a32(); | ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_a32` called here @@ -23,7 +23,7 @@ LL | instruction_set_a32(); = note: could not be inlined due to: incompatible instruction set error: `instruction_set_t32` could not be inlined into `default` but is required to be inlined - --> $DIR/asm.rs:56:5 + --> $DIR/asm.rs:57:5 | LL | instruction_set_t32(); | ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_t32` called here diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr index 8727e55f4cef..5a574636245d 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr @@ -1,5 +1,5 @@ warning: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported-abi.rs:13:1 + --> $DIR/unsupported-abi.rs:14:1 | LL | / extern "stdcall" { LL | | @@ -15,7 +15,7 @@ LL | | } = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture - --> $DIR/unsupported-abi.rs:16:5 + --> $DIR/unsupported-abi.rs:17:5 | LL | fn f(x: i32); | ^^^^^^^^^^^^^ diff --git a/tests/ui/repr/repr_align_greater_usize.msp430.stderr b/tests/ui/repr/repr_align_greater_usize.msp430.stderr index db25cb1b5f2e..a7b06acb6752 100644 --- a/tests/ui/repr/repr_align_greater_usize.msp430.stderr +++ b/tests/ui/repr/repr_align_greater_usize.msp430.stderr @@ -1,5 +1,5 @@ error[E0589]: alignment must not be greater than `isize::MAX` bytes - --> $DIR/repr_align_greater_usize.rs:22:8 + --> $DIR/repr_align_greater_usize.rs:23:8 | LL | #[repr(align(32768))] | ^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[repr(align(32768))] = note: `isize::MAX` is 32767 for the current target error[E0589]: alignment must not be greater than `isize::MAX` bytes - --> $DIR/repr_align_greater_usize.rs:25:8 + --> $DIR/repr_align_greater_usize.rs:26:8 | LL | #[repr(align(65536))] | ^^^^^^^^^^^^ diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr index e3bb8bef9a00..9595d1aba477 100644 --- a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr @@ -1,5 +1,5 @@ error: enabling the `neon` target feature on the current target is unsound due to ABI issues - --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:12:18 + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:13:18 | LL | #[target_feature(enable = "neon")] | ^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[target_feature(enable = "neon")] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #134375 note: the lint level is defined here - --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:7:9 + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:8:9 | LL | #![deny(aarch64_softfloat_neon)] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ error: aborting due to 1 previous error Future incompatibility report: Future breakage diagnostic: error: enabling the `neon` target feature on the current target is unsound due to ABI issues - --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:12:18 + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:13:18 | LL | #[target_feature(enable = "neon")] | ^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | #[target_feature(enable = "neon")] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #134375 note: the lint level is defined here - --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:7:9 + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:8:9 | LL | #![deny(aarch64_softfloat_neon)] | ^^^^^^^^^^^^^^^^^^^^^^ From 2a74c626d66995293f5341a932c7003939253ef0 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 29 Nov 2025 11:09:23 -0500 Subject: [PATCH 338/585] Move to rustlib directory --- compiler/rustc_codegen_gcc/src/lib.rs | 5 +++-- src/bootstrap/src/core/build_steps/gcc.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 1bdc62f7f29c..c40ee39ba6e4 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -182,8 +182,9 @@ pub struct GccCodegenBackend { static LTO_SUPPORTED: AtomicBool = AtomicBool::new(false); fn libgccjit_path(sysroot_path: &Path, target_triple: &str) -> PathBuf { - let sysroot_lib_dir = sysroot_path.join("lib"); - sysroot_lib_dir.join(target_triple).join("libgccjit.so") + let sysroot_lib_dir = sysroot_path.join("lib").join("rustlib"); + let libgccjit_target_lib_file = + sysroot_lib_dir.join(target_triple).join("lib").join("libgccjit.so"); } fn load_libgccjit_if_needed(sysroot_path: &Path, target_triple: &str) { diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index d638dd45f3ac..fc87c48f17b6 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -47,7 +47,7 @@ pub fn install_to(&self, builder: &Builder<'_>, directory: &Path) { format!("Cannot find libgccjit at {}", self.libgccjit.display()) ); - let dest_dir = directory.join(self.target); + let dest_dir = directory.join("rustlib").join(self.target).join("lib"); t!(fs::create_dir_all(&dest_dir)); let dst = dest_dir.join(target_filename); builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); From 58f3f313b3789a9aa36d99687e4b7f85f7499619 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 29 Nov 2025 12:19:14 -0500 Subject: [PATCH 339/585] Fix lib path --- compiler/rustc_codegen_gcc/src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index c40ee39ba6e4..6c072e7daca2 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -98,6 +98,7 @@ use rustc_middle::util::Providers; use rustc_session::Session; use rustc_session::config::{OptLevel, OutputFilenames}; +use rustc_session::filesearch::make_target_lib_path; use rustc_span::Symbol; use rustc_target::spec::{Arch, RelocModel}; use tempfile::TempDir; @@ -182,9 +183,7 @@ pub struct GccCodegenBackend { static LTO_SUPPORTED: AtomicBool = AtomicBool::new(false); fn libgccjit_path(sysroot_path: &Path, target_triple: &str) -> PathBuf { - let sysroot_lib_dir = sysroot_path.join("lib").join("rustlib"); - let libgccjit_target_lib_file = - sysroot_lib_dir.join(target_triple).join("lib").join("libgccjit.so"); + make_target_lib_path(sysroot_path, target_triple).join("libgccjit.so") } fn load_libgccjit_if_needed(sysroot_path: &Path, target_triple: &str) { From 42059a3041bfceabbee8edd42b26c643901886cd Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 5 Dec 2025 09:58:37 -0500 Subject: [PATCH 340/585] Remove libgccjit_path function --- compiler/rustc_codegen_gcc/src/lib.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 6c072e7daca2..a77239e23b4e 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -182,17 +182,12 @@ pub struct GccCodegenBackend { static LTO_SUPPORTED: AtomicBool = AtomicBool::new(false); -fn libgccjit_path(sysroot_path: &Path, target_triple: &str) -> PathBuf { - make_target_lib_path(sysroot_path, target_triple).join("libgccjit.so") -} - -fn load_libgccjit_if_needed(sysroot_path: &Path, target_triple: &str) { +fn load_libgccjit_if_needed(libgccjit_target_lib_file: &Path) { if gccjit::is_loaded() { // Do not load a libgccjit second time. return; } - let libgccjit_target_lib_file = libgccjit_path(sysroot_path, target_triple); let path = libgccjit_target_lib_file.to_str().expect("libgccjit path"); let string = CString::new(path).expect("string to libgccjit path"); @@ -216,9 +211,10 @@ fn init(&self, sess: &Session) { // invalid. // This is the case for instance in Rust for Linux where they specify --sysroot=/dev/null. for path in sess.opts.sysroot.all_paths() { - let libgccjit_target_lib_file = libgccjit_path(path, &sess.target.llvm_target); - if let Ok(true) = fs::exists(libgccjit_target_lib_file) { - load_libgccjit_if_needed(path, &sess.target.llvm_target); + let libgccjit_target_lib_file = + make_target_lib_path(path, &sess.target.llvm_target).join("libgccjit.so"); + if let Ok(true) = fs::exists(&libgccjit_target_lib_file) { + load_libgccjit_if_needed(&libgccjit_target_lib_file); break; } } From 2081b7a66317272a511294ee18300b5e7f1bab46 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 5 Dec 2025 14:39:30 +0100 Subject: [PATCH 341/585] chore(len_without_is_empty): extract to a separate module It didn't share any logic at all with the lints in `len_zero.rs`, whereas the helper functions were partially mixed together, so that the file was hard to navigate --- clippy_lints/src/declared_lints.rs | 2 +- clippy_lints/src/len_without_is_empty.rs | 342 ++++++++++++++++++++++ clippy_lints/src/len_zero.rs | 344 +---------------------- clippy_lints/src/lib.rs | 2 + 4 files changed, 352 insertions(+), 338 deletions(-) create mode 100644 clippy_lints/src/len_without_is_empty.rs diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 17bcc3824a7b..1a02c2166454 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -245,8 +245,8 @@ crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO, crate::large_stack_frames::LARGE_STACK_FRAMES_INFO, crate::legacy_numeric_constants::LEGACY_NUMERIC_CONSTANTS_INFO, + crate::len_without_is_empty::LEN_WITHOUT_IS_EMPTY_INFO, crate::len_zero::COMPARISON_TO_EMPTY_INFO, - crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO, crate::len_zero::LEN_ZERO_INFO, crate::let_if_seq::USELESS_LET_IF_SEQ_INFO, crate::let_underscore::LET_UNDERSCORE_FUTURE_INFO, diff --git a/clippy_lints/src/len_without_is_empty.rs b/clippy_lints/src/len_without_is_empty.rs new file mode 100644 index 000000000000..1d219d7c3b74 --- /dev/null +++ b/clippy_lints/src/len_without_is_empty.rs @@ -0,0 +1,342 @@ +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::res::MaybeDef; +use clippy_utils::{fulfill_or_allowed, get_parent_as_impl, sym}; +use rustc_hir::def::Res; +use rustc_hir::def_id::{DefId, DefIdSet}; +use rustc_hir::{ + FnRetTy, GenericArg, GenericBound, HirId, ImplItem, ImplItemKind, ImplicitSelfKind, Item, ItemKind, Mutability, + Node, OpaqueTyOrigin, PathSegment, PrimTy, QPath, TraitItemId, TyKind, +}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, FnSig, Ty}; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::kw; +use rustc_span::{Ident, Span, Symbol}; +use rustc_trait_selection::traits::supertrait_def_ids; + +declare_clippy_lint! { + /// ### What it does + /// Checks for items that implement `.len()` but not + /// `.is_empty()`. + /// + /// ### Why is this bad? + /// It is good custom to have both methods, because for + /// some data structures, asking about the length will be a costly operation, + /// whereas `.is_empty()` can usually answer in constant time. Also it used to + /// lead to false positives on the [`len_zero`](#len_zero) lint – currently that + /// lint will ignore such entities. + /// + /// ### Example + /// ```ignore + /// impl X { + /// pub fn len(&self) -> usize { + /// .. + /// } + /// } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub LEN_WITHOUT_IS_EMPTY, + style, + "traits or impls with a public `len` method but no corresponding `is_empty` method" +} + +declare_lint_pass!(LenWithoutIsEmpty => [LEN_WITHOUT_IS_EMPTY]); + +impl<'tcx> LateLintPass<'tcx> for LenWithoutIsEmpty { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if let ItemKind::Trait(_, _, _, ident, _, _, trait_items) = item.kind + && !item.span.from_expansion() + { + check_trait_items(cx, item, ident, trait_items); + } + } + + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { + if item.ident.name == sym::len + && let ImplItemKind::Fn(sig, _) = &item.kind + && sig.decl.implicit_self.has_implicit_self() + && sig.decl.inputs.len() == 1 + && cx.effective_visibilities.is_exported(item.owner_id.def_id) + && matches!(sig.decl.output, FnRetTy::Return(_)) + && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id()) + && imp.of_trait.is_none() + && let TyKind::Path(ty_path) = &imp.self_ty.kind + && let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id() + && let Some(local_id) = ty_id.as_local() + && let ty_hir_id = cx.tcx.local_def_id_to_hir_id(local_id) + && let Some(output) = LenOutput::new(cx, cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder()) + { + let (name, kind) = match cx.tcx.hir_node(ty_hir_id) { + Node::ForeignItem(x) => (x.ident.name, "extern type"), + Node::Item(x) => match x.kind { + ItemKind::Struct(ident, ..) => (ident.name, "struct"), + ItemKind::Enum(ident, ..) => (ident.name, "enum"), + ItemKind::Union(ident, ..) => (ident.name, "union"), + _ => (x.kind.ident().unwrap().name, "type"), + }, + _ => return, + }; + check_for_is_empty( + cx, + sig.span, + sig.decl.implicit_self, + output, + ty_id, + name, + kind, + item.hir_id(), + ty_hir_id, + ); + } + } +} + +fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Ident, trait_items: &[TraitItemId]) { + fn is_named_self(cx: &LateContext<'_>, item: TraitItemId, name: Symbol) -> bool { + cx.tcx.item_name(item.owner_id) == name + && matches!( + cx.tcx.fn_arg_idents(item.owner_id), + [Some(Ident { + name: kw::SelfLower, + .. + })], + ) + } + + // fill the set with current and super traits + fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) { + if set.insert(traitt) { + for supertrait in supertrait_def_ids(cx.tcx, traitt) { + fill_trait_set(supertrait, set, cx); + } + } + } + + if cx.effective_visibilities.is_exported(visited_trait.owner_id.def_id) + && trait_items.iter().any(|&i| is_named_self(cx, i, sym::len)) + { + let mut current_and_super_traits = DefIdSet::default(); + fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx); + let is_empty_method_found = current_and_super_traits + .items() + .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(sym::is_empty)) + .any(|i| i.is_method() && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1); + + if !is_empty_method_found { + span_lint( + cx, + LEN_WITHOUT_IS_EMPTY, + visited_trait.span, + format!( + "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method", + ident.name + ), + ); + } + } +} + +fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { + if let ty::Alias(_, alias_ty) = ty.kind() + && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir_get_if_local(alias_ty.def_id) + && let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin + && let [GenericBound::Trait(trait_ref)] = &opaque.bounds + && let Some(segment) = trait_ref.trait_ref.path.segments.last() + && let Some(generic_args) = segment.args + && let [constraint] = generic_args.constraints + && let Some(ty) = constraint.ty() + && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind + && let [segment] = path.segments + { + return Some(segment); + } + + None +} + +fn is_first_generic_integral<'tcx>(segment: &'tcx PathSegment<'tcx>) -> bool { + if let Some(generic_args) = segment.args + && let [GenericArg::Type(ty), ..] = &generic_args.args + && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind + && let [segment, ..] = &path.segments + && matches!(segment.res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) + { + true + } else { + false + } +} + +#[derive(Debug, Clone, Copy)] +enum LenOutput { + Integral, + Option(DefId), + Result(DefId), +} + +impl LenOutput { + fn new<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option { + if let Some(segment) = extract_future_output(cx, sig.output()) { + let res = segment.res; + + if matches!(res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) { + return Some(Self::Integral); + } + + if let Res::Def(_, def_id) = res + && let Some(res) = match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::Option) => Some(Self::Option(def_id)), + Some(sym::Result) => Some(Self::Result(def_id)), + _ => None, + } + && is_first_generic_integral(segment) + { + return Some(res); + } + + return None; + } + + match *sig.output().kind() { + ty::Int(_) | ty::Uint(_) => Some(Self::Integral), + ty::Adt(adt, subs) => match cx.tcx.get_diagnostic_name(adt.did()) { + Some(sym::Option) => subs.type_at(0).is_integral().then(|| Self::Option(adt.did())), + Some(sym::Result) => subs.type_at(0).is_integral().then(|| Self::Result(adt.did())), + _ => None, + }, + _ => None, + } + } + + fn matches_is_empty_output<'tcx>(self, cx: &LateContext<'tcx>, is_empty_output: Ty<'tcx>) -> bool { + if let Some(segment) = extract_future_output(cx, is_empty_output) { + return match (self, segment.res) { + (_, Res::PrimTy(PrimTy::Bool)) => true, + (Self::Option(_), Res::Def(_, def_id)) if cx.tcx.is_diagnostic_item(sym::Option, def_id) => true, + (Self::Result(_), Res::Def(_, def_id)) if cx.tcx.is_diagnostic_item(sym::Result, def_id) => true, + _ => false, + }; + } + + match (self, is_empty_output.kind()) { + (_, &ty::Bool) => true, + (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(), + (Self::Result(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(), + _ => false, + } + } +} + +/// The expected signature of `is_empty`, based on that of `len` +fn expected_is_empty_sig(len_output: LenOutput, len_self_kind: ImplicitSelfKind) -> String { + let self_ref = match len_self_kind { + ImplicitSelfKind::RefImm => "&", + ImplicitSelfKind::RefMut => "&(mut) ", + _ => "", + }; + match len_output { + LenOutput::Integral => format!("expected signature: `({self_ref}self) -> bool`"), + LenOutput::Option(_) => { + format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Option") + }, + LenOutput::Result(..) => { + format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Result") + }, + } +} + +/// Checks if the given signature matches the expectations for `is_empty` +fn check_is_empty_sig<'tcx>( + cx: &LateContext<'tcx>, + is_empty_sig: FnSig<'tcx>, + len_self_kind: ImplicitSelfKind, + len_output: LenOutput, +) -> bool { + if let [is_empty_self_arg, is_empty_output] = &**is_empty_sig.inputs_and_output + && len_output.matches_is_empty_output(cx, *is_empty_output) + { + match (is_empty_self_arg.kind(), len_self_kind) { + // if `len` takes `&self`, `is_empty` should do so as well + (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::RefImm) + // if `len` takes `&mut self`, `is_empty` may take that _or_ `&self` (#16190) + | (ty::Ref(_, _, Mutability::Mut | Mutability::Not), ImplicitSelfKind::RefMut) => true, + // if len takes `self`, `is_empty` should do so as well + // XXX: we might want to relax this to allow `&self` and `&mut self` + (_, ImplicitSelfKind::Imm | ImplicitSelfKind::Mut) if !is_empty_self_arg.is_ref() => true, + _ => false, + } + } else { + false + } +} + +/// Checks if the given type has an `is_empty` method with the appropriate signature. +#[expect(clippy::too_many_arguments)] +fn check_for_is_empty( + cx: &LateContext<'_>, + len_span: Span, + len_self_kind: ImplicitSelfKind, + len_output: LenOutput, + impl_ty: DefId, + item_name: Symbol, + item_kind: &str, + len_method_hir_id: HirId, + ty_decl_hir_id: HirId, +) { + // Implementor may be a type alias, in which case we need to get the `DefId` of the aliased type to + // find the correct inherent impls. + let impl_ty = if let Some(adt) = cx.tcx.type_of(impl_ty).skip_binder().ty_adt_def() { + adt.did() + } else { + return; + }; + + let is_empty = cx + .tcx + .inherent_impls(impl_ty) + .iter() + .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(sym::is_empty)) + .find(|item| item.is_fn()); + + let (msg, is_empty_span, is_empty_expected_sig) = match is_empty { + None => ( + format!("{item_kind} `{item_name}` has a public `len` method, but no `is_empty` method"), + None, + None, + ), + Some(is_empty) if !cx.effective_visibilities.is_exported(is_empty.def_id.expect_local()) => ( + format!("{item_kind} `{item_name}` has a public `len` method, but a private `is_empty` method"), + Some(cx.tcx.def_span(is_empty.def_id)), + None, + ), + Some(is_empty) + if !(is_empty.is_method() + && check_is_empty_sig( + cx, + cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(), + len_self_kind, + len_output, + )) => + { + ( + format!( + "{item_kind} `{item_name}` has a public `len` method, but the `is_empty` method has an unexpected signature", + ), + Some(cx.tcx.def_span(is_empty.def_id)), + Some(expected_is_empty_sig(len_output, len_self_kind)), + ) + }, + Some(_) => return, + }; + + if !fulfill_or_allowed(cx, LEN_WITHOUT_IS_EMPTY, [len_method_hir_id, ty_decl_hir_id]) { + span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, len_span, msg, |db| { + if let Some(span) = is_empty_span { + db.span_note(span, "`is_empty` defined here"); + } + if let Some(expected_sig) = is_empty_expected_sig { + db.note(expected_sig); + } + }); + } +} diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index f5a832f3adfd..2e576da38b89 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,27 +1,20 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::Msrv; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::ty::implements_trait; -use clippy_utils::{fulfill_or_allowed, get_parent_as_impl, parent_item_name, peel_ref_operators, sym}; +use clippy_utils::{parent_item_name, peel_ref_operators, sym}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::def::Res; -use rustc_hir::def_id::{DefId, DefIdSet}; -use rustc_hir::{ - BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, HirId, ImplItem, ImplItemKind, ImplicitSelfKind, - Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy, QPath, RustcVersion, - StabilityLevel, StableSince, TraitItemId, TyKind, -}; +use rustc_hir::def_id::DefId; +use rustc_hir::{BinOpKind, Expr, ExprKind, PatExprKind, PatKind, RustcVersion, StabilityLevel, StableSince}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, FnSig, Ty}; +use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::symbol::kw; -use rustc_span::{Ident, Span, Symbol}; -use rustc_trait_selection::traits::supertrait_def_ids; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -58,32 +51,6 @@ "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead" } -declare_clippy_lint! { - /// ### What it does - /// Checks for items that implement `.len()` but not - /// `.is_empty()`. - /// - /// ### Why is this bad? - /// It is good custom to have both methods, because for - /// some data structures, asking about the length will be a costly operation, - /// whereas `.is_empty()` can usually answer in constant time. Also it used to - /// lead to false positives on the [`len_zero`](#len_zero) lint – currently that - /// lint will ignore such entities. - /// - /// ### Example - /// ```ignore - /// impl X { - /// pub fn len(&self) -> usize { - /// .. - /// } - /// } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub LEN_WITHOUT_IS_EMPTY, - style, - "traits or impls with a public `len` method but no corresponding `is_empty` method" -} - declare_clippy_lint! { /// ### What it does /// Checks for comparing to an empty slice such as `""` or `[]`, @@ -126,7 +93,7 @@ pub struct LenZero { msrv: Msrv, } -impl_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMPTY]); +impl_lint_pass!(LenZero => [LEN_ZERO, COMPARISON_TO_EMPTY]); impl LenZero { pub fn new(conf: &'static Conf) -> Self { @@ -135,53 +102,6 @@ pub fn new(conf: &'static Conf) -> Self { } impl<'tcx> LateLintPass<'tcx> for LenZero { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Trait(_, _, _, ident, _, _, trait_items) = item.kind - && !item.span.from_expansion() - { - check_trait_items(cx, item, ident, trait_items); - } - } - - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { - if item.ident.name == sym::len - && let ImplItemKind::Fn(sig, _) = &item.kind - && sig.decl.implicit_self.has_implicit_self() - && sig.decl.inputs.len() == 1 - && cx.effective_visibilities.is_exported(item.owner_id.def_id) - && matches!(sig.decl.output, FnRetTy::Return(_)) - && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id()) - && imp.of_trait.is_none() - && let TyKind::Path(ty_path) = &imp.self_ty.kind - && let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id() - && let Some(local_id) = ty_id.as_local() - && let ty_hir_id = cx.tcx.local_def_id_to_hir_id(local_id) - && let Some(output) = LenOutput::new(cx, cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder()) - { - let (name, kind) = match cx.tcx.hir_node(ty_hir_id) { - Node::ForeignItem(x) => (x.ident.name, "extern type"), - Node::Item(x) => match x.kind { - ItemKind::Struct(ident, ..) => (ident.name, "struct"), - ItemKind::Enum(ident, ..) => (ident.name, "enum"), - ItemKind::Union(ident, ..) => (ident.name, "union"), - _ => (x.kind.ident().unwrap().name, "type"), - }, - _ => return, - }; - check_for_is_empty( - cx, - sig.span, - sig.decl.implicit_self, - output, - ty_id, - name, - kind, - item.hir_id(), - ty_hir_id, - ); - } - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Let(lt) = expr.kind && match lt.pat.kind { @@ -355,256 +275,6 @@ fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span { } } -fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Ident, trait_items: &[TraitItemId]) { - fn is_named_self(cx: &LateContext<'_>, item: TraitItemId, name: Symbol) -> bool { - cx.tcx.item_name(item.owner_id) == name - && matches!( - cx.tcx.fn_arg_idents(item.owner_id), - [Some(Ident { - name: kw::SelfLower, - .. - })], - ) - } - - // fill the set with current and super traits - fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) { - if set.insert(traitt) { - for supertrait in supertrait_def_ids(cx.tcx, traitt) { - fill_trait_set(supertrait, set, cx); - } - } - } - - if cx.effective_visibilities.is_exported(visited_trait.owner_id.def_id) - && trait_items.iter().any(|&i| is_named_self(cx, i, sym::len)) - { - let mut current_and_super_traits = DefIdSet::default(); - fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx); - let is_empty_method_found = current_and_super_traits - .items() - .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(sym::is_empty)) - .any(|i| i.is_method() && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1); - - if !is_empty_method_found { - span_lint( - cx, - LEN_WITHOUT_IS_EMPTY, - visited_trait.span, - format!( - "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method", - ident.name - ), - ); - } - } -} - -fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { - if let ty::Alias(_, alias_ty) = ty.kind() - && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir_get_if_local(alias_ty.def_id) - && let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin - && let [GenericBound::Trait(trait_ref)] = &opaque.bounds - && let Some(segment) = trait_ref.trait_ref.path.segments.last() - && let Some(generic_args) = segment.args - && let [constraint] = generic_args.constraints - && let Some(ty) = constraint.ty() - && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind - && let [segment] = path.segments - { - return Some(segment); - } - - None -} - -fn is_first_generic_integral<'tcx>(segment: &'tcx PathSegment<'tcx>) -> bool { - if let Some(generic_args) = segment.args - && let [GenericArg::Type(ty), ..] = &generic_args.args - && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind - && let [segment, ..] = &path.segments - && matches!(segment.res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) - { - true - } else { - false - } -} - -#[derive(Debug, Clone, Copy)] -enum LenOutput { - Integral, - Option(DefId), - Result(DefId), -} - -impl LenOutput { - fn new<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option { - if let Some(segment) = extract_future_output(cx, sig.output()) { - let res = segment.res; - - if matches!(res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) { - return Some(Self::Integral); - } - - if let Res::Def(_, def_id) = res - && let Some(res) = match cx.tcx.get_diagnostic_name(def_id) { - Some(sym::Option) => Some(Self::Option(def_id)), - Some(sym::Result) => Some(Self::Result(def_id)), - _ => None, - } - && is_first_generic_integral(segment) - { - return Some(res); - } - - return None; - } - - match *sig.output().kind() { - ty::Int(_) | ty::Uint(_) => Some(Self::Integral), - ty::Adt(adt, subs) => match cx.tcx.get_diagnostic_name(adt.did()) { - Some(sym::Option) => subs.type_at(0).is_integral().then(|| Self::Option(adt.did())), - Some(sym::Result) => subs.type_at(0).is_integral().then(|| Self::Result(adt.did())), - _ => None, - }, - _ => None, - } - } - - fn matches_is_empty_output<'tcx>(self, cx: &LateContext<'tcx>, is_empty_output: Ty<'tcx>) -> bool { - if let Some(segment) = extract_future_output(cx, is_empty_output) { - return match (self, segment.res) { - (_, Res::PrimTy(PrimTy::Bool)) => true, - (Self::Option(_), Res::Def(_, def_id)) if cx.tcx.is_diagnostic_item(sym::Option, def_id) => true, - (Self::Result(_), Res::Def(_, def_id)) if cx.tcx.is_diagnostic_item(sym::Result, def_id) => true, - _ => false, - }; - } - - match (self, is_empty_output.kind()) { - (_, &ty::Bool) => true, - (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(), - (Self::Result(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(), - _ => false, - } - } -} - -/// The expected signature of `is_empty`, based on that of `len` -fn expected_is_empty_sig(len_output: LenOutput, len_self_kind: ImplicitSelfKind) -> String { - let self_ref = match len_self_kind { - ImplicitSelfKind::RefImm => "&", - ImplicitSelfKind::RefMut => "&(mut) ", - _ => "", - }; - match len_output { - LenOutput::Integral => format!("expected signature: `({self_ref}self) -> bool`"), - LenOutput::Option(_) => { - format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Option") - }, - LenOutput::Result(..) => { - format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Result") - }, - } -} - -/// Checks if the given signature matches the expectations for `is_empty` -fn check_is_empty_sig<'tcx>( - cx: &LateContext<'tcx>, - is_empty_sig: FnSig<'tcx>, - len_self_kind: ImplicitSelfKind, - len_output: LenOutput, -) -> bool { - if let [is_empty_self_arg, is_empty_output] = &**is_empty_sig.inputs_and_output - && len_output.matches_is_empty_output(cx, *is_empty_output) - { - match (is_empty_self_arg.kind(), len_self_kind) { - // if `len` takes `&self`, `is_empty` should do so as well - (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::RefImm) - // if `len` takes `&mut self`, `is_empty` may take that _or_ `&self` (#16190) - | (ty::Ref(_, _, Mutability::Mut | Mutability::Not), ImplicitSelfKind::RefMut) => true, - // if len takes `self`, `is_empty` should do so as well - // XXX: we might want to relax this to allow `&self` and `&mut self` - (_, ImplicitSelfKind::Imm | ImplicitSelfKind::Mut) if !is_empty_self_arg.is_ref() => true, - _ => false, - } - } else { - false - } -} - -/// Checks if the given type has an `is_empty` method with the appropriate signature. -#[expect(clippy::too_many_arguments)] -fn check_for_is_empty( - cx: &LateContext<'_>, - len_span: Span, - len_self_kind: ImplicitSelfKind, - len_output: LenOutput, - impl_ty: DefId, - item_name: Symbol, - item_kind: &str, - len_method_hir_id: HirId, - ty_decl_hir_id: HirId, -) { - // Implementor may be a type alias, in which case we need to get the `DefId` of the aliased type to - // find the correct inherent impls. - let impl_ty = if let Some(adt) = cx.tcx.type_of(impl_ty).skip_binder().ty_adt_def() { - adt.did() - } else { - return; - }; - - let is_empty = cx - .tcx - .inherent_impls(impl_ty) - .iter() - .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(sym::is_empty)) - .find(|item| item.is_fn()); - - let (msg, is_empty_span, is_empty_expected_sig) = match is_empty { - None => ( - format!("{item_kind} `{item_name}` has a public `len` method, but no `is_empty` method"), - None, - None, - ), - Some(is_empty) if !cx.effective_visibilities.is_exported(is_empty.def_id.expect_local()) => ( - format!("{item_kind} `{item_name}` has a public `len` method, but a private `is_empty` method"), - Some(cx.tcx.def_span(is_empty.def_id)), - None, - ), - Some(is_empty) - if !(is_empty.is_method() - && check_is_empty_sig( - cx, - cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(), - len_self_kind, - len_output, - )) => - { - ( - format!( - "{item_kind} `{item_name}` has a public `len` method, but the `is_empty` method has an unexpected signature", - ), - Some(cx.tcx.def_span(is_empty.def_id)), - Some(expected_is_empty_sig(len_output, len_self_kind)), - ) - }, - Some(_) => return, - }; - - if !fulfill_or_allowed(cx, LEN_WITHOUT_IS_EMPTY, [len_method_hir_id, ty_decl_hir_id]) { - span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, len_span, msg, |db| { - if let Some(span) = is_empty_span { - db.span_note(span, "`is_empty` defined here"); - } - if let Some(expected_sig) = is_empty_expected_sig { - db.note(expected_sig); - } - }); - } -} - fn is_empty_string(expr: &Expr<'_>) -> bool { if let ExprKind::Lit(lit) = expr.kind && let LitKind::Str(lit, _) = lit.node diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index cad36b7f197a..5b39d8844797 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -182,6 +182,7 @@ mod large_stack_arrays; mod large_stack_frames; mod legacy_numeric_constants; +mod len_without_is_empty; mod len_zero; mod let_if_seq; mod let_underscore; @@ -539,6 +540,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(|_| Box::new(unnecessary_mut_passed::UnnecessaryMutPassed)), Box::new(|_| Box::>::default()), Box::new(move |_| Box::new(len_zero::LenZero::new(conf))), + Box::new(|_| Box::new(len_without_is_empty::LenWithoutIsEmpty)), Box::new(move |_| Box::new(attrs::Attributes::new(conf))), Box::new(|_| Box::new(blocks_in_conditions::BlocksInConditions)), Box::new(|_| Box::new(unicode::Unicode)), From 803cfb9ddf67ff39535a142bc4459eec28f3fef3 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Fri, 5 Dec 2025 17:09:11 +0100 Subject: [PATCH 342/585] Fix armv8r-none-eabihf tier It's listed as Tier 2 in `armv8r-none-eabihf.md`, but Tier 3 in `arm-none-eabi.md`. Updated to reflect current state of Tier 2. --- src/doc/rustc/src/platform-support/arm-none-eabi.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md index aaa80e429718..81545db6c51f 100644 --- a/src/doc/rustc/src/platform-support/arm-none-eabi.md +++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md @@ -16,6 +16,7 @@ their own document. - Arm R-Profile Architectures - [`armv7r-none-eabi` and `armv7r-none-eabihf`](armv7r-none-eabi.md) - [`armebv7r-none-eabi` and `armebv7r-none-eabihf`](armebv7r-none-eabi.md) + - [`armv8r-none-eabihf`](armv8r-none-eabihf.md) - Arm M-Profile Architectures - [`thumbv6m-none-eabi`](thumbv6m-none-eabi.md) - [`thumbv7m-none-eabi`](thumbv7m-none-eabi.md) @@ -30,7 +31,7 @@ their own document. - Arm A-Profile Architectures - [`armv7a-none-eabihf`](armv7a-none-eabi.md) - Arm R-Profile Architectures - - [`armv8r-none-eabihf`](armv8r-none-eabihf.md) + - None - Arm M-Profile Architectures - None - *Legacy* Arm Architectures From c9055034744c98739e087a2a7f3197f4e547aed2 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 5 Dec 2025 18:18:58 +0000 Subject: [PATCH 343/585] fix: `panicking_unwrap` FP on field access with implicit deref --- clippy_lints/src/unwrap.rs | 9 +++++++-- .../ui/checked_unwrap/simple_conditionals.rs | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 8ed3df8731b3..a95f2b681add 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -180,14 +180,19 @@ fn is_potentially_local_place(&self, place: &Place<'_>) -> bool { field_indices, .. } => { + let field_projections = place + .projections + .iter() + .filter(|proj| matches!(proj.kind, ProjectionKind::Field(_, _))) + .collect::>(); is_potentially_local_place(*local_id, place) // If there were projections other than field projections, err on the side of caution and say that they // _might_ be mutating something. // // The reason we use `<=` and not `==` is that a mutation of `struct` or `struct.field1` should count as // mutation of the child fields such as `struct.field1.field2` - && place.projections.len() <= field_indices.len() - && iter::zip(&place.projections, field_indices.iter().copied().rev()).all(|(proj, field_idx)| { + && field_projections.len() <= field_indices.len() + && iter::zip(&field_projections, field_indices.iter().copied().rev()).all(|(proj, field_idx)| { match proj.kind { ProjectionKind::Field(f_idx, _) => f_idx == field_idx, // If this is a projection we don't expect, it _might_ be mutating something diff --git a/tests/ui/checked_unwrap/simple_conditionals.rs b/tests/ui/checked_unwrap/simple_conditionals.rs index c6476a7507a1..bab20b091d38 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.rs +++ b/tests/ui/checked_unwrap/simple_conditionals.rs @@ -472,3 +472,22 @@ fn borrow_toption(_: &Toption) {} //~^ unnecessary_unwrap } } + +mod issue16188 { + struct Foo { + value: Option, + } + + impl Foo { + pub fn bar(&mut self) { + let print_value = |v: i32| { + println!("{}", v); + }; + + if self.value.is_none() { + self.value = Some(10); + print_value(self.value.unwrap()); + } + } + } +} From dfee0dad260cf22efd0d56e0b07021d0fc86a564 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Fri, 5 Dec 2025 18:06:42 +0000 Subject: [PATCH 344/585] Add test for misspelled feature name --- tests/ui/feature-gates/unknown-feature.rs | 13 +++++++++++- tests/ui/feature-gates/unknown-feature.stderr | 20 +++++++++++++++---- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/tests/ui/feature-gates/unknown-feature.rs b/tests/ui/feature-gates/unknown-feature.rs index 20fd932d4c2f..2ecc9b82a48d 100644 --- a/tests/ui/feature-gates/unknown-feature.rs +++ b/tests/ui/feature-gates/unknown-feature.rs @@ -1,3 +1,14 @@ -#![feature(unknown_rust_feature)] //~ ERROR unknown feature +#![feature( + unknown_rust_feature, + //~^ ERROR unknown feature + + // Typo for lang feature + associated_types_default, + //~^ ERROR unknown feature + + // Typo for lib feature + core_intrnisics, + //~^ ERROR unknown feature +)] fn main() {} diff --git a/tests/ui/feature-gates/unknown-feature.stderr b/tests/ui/feature-gates/unknown-feature.stderr index 0a731ddcc0b6..a0cadb3f817f 100644 --- a/tests/ui/feature-gates/unknown-feature.stderr +++ b/tests/ui/feature-gates/unknown-feature.stderr @@ -1,9 +1,21 @@ error[E0635]: unknown feature `unknown_rust_feature` - --> $DIR/unknown-feature.rs:1:12 + --> $DIR/unknown-feature.rs:2:5 | -LL | #![feature(unknown_rust_feature)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | unknown_rust_feature, + | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error[E0635]: unknown feature `associated_types_default` + --> $DIR/unknown-feature.rs:6:5 + | +LL | associated_types_default, + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0635]: unknown feature `core_intrnisics` + --> $DIR/unknown-feature.rs:10:5 + | +LL | core_intrnisics, + | ^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0635`. From e6b6de40c23893fbce3e37f708175cb4f7e6e1ae Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Fri, 5 Dec 2025 19:33:24 +0000 Subject: [PATCH 345/585] bump version number --- src/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version b/src/version index 95784efddbc4..8db4a57b3d02 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.93.0 +1.94.0 From a57470ff727f5b527504d85b5eddfb2415ed9522 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Thu, 4 Dec 2025 14:33:47 +0000 Subject: [PATCH 346/585] Look for typos when reporting an unknown nightly feature --- .../rustc_parse/src/parser/diagnostics.rs | 24 +++++++-------- compiler/rustc_passes/messages.ftl | 2 ++ compiler/rustc_passes/src/errors.rs | 15 ++++++++++ compiler/rustc_passes/src/stability.rs | 30 +++++++++++++++---- compiler/rustc_span/src/symbol.rs | 22 ++++++++++++++ tests/ui/feature-gates/unknown-feature.rs | 4 ++- tests/ui/feature-gates/unknown-feature.stderr | 14 ++++++++- 7 files changed, 89 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index bd495f6ec1ac..d4667a09af6d 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -16,7 +16,6 @@ pluralize, }; use rustc_session::errors::ExprParenthesesNeeded; -use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::source_map::Spanned; use rustc_span::symbol::used_keywords; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, SpanSnippetError, Symbol, kw, sym}; @@ -222,6 +221,8 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { style = "verbose" )] struct MisspelledKw { + // We use a String here because `Symbol::into_diag_arg` calls `Symbol::to_ident_string`, which + // prefix the keyword with a `r#` because it aims to print the symbol as an identifier. similar_kw: String, #[primary_span] span: Span, @@ -229,20 +230,15 @@ struct MisspelledKw { } /// Checks if the given `lookup` identifier is similar to any keyword symbol in `candidates`. +/// +/// This is a specialized version of [`Symbol::find_similar`] that constructs an error when a +/// candidate is found. fn find_similar_kw(lookup: Ident, candidates: &[Symbol]) -> Option { - let lowercase = lookup.name.as_str().to_lowercase(); - let lowercase_sym = Symbol::intern(&lowercase); - if candidates.contains(&lowercase_sym) { - Some(MisspelledKw { similar_kw: lowercase, span: lookup.span, is_incorrect_case: true }) - } else if let Some(similar_sym) = find_best_match_for_name(candidates, lookup.name, None) { - Some(MisspelledKw { - similar_kw: similar_sym.to_string(), - span: lookup.span, - is_incorrect_case: false, - }) - } else { - None - } + lookup.name.find_similar(candidates).map(|(similar_kw, is_incorrect_case)| MisspelledKw { + similar_kw: similar_kw.to_string(), + is_incorrect_case, + span: lookup.span, + }) } struct MultiSugg { diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 09ac3ae1c3a9..70e91c081776 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -421,6 +421,8 @@ passes_missing_panic_handler = passes_missing_stability_attr = {$descr} has missing stability attribute +passes_misspelled_feature = there is a feature with a similar name: `{$actual_name}` + passes_mixed_export_name_and_no_mangle = `{$no_mangle_attr}` attribute may not be used in combination with `{$export_name_attr}` .label = `{$no_mangle_attr}` is ignored .note = `{$export_name_attr}` takes precedence diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index e4826cccd32f..6aa0f5212af7 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1183,6 +1183,21 @@ pub(crate) struct UnknownFeature { #[primary_span] pub span: Span, pub feature: Symbol, + #[subdiagnostic] + pub suggestion: Option, +} + +#[derive(Subdiagnostic)] +#[suggestion( + passes_misspelled_feature, + style = "verbose", + code = "{actual_name}", + applicability = "maybe-incorrect" +)] +pub(crate) struct MisspelledFeature { + #[primary_span] + pub span: Span, + pub actual_name: Symbol, } #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 39830db2b11d..9d94c4cc6225 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -6,7 +6,7 @@ use rustc_ast_lowering::stability::extern_abi_stability; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; -use rustc_feature::{EnabledLangFeature, EnabledLibFeature}; +use rustc_feature::{EnabledLangFeature, EnabledLibFeature, UNSTABLE_LANG_FEATURES}; use rustc_hir::attrs::{AttributeKind, DeprecatedSince}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; @@ -1062,11 +1062,13 @@ fn check_features<'tcx>( // no unknown features, because the collection also does feature attribute validation. let local_defined_features = tcx.lib_features(LOCAL_CRATE); if !remaining_lib_features.is_empty() || !remaining_implications.is_empty() { + let crates = tcx.crates(()); + // Loading the implications of all crates is unavoidable to be able to emit the partial // stabilization diagnostic, but it can be avoided when there are no // `remaining_lib_features`. let mut all_implications = remaining_implications.clone(); - for &cnum in tcx.crates(()) { + for &cnum in crates { all_implications .extend_unord(tcx.stability_implications(cnum).items().map(|(k, v)| (*k, *v))); } @@ -1079,7 +1081,7 @@ fn check_features<'tcx>( &all_implications, ); - for &cnum in tcx.crates(()) { + for &cnum in crates { if remaining_lib_features.is_empty() && remaining_implications.is_empty() { break; } @@ -1091,10 +1093,26 @@ fn check_features<'tcx>( &all_implications, ); } - } - for (feature, span) in remaining_lib_features { - tcx.dcx().emit_err(errors::UnknownFeature { span, feature }); + if !remaining_lib_features.is_empty() { + let lang_features = + UNSTABLE_LANG_FEATURES.iter().map(|feature| feature.name).collect::>(); + let lib_features = crates + .into_iter() + .flat_map(|&cnum| { + tcx.lib_features(cnum).stability.keys().copied().into_sorted_stable_ord() + }) + .collect::>(); + + let valid_feature_names = [lang_features, lib_features].concat(); + + for (feature, span) in remaining_lib_features { + let suggestion = feature + .find_similar(&valid_feature_names) + .map(|(actual_name, _)| errors::MisspelledFeature { span, actual_name }); + tcx.dcx().emit_err(errors::UnknownFeature { span, feature, suggestion }); + } + } } for (&implied_by, &feature) in remaining_implications.to_sorted_stable_ord() { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7e513160de0c..171539b42a6e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -14,6 +14,7 @@ use rustc_data_structures::sync::Lock; use rustc_macros::{Decodable, Encodable, HashStable_Generic, symbols}; +use crate::edit_distance::find_best_match_for_name; use crate::{DUMMY_SP, Edition, Span, with_session_globals}; #[cfg(test)] @@ -2843,6 +2844,27 @@ pub fn to_ident_string(self) -> String { // Avoid creating an empty identifier, because that asserts in debug builds. if self == sym::empty { String::new() } else { Ident::with_dummy_span(self).to_string() } } + + /// Checks if `self` is similar to any symbol in `candidates`. + /// + /// The returned boolean represents whether the candidate is the same symbol with a different + /// casing. + /// + /// All the candidates are assumed to be lowercase. + pub fn find_similar( + self, + candidates: &[Symbol], + ) -> Option<(Symbol, /* is incorrect case */ bool)> { + let lowercase = self.as_str().to_lowercase(); + let lowercase_sym = Symbol::intern(&lowercase); + if candidates.contains(&lowercase_sym) { + Some((lowercase_sym, true)) + } else if let Some(similar_sym) = find_best_match_for_name(candidates, self, None) { + Some((similar_sym, false)) + } else { + None + } + } } impl fmt::Debug for Symbol { diff --git a/tests/ui/feature-gates/unknown-feature.rs b/tests/ui/feature-gates/unknown-feature.rs index 2ecc9b82a48d..a9e8e046eb16 100644 --- a/tests/ui/feature-gates/unknown-feature.rs +++ b/tests/ui/feature-gates/unknown-feature.rs @@ -1,14 +1,16 @@ #![feature( unknown_rust_feature, //~^ ERROR unknown feature - + // Typo for lang feature associated_types_default, //~^ ERROR unknown feature + //~| HELP there is a feature with a similar name // Typo for lib feature core_intrnisics, //~^ ERROR unknown feature + //~| HELP there is a feature with a similar name )] fn main() {} diff --git a/tests/ui/feature-gates/unknown-feature.stderr b/tests/ui/feature-gates/unknown-feature.stderr index a0cadb3f817f..1e5b953e99ca 100644 --- a/tests/ui/feature-gates/unknown-feature.stderr +++ b/tests/ui/feature-gates/unknown-feature.stderr @@ -9,12 +9,24 @@ error[E0635]: unknown feature `associated_types_default` | LL | associated_types_default, | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: there is a feature with a similar name: `associated_type_defaults` + | +LL - associated_types_default, +LL + associated_type_defaults, + | error[E0635]: unknown feature `core_intrnisics` - --> $DIR/unknown-feature.rs:10:5 + --> $DIR/unknown-feature.rs:11:5 | LL | core_intrnisics, | ^^^^^^^^^^^^^^^ + | +help: there is a feature with a similar name: `core_intrinsics` + | +LL - core_intrnisics, +LL + core_intrinsics, + | error: aborting due to 3 previous errors From cf83387d2feefcb396f68b076d0210d764c9f733 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 5 Dec 2025 20:37:07 -0700 Subject: [PATCH 347/585] rustdoc: add test case for alias bug Reproduces --- .../rustdoc-merge-directory-alias/dep1.rs | 10 +++ .../rustdoc-merge-directory-alias/dep2.rs | 4 ++ .../rustdoc-merge-directory-alias/rmake.rs | 66 +++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 tests/run-make/rustdoc-merge-directory-alias/dep1.rs create mode 100644 tests/run-make/rustdoc-merge-directory-alias/dep2.rs create mode 100644 tests/run-make/rustdoc-merge-directory-alias/rmake.rs diff --git a/tests/run-make/rustdoc-merge-directory-alias/dep1.rs b/tests/run-make/rustdoc-merge-directory-alias/dep1.rs new file mode 100644 index 000000000000..d1b32ccc69de --- /dev/null +++ b/tests/run-make/rustdoc-merge-directory-alias/dep1.rs @@ -0,0 +1,10 @@ +pub struct Dep1; +pub struct Dep2; +pub struct Dep3; +pub struct Dep4; + +//@ hasraw crates.js 'dep1' +//@ hasraw search.index/name/*.js 'Dep1' +//@ has dep1/index.html +#[doc(alias="dep1_missing")] +pub struct Dep5; diff --git a/tests/run-make/rustdoc-merge-directory-alias/dep2.rs b/tests/run-make/rustdoc-merge-directory-alias/dep2.rs new file mode 100644 index 000000000000..2df4452413c2 --- /dev/null +++ b/tests/run-make/rustdoc-merge-directory-alias/dep2.rs @@ -0,0 +1,4 @@ +//@ hasraw crates.js 'dep2' +//@ hasraw search.index/name/*.js 'Second' +//@ has dep2/index.html +pub struct Second; diff --git a/tests/run-make/rustdoc-merge-directory-alias/rmake.rs b/tests/run-make/rustdoc-merge-directory-alias/rmake.rs new file mode 100644 index 000000000000..934e695826ac --- /dev/null +++ b/tests/run-make/rustdoc-merge-directory-alias/rmake.rs @@ -0,0 +1,66 @@ +// Running --merge=finalize without an input crate root should not trigger ICE. +// Issue: https://github.com/rust-lang/rust/issues/146646 + +//@ needs-target-std + +use run_make_support::{htmldocck, path, rustdoc}; + +fn main() { + let out_dir = path("out"); + let merged_dir = path("merged"); + let parts_out_dir = path("parts"); + + rustdoc() + .input("dep1.rs") + .out_dir(&out_dir) + .arg("-Zunstable-options") + .arg(format!("--parts-out-dir={}", parts_out_dir.display())) + .arg("--merge=none") + .run(); + assert!(parts_out_dir.join("dep1.json").exists()); + + let output = rustdoc() + .arg("-Zunstable-options") + .out_dir(&out_dir) + .arg(format!("--include-parts-dir={}", parts_out_dir.display())) + .arg("--merge=finalize") + .run(); + output.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug."); + + rustdoc() + .input("dep2.rs") + .out_dir(&out_dir) + .arg("-Zunstable-options") + .arg(format!("--parts-out-dir={}", parts_out_dir.display())) + .arg("--merge=none") + .run(); + assert!(parts_out_dir.join("dep2.json").exists()); + + let output2 = rustdoc() + .arg("-Zunstable-options") + .out_dir(&out_dir) + .arg(format!("--include-parts-dir={}", parts_out_dir.display())) + .arg("--merge=finalize") + .run(); + output2.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug."); + + rustdoc() + .input("dep1.rs") + .out_dir(&out_dir) + .arg("-Zunstable-options") + .arg(format!("--parts-out-dir={}", parts_out_dir.display())) + .arg("--merge=none") + .run(); + assert!(parts_out_dir.join("dep1.json").exists()); + + let output3 = rustdoc() + .arg("-Zunstable-options") + .out_dir(&out_dir) + .arg(format!("--include-parts-dir={}", parts_out_dir.display())) + .arg("--merge=finalize") + .run(); + output3.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug."); + + htmldocck().arg(&out_dir).arg("dep1.rs").run(); + htmldocck().arg(&out_dir).arg("dep2.rs").run(); +} From fb3a0895e0c806c57ca28e84d3aac9768696b940 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 5 Dec 2025 20:45:31 -0700 Subject: [PATCH 348/585] rustdoc: avoid dangling alias pointers after merge --- src/librustdoc/html/render/search_index.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index da6840c72f5b..777a0a95fc83 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -721,7 +721,13 @@ fn map_fn_sig_item(map: &FxHashMap, ty: &mut RenderType) { } }, ), - self.alias_pointers[id].and_then(|alias| map.get(&alias).copied()), + self.alias_pointers[id].and_then(|alias| { + if self.names[alias].is_empty() { + None + } else { + map.get(&alias).copied() + } + }), ); } new.generic_inverted_index = self From 38a2a3da3c9374eb11dbe63e68d57fb3315f869f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 5 Dec 2025 20:58:02 -0700 Subject: [PATCH 349/585] rustdoc: test for loading index when user said no Also mentioned, as a perf problem, in --- .../rustdoc-merge-directory-alias/dep1.rs | 2 +- .../dep_missing.rs | 4 ++++ .../rustdoc-merge-directory-alias/rmake.rs | 22 +++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/run-make/rustdoc-merge-directory-alias/dep_missing.rs diff --git a/tests/run-make/rustdoc-merge-directory-alias/dep1.rs b/tests/run-make/rustdoc-merge-directory-alias/dep1.rs index d1b32ccc69de..b62f31c982b7 100644 --- a/tests/run-make/rustdoc-merge-directory-alias/dep1.rs +++ b/tests/run-make/rustdoc-merge-directory-alias/dep1.rs @@ -6,5 +6,5 @@ //@ hasraw crates.js 'dep1' //@ hasraw search.index/name/*.js 'Dep1' //@ has dep1/index.html -#[doc(alias="dep1_missing")] +#[doc(alias = "dep1_missing")] pub struct Dep5; diff --git a/tests/run-make/rustdoc-merge-directory-alias/dep_missing.rs b/tests/run-make/rustdoc-merge-directory-alias/dep_missing.rs new file mode 100644 index 000000000000..74236aef47ea --- /dev/null +++ b/tests/run-make/rustdoc-merge-directory-alias/dep_missing.rs @@ -0,0 +1,4 @@ +//@ !hasraw crates.js 'dep_missing' +//@ !hasraw search.index/name/*.js 'DepMissing' +//@ has dep_missing/index.html +pub struct DepMissing; diff --git a/tests/run-make/rustdoc-merge-directory-alias/rmake.rs b/tests/run-make/rustdoc-merge-directory-alias/rmake.rs index 934e695826ac..096eb4a487c1 100644 --- a/tests/run-make/rustdoc-merge-directory-alias/rmake.rs +++ b/tests/run-make/rustdoc-merge-directory-alias/rmake.rs @@ -61,6 +61,28 @@ fn main() { .run(); output3.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug."); + // dep_missing is different, because --parts-out-dir is not supplied + rustdoc().input("dep_missing.rs").out_dir(&out_dir).run(); + assert!(parts_out_dir.join("dep2.json").exists()); + + rustdoc() + .input("dep1.rs") + .out_dir(&out_dir) + .arg("-Zunstable-options") + .arg(format!("--parts-out-dir={}", parts_out_dir.display())) + .arg("--merge=none") + .run(); + assert!(parts_out_dir.join("dep1.json").exists()); + + let output4 = rustdoc() + .arg("-Zunstable-options") + .out_dir(&out_dir) + .arg(format!("--include-parts-dir={}", parts_out_dir.display())) + .arg("--merge=finalize") + .run(); + output4.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug."); + htmldocck().arg(&out_dir).arg("dep1.rs").run(); htmldocck().arg(&out_dir).arg("dep2.rs").run(); + htmldocck().arg(&out_dir).arg("dep_missing.rs").run(); } From 6fb8d9fd92881ef06a49c253b0bb7f05c20431f4 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 5 Dec 2025 21:00:19 -0700 Subject: [PATCH 350/585] rustdoc: avoid loading index when user says no --- src/librustdoc/html/render/search_index.rs | 14 ++++++++------ src/librustdoc/html/render/write_shared.rs | 10 ++++++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 777a0a95fc83..a4cbef8c3917 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -24,6 +24,7 @@ use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate}; use crate::clean::{self, utils}; +use crate::config::ShouldMerge; use crate::error::Error; use crate::formats::cache::{Cache, OrphanImplItem}; use crate::formats::item_type::ItemType; @@ -722,11 +723,7 @@ fn map_fn_sig_item(map: &FxHashMap, ty: &mut RenderType) { }, ), self.alias_pointers[id].and_then(|alias| { - if self.names[alias].is_empty() { - None - } else { - map.get(&alias).copied() - } + if self.names[alias].is_empty() { None } else { map.get(&alias).copied() } }), ); } @@ -1254,6 +1251,7 @@ pub(crate) fn build_index( tcx: TyCtxt<'_>, doc_root: &Path, resource_suffix: &str, + should_merge: &ShouldMerge, ) -> Result { let mut search_index = std::mem::take(&mut cache.search_index); @@ -1304,7 +1302,11 @@ pub(crate) fn build_index( // // if there's already a search index, load it into memory and add the new entries to it // otherwise, do nothing - let mut serialized_index = SerializedSearchIndex::load(doc_root, resource_suffix)?; + let mut serialized_index = if should_merge.read_rendered_cci { + SerializedSearchIndex::load(doc_root, resource_suffix)? + } else { + SerializedSearchIndex::default() + }; // The crate always goes first in this list let crate_name = krate.name(tcx); diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 9a8df5393139..6bf116c3b75a 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -66,8 +66,14 @@ pub(crate) fn write_shared( // Write shared runs within a flock; disable thread dispatching of IO temporarily. let _lock = try_err!(flock::Lock::new(&lock_file, true, true, true), &lock_file); - let search_index = - build_index(krate, &mut cx.shared.cache, tcx, &cx.dst, &cx.shared.resource_suffix)?; + let search_index = build_index( + krate, + &mut cx.shared.cache, + tcx, + &cx.dst, + &cx.shared.resource_suffix, + &opt.should_merge, + )?; let crate_name = krate.name(cx.tcx()); let crate_name = crate_name.as_str(); // rand From de3100e56077343ae5491655b6162615ae573cfb Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 6 Dec 2025 04:53:34 +0000 Subject: [PATCH 351/585] Prepare for merging from rust-lang/rust This updates the rust-version file to 36b2369c91d32c2659887ed6fe3d570640f44fd2. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 45bf94eb4de4..b6a1415f1834 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -864339abf952f07098dd82610256338520167d4a +36b2369c91d32c2659887ed6fe3d570640f44fd2 From c5113ca1e2fd2eb24cd5ee1dc07f9ec224a7c2c9 Mon Sep 17 00:00:00 2001 From: EFanZh Date: Sat, 6 Dec 2025 12:55:15 +0800 Subject: [PATCH 352/585] Implement `Vec::from_fn` --- library/alloc/src/vec/mod.rs | 53 +++++++++++++++++++ tests/ui/suggestions/deref-path-method.stderr | 2 +- tests/ui/ufcs/bad-builder.stderr | 2 +- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 2adce8d27039..d2bc5d9bce39 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -745,6 +745,59 @@ pub unsafe fn from_parts(ptr: NonNull, length: usize, capacity: usize) -> Sel unsafe { Self::from_parts_in(ptr, length, capacity, Global) } } + /// Creates a `Vec` where each element is produced by calling `f` with + /// that element's index while walking forward through the `Vec`. + /// + /// This is essentially the same as writing + /// + /// ```text + /// vec![f(0), f(1), f(2), …, f(length - 2), f(length - 1)] + /// ``` + /// and is similar to `(0..i).map(f)`, just for `Vec`s not iterators. + /// + /// If `length == 0`, this produces an empty `Vec` without ever calling `f`. + /// + /// # Example + /// + /// ```rust + /// #![feature(vec_from_fn)] + /// + /// let vec = Vec::from_fn(5, |i| i); + /// + /// // indexes are: 0 1 2 3 4 + /// assert_eq!(vec, [0, 1, 2, 3, 4]); + /// + /// let vec2 = Vec::from_fn(8, |i| i * 2); + /// + /// // indexes are: 0 1 2 3 4 5 6 7 + /// assert_eq!(vec2, [0, 2, 4, 6, 8, 10, 12, 14]); + /// + /// let bool_vec = Vec::from_fn(5, |i| i % 2 == 0); + /// + /// // indexes are: 0 1 2 3 4 + /// assert_eq!(bool_vec, [true, false, true, false, true]); + /// ``` + /// + /// The `Vec` is generated in ascending index order, starting from the front + /// and going towards the back, so you can use closures with mutable state: + /// ``` + /// #![feature(vec_from_fn)] + /// + /// let mut state = 1; + /// let a = Vec::from_fn(6, |_| { let x = state; state *= 2; x }); + /// + /// assert_eq!(a, [1, 2, 4, 8, 16, 32]); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline] + #[unstable(feature = "vec_from_fn", reason = "new API", issue = "149698")] + pub fn from_fn(length: usize, f: F) -> Self + where + F: FnMut(usize) -> T, + { + (0..length).map(f).collect() + } + /// Decomposes a `Vec` into its raw components: `(pointer, length, capacity)`. /// /// Returns the raw pointer to the underlying data, the length of diff --git a/tests/ui/suggestions/deref-path-method.stderr b/tests/ui/suggestions/deref-path-method.stderr index dc2f6f66437e..0dec424555ed 100644 --- a/tests/ui/suggestions/deref-path-method.stderr +++ b/tests/ui/suggestions/deref-path-method.stderr @@ -9,7 +9,7 @@ note: if you're trying to build a new `Vec<_, _>` consider using one of the foll Vec::::with_capacity Vec::::try_with_capacity Vec::::from_raw_parts - and 6 others + and 7 others --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL help: the function `contains` is implemented on `[_]` | diff --git a/tests/ui/ufcs/bad-builder.stderr b/tests/ui/ufcs/bad-builder.stderr index a3528cb1e7d8..2504a3d09253 100644 --- a/tests/ui/ufcs/bad-builder.stderr +++ b/tests/ui/ufcs/bad-builder.stderr @@ -9,7 +9,7 @@ note: if you're trying to build a new `Vec` consider using one of the followi Vec::::with_capacity Vec::::try_with_capacity Vec::::from_raw_parts - and 6 others + and 7 others --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL help: there is an associated function `new` with a similar name | From 77825a264367ac4eafd4011e58a743411b687432 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Dec 2025 10:15:15 +0100 Subject: [PATCH 353/585] ubuntu riscv64 is broken even with extensive retries --- src/tools/miri/.github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index d6c702848494..4eeba3022892 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -31,13 +31,13 @@ jobs: os: ubuntu-24.04-arm multiarch: armhf gcc_cross: arm-linux-gnueabihf - - host_target: riscv64gc-unknown-linux-gnu - os: ubuntu-latest - multiarch: riscv64 - gcc_cross: riscv64-linux-gnu - qemu: true # Ubuntu mirrors are not reliable enough for these architectures # (see ). + # - host_target: riscv64gc-unknown-linux-gnu + # os: ubuntu-latest + # multiarch: riscv64 + # gcc_cross: riscv64-linux-gnu + # qemu: true # - host_target: s390x-unknown-linux-gnu # os: ubuntu-latest # multiarch: s390x From 71b093fd2c79a4de1354f8b00adba64d0bce25b6 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 5 Dec 2025 15:06:07 +0100 Subject: [PATCH 354/585] Emit `check-cfg` lints during attribute parsing rather than evaluation#149215 --- .../rustc_attr_parsing/src/attributes/cfg.rs | 82 +++++++------------ .../src/attributes/cfg_old.rs | 9 +- compiler/rustc_builtin_macros/src/cfg.rs | 8 +- .../rustc_builtin_macros/src/cfg_select.rs | 16 +--- compiler/rustc_codegen_ssa/src/back/link.rs | 7 +- compiler/rustc_expand/src/config.rs | 32 ++------ compiler/rustc_expand/src/expand.rs | 2 +- .../rustc_hir/src/attrs/data_structures.rs | 2 +- compiler/rustc_lint/src/early/diagnostics.rs | 16 ++-- compiler/rustc_lint_defs/src/lib.rs | 4 +- compiler/rustc_metadata/src/native_libs.rs | 7 +- compiler/rustc_resolve/src/diagnostics.rs | 2 +- 12 files changed, 64 insertions(+), 123 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index bd228315b2c9..490e28ed64c5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -2,16 +2,16 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; -use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, NodeId, ast, token}; +use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token}; use rustc_errors::{Applicability, PResult}; use rustc_feature::{AttrSuggestionStyle, AttributeTemplate, Features, template}; use rustc_hir::attrs::CfgEntry; +use rustc_hir::lints::AttributeLintKind; use rustc_hir::{AttrPath, RustcVersion}; use rustc_parse::parser::{ForceCollect, Parser}; use rustc_parse::{exp, parse_in}; use rustc_session::Session; use rustc_session::config::ExpectedValues; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::parse::{ParseSess, feature_err}; use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; @@ -23,10 +23,7 @@ AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg, ParsedDescription, }; -use crate::{ - AttributeParser, CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, - try_gate_cfg, -}; +use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics, try_gate_cfg}; pub const CFG_TEMPLATE: AttributeTemplate = template!( List: &["predicate"], @@ -195,43 +192,46 @@ fn parse_name_value( } }; - Ok(CfgEntry::NameValue { name, name_span, value, span }) + match cx.sess.psess.check_config.expecteds.get(&name) { + Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => cx + .emit_lint( + UNEXPECTED_CFGS, + AttributeLintKind::UnexpectedCfgValue((name, name_span), value), + span, + ), + None if cx.sess.psess.check_config.exhaustive_names => cx.emit_lint( + UNEXPECTED_CFGS, + AttributeLintKind::UnexpectedCfgName((name, name_span), value), + span, + ), + _ => { /* not unexpected */ } + } + + Ok(CfgEntry::NameValue { name, value: value.map(|(v, _)| v), span }) } -pub fn eval_config_entry( - sess: &Session, - cfg_entry: &CfgEntry, - id: NodeId, - emit_lints: ShouldEmit, -) -> EvalConfigResult { +pub fn eval_config_entry(sess: &Session, cfg_entry: &CfgEntry) -> EvalConfigResult { match cfg_entry { CfgEntry::All(subs, ..) => { - let mut all = None; for sub in subs { - let res = eval_config_entry(sess, sub, id, emit_lints); - // We cannot short-circuit because `eval_config_entry` emits some lints + let res = eval_config_entry(sess, sub); if !res.as_bool() { - all.get_or_insert(res); + return res; } } - all.unwrap_or_else(|| EvalConfigResult::True) + EvalConfigResult::True } CfgEntry::Any(subs, span) => { - let mut any = None; for sub in subs { - let res = eval_config_entry(sess, sub, id, emit_lints); - // We cannot short-circuit because `eval_config_entry` emits some lints + let res = eval_config_entry(sess, sub); if res.as_bool() { - any.get_or_insert(res); + return res; } } - any.unwrap_or_else(|| EvalConfigResult::False { - reason: cfg_entry.clone(), - reason_span: *span, - }) + EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } } CfgEntry::Not(sub, span) => { - if eval_config_entry(sess, sub, id, emit_lints).as_bool() { + if eval_config_entry(sess, sub).as_bool() { EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } } else { EvalConfigResult::True @@ -244,32 +244,8 @@ pub fn eval_config_entry( EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } } } - CfgEntry::NameValue { name, name_span, value, span } => { - if let ShouldEmit::ErrorsAndLints = emit_lints { - 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))) { + CfgEntry::NameValue { name, value, span } => { + if sess.psess.config.contains(&(*name, *value)) { EvalConfigResult::True } else { EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs index 70228d1e1510..adae3fa635f4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs @@ -2,6 +2,7 @@ use rustc_ast_pretty::pprust; use rustc_feature::{Features, GatedCfg, find_gated_cfg}; use rustc_hir::RustcVersion; +use rustc_hir::lints::AttributeLintKind; use rustc_session::Session; use rustc_session::config::ExpectedValues; use rustc_session::lint::builtin::UNEXPECTED_CFGS; @@ -51,10 +52,10 @@ pub fn cfg_matches( sess, UNEXPECTED_CFGS, cfg.span, - BuiltinLintDiag::UnexpectedCfgValue( + BuiltinLintDiag::AttributeLint(AttributeLintKind::UnexpectedCfgValue( (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), - ), + )), ); } None if sess.psess.check_config.exhaustive_names => { @@ -62,10 +63,10 @@ pub fn cfg_matches( sess, UNEXPECTED_CFGS, cfg.span, - BuiltinLintDiag::UnexpectedCfgName( + BuiltinLintDiag::AttributeLint(AttributeLintKind::UnexpectedCfgName( (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), - ), + )), ); } _ => { /* not unexpected */ } diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index b24e3065622d..7bc9080ba022 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -26,13 +26,7 @@ pub(crate) fn expand_cfg( ExpandResult::Ready(match parse_cfg(cx, sp, tts) { Ok(cfg) => { - let matches_cfg = attr::eval_config_entry( - cx.sess, - &cfg, - cx.current_expansion.lint_node_id, - ShouldEmit::ErrorsAndLints, - ) - .as_bool(); + let matches_cfg = attr::eval_config_entry(cx.sess, &cfg).as_bool(); MacEager::expr(cx.expr_bool(sp, matches_cfg)) } diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs index b77a121ca0b9..dc8077b2a1ff 100644 --- a/compiler/rustc_builtin_macros/src/cfg_select.rs +++ b/compiler/rustc_builtin_macros/src/cfg_select.rs @@ -1,7 +1,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_attr_parsing as attr; use rustc_attr_parsing::{ - CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, ShouldEmit, parse_cfg_select, + CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, parse_cfg_select, }; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_span::{Ident, Span, sym}; @@ -10,21 +10,13 @@ /// Selects the first arm whose predicate evaluates to true. fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> { - let mut result = None; for (cfg, tt, arm_span) in branches.reachable { - if let EvalConfigResult::True = attr::eval_config_entry( - &ecx.sess, - &cfg, - ecx.current_expansion.lint_node_id, - ShouldEmit::ErrorsAndLints, - ) { - // FIXME(#149215) Ideally we should short-circuit here, but `eval_config_entry` currently emits lints so we cannot do this yet. - result.get_or_insert((tt, arm_span)); + if let EvalConfigResult::True = attr::eval_config_entry(&ecx.sess, &cfg) { + return Some((tt, arm_span)); } } - let wildcard = branches.wildcard.map(|(_, tt, span)| (tt, span)); - result.or(wildcard) + branches.wildcard.map(|(_, tt, span)| (tt, span)) } pub(super) fn expand_cfg_select<'cx>( diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index d35c3b6bb189..70db6794742d 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -13,8 +13,7 @@ use itertools::Itertools; use regex::Regex; use rustc_arena::TypedArena; -use rustc_ast::CRATE_NODE_ID; -use rustc_attr_parsing::{ShouldEmit, eval_config_entry}; +use rustc_attr_parsing::eval_config_entry; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; @@ -3029,9 +3028,7 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { - Some(ref cfg) => { - eval_config_entry(sess, cfg, CRATE_NODE_ID, ShouldEmit::ErrorsAndLints).as_bool() - } + Some(ref cfg) => eval_config_entry(sess, cfg).as_bool(), None => true, } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 0b3ac472e0e8..492c845df171 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -163,10 +163,7 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec .iter() .flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)) .take_while(|attr| { - !is_cfg(attr) - || strip_unconfigured - .cfg_true(attr, strip_unconfigured.lint_node_id, ShouldEmit::Nothing) - .as_bool() + !is_cfg(attr) || strip_unconfigured.cfg_true(attr, ShouldEmit::Nothing).as_bool() }) .collect() } @@ -309,14 +306,7 @@ pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> V ); } - if !attr::eval_config_entry( - self.sess, - &cfg_predicate, - ast::CRATE_NODE_ID, - ShouldEmit::ErrorsAndLints, - ) - .as_bool() - { + if !attr::eval_config_entry(self.sess, &cfg_predicate).as_bool() { return vec![trace_attr]; } @@ -400,23 +390,17 @@ fn expand_cfg_attr_item( /// 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, self.lint_node_id, ShouldEmit::ErrorsAndLints).as_bool() - }) + attrs + .iter() + .all(|attr| !is_cfg(attr) || self.cfg_true(attr, ShouldEmit::ErrorsAndLints).as_bool()) } - pub(crate) fn cfg_true( - &self, - attr: &Attribute, - node: NodeId, - emit_errors: ShouldEmit, - ) -> EvalConfigResult { + pub(crate) fn cfg_true(&self, attr: &Attribute, emit_errors: ShouldEmit) -> EvalConfigResult { let Some(cfg) = AttributeParser::parse_single( self.sess, attr, attr.span, - node, + self.lint_node_id, self.features, emit_errors, parse_cfg, @@ -426,7 +410,7 @@ pub(crate) fn cfg_true( return EvalConfigResult::True; }; - eval_config_entry(self.sess, &cfg, self.lint_node_id, emit_errors) + eval_config_entry(self.sess, &cfg) } /// If attributes are not allowed on expressions, emit an error for `attr` diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 20fb321307ac..90563b21d2e8 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -2213,7 +2213,7 @@ fn expand_cfg_true( attr: ast::Attribute, pos: usize, ) -> EvalConfigResult { - let res = self.cfg().cfg_true(&attr, node.node_id(), ShouldEmit::ErrorsAndLints); + let res = self.cfg().cfg_true(&attr, ShouldEmit::ErrorsAndLints); 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. diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index d3cc1dd6cf75..aff79d055838 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -190,7 +190,7 @@ pub enum CfgEntry { Any(ThinVec, Span), Not(Box, Span), Bool(bool, Span), - NameValue { name: Symbol, name_span: Span, value: Option<(Symbol, Span)>, span: Span }, + NameValue { name: Symbol, value: Option, span: Span }, Version(Option, Span), } diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index b654bc848ecf..5345c9a4a985 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -169,12 +169,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::UnexpectedCfgName(name, value) => { - check_cfg::unexpected_cfg_name(sess, tcx, name, value).decorate_lint(diag); - } - BuiltinLintDiag::UnexpectedCfgValue(name, value) => { - check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag); - } BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => { let suggestion = match sugg { Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd { @@ -307,8 +301,8 @@ pub fn decorate_builtin_lint( } pub fn decorate_attribute_lint( - _sess: &Session, - _tcx: Option>, + sess: &Session, + tcx: Option>, kind: &AttributeLintKind, diag: &mut Diag<'_, ()>, ) { @@ -364,5 +358,11 @@ pub fn decorate_attribute_lint( suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }, } .decorate_lint(diag), + &AttributeLintKind::UnexpectedCfgName(name, value) => { + check_cfg::unexpected_cfg_name(sess, tcx, name, value).decorate_lint(diag) + } + &AttributeLintKind::UnexpectedCfgValue(name, value) => { + check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag) + } } } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 3c6e7d04a29d..cc4062775ad3 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -636,8 +636,6 @@ pub enum BuiltinLintDiag { }, BreakWithLabelAndLoop(Span), UnicodeTextFlow(Span, String), - UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), - UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), DeprecatedWhereclauseLocation(Span, Option<(Span, String)>), SingleUseLifetime { /// Span of the parameter which declares this lifetime. @@ -732,6 +730,8 @@ pub enum AttributeLintKind { attribute_name_span: Span, sugg_spans: (Span, Span), }, + UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), + UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), } pub type RegisteredTools = FxIndexSet; diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 250657bc6806..e08460c3d4c9 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -2,8 +2,7 @@ use std::path::{Path, PathBuf}; use rustc_abi::ExternAbi; -use rustc_ast::CRATE_NODE_ID; -use rustc_attr_parsing::{ShouldEmit, eval_config_entry}; +use rustc_attr_parsing::eval_config_entry; use rustc_data_structures::fx::FxHashSet; use rustc_hir::attrs::{AttributeKind, NativeLibKind, PeImportNameType}; use rustc_hir::find_attr; @@ -188,9 +187,7 @@ pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { - Some(ref cfg) => { - eval_config_entry(sess, cfg, CRATE_NODE_ID, ShouldEmit::ErrorsAndLints).as_bool() - } + Some(ref cfg) => eval_config_entry(sess, cfg).as_bool(), None => true, } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 33c111708e36..a675c62ddf70 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -3070,7 +3070,7 @@ fn comes_from_same_module_for_glob( continue; } - let item_was = if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 { + let item_was = if let CfgEntry::NameValue { value: Some(feature), .. } = cfg.0 { errors::ItemWas::BehindFeature { feature, span: cfg.1 } } else { errors::ItemWas::CfgOut { span: cfg.1 } From e7df90412c208f3e18af8ed60781a343dd87645a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 5 Dec 2025 15:08:04 +0100 Subject: [PATCH 355/585] Changes to uitests --- .../ui/feature-gates/feature-gate-link_cfg.rs | 2 +- .../feature-gate-link_cfg.stderr | 4 ++-- tests/ui/link-native-libs/link-cfg-works.rs | 2 +- tests/ui/macros/cfg.rs | 3 ++- tests/ui/macros/cfg.stderr | 17 ++++++++++--- tests/ui/macros/cfg_select.rs | 2 ++ tests/ui/macros/cfg_select.stderr | 24 +++++++++++++++++-- 7 files changed, 44 insertions(+), 10 deletions(-) diff --git a/tests/ui/feature-gates/feature-gate-link_cfg.rs b/tests/ui/feature-gates/feature-gate-link_cfg.rs index d30ee3bcfdb1..286c3d0a4977 100644 --- a/tests/ui/feature-gates/feature-gate-link_cfg.rs +++ b/tests/ui/feature-gates/feature-gate-link_cfg.rs @@ -1,4 +1,4 @@ -#[link(name = "foo", cfg(foo))] +#[link(name = "foo", cfg(false))] //~^ ERROR: is unstable extern "C" {} diff --git a/tests/ui/feature-gates/feature-gate-link_cfg.stderr b/tests/ui/feature-gates/feature-gate-link_cfg.stderr index bfe7f74a9213..0e9707c6c962 100644 --- a/tests/ui/feature-gates/feature-gate-link_cfg.stderr +++ b/tests/ui/feature-gates/feature-gate-link_cfg.stderr @@ -1,8 +1,8 @@ error[E0658]: link cfg is unstable --> $DIR/feature-gate-link_cfg.rs:1:22 | -LL | #[link(name = "foo", cfg(foo))] - | ^^^^^^^^ +LL | #[link(name = "foo", cfg(false))] + | ^^^^^^^^^^ | = help: add `#![feature(link_cfg)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/link-native-libs/link-cfg-works.rs b/tests/ui/link-native-libs/link-cfg-works.rs index 7b936bc43b1a..0e02933ce01c 100644 --- a/tests/ui/link-native-libs/link-cfg-works.rs +++ b/tests/ui/link-native-libs/link-cfg-works.rs @@ -7,7 +7,7 @@ extern crate link_cfg_works_transitive_dylib; extern crate link_cfg_works_transitive_rlib; -#[link(name = "foo", cfg(foo))] +#[link(name = "foo", cfg(false))] extern "C" {} fn main() {} diff --git a/tests/ui/macros/cfg.rs b/tests/ui/macros/cfg.rs index d992ec82e2fd..f0c51b2942f1 100644 --- a/tests/ui/macros/cfg.rs +++ b/tests/ui/macros/cfg.rs @@ -2,5 +2,6 @@ fn main() { cfg!(); //~ ERROR macro requires a cfg-pattern cfg!(123); //~ ERROR malformed `cfg` macro input cfg!(foo = 123); //~ ERROR malformed `cfg` macro input - cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern + cfg!(false, false); //~ ERROR expected 1 cfg-pattern + cfg!(foo); //~ WARN unexpected `cfg` condition name: `foo` } diff --git a/tests/ui/macros/cfg.stderr b/tests/ui/macros/cfg.stderr index 9a4c187f37b2..06529a5b7a61 100644 --- a/tests/ui/macros/cfg.stderr +++ b/tests/ui/macros/cfg.stderr @@ -29,9 +29,20 @@ LL | cfg!(foo = 123); error: expected 1 cfg-pattern --> $DIR/cfg.rs:5:5 | -LL | cfg!(foo, bar); - | ^^^^^^^^^^^^^^ +LL | cfg!(false, false); + | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +warning: unexpected `cfg` condition name: `foo` + --> $DIR/cfg.rs:6:10 + | +LL | cfg!(foo); + | ^^^ + | + = help: expected names are: `FALSE` and `test` and 31 more + = help: to expect this configuration use `--check-cfg=cfg(foo)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/macros/cfg_select.rs b/tests/ui/macros/cfg_select.rs index 2a627cc05b93..a54c385747fa 100644 --- a/tests/ui/macros/cfg_select.rs +++ b/tests/ui/macros/cfg_select.rs @@ -89,9 +89,11 @@ fn arm_rhs_expr_3() -> i32 { cfg_select! { a + 1 => {} //~^ ERROR expected one of `(`, `::`, `=>`, or `=`, found `+` + //~| WARN unexpected `cfg` condition name } cfg_select! { cfg!() => {} //~^ ERROR expected one of `(`, `::`, `=>`, or `=`, found `!` + //~| WARN unexpected `cfg` condition name } diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr index 3a5d2b0a1e1e..d79e1b9b5c10 100644 --- a/tests/ui/macros/cfg_select.stderr +++ b/tests/ui/macros/cfg_select.stderr @@ -60,12 +60,32 @@ LL | a + 1 => {} | ^ expected one of `(`, `::`, `=>`, or `=` error: expected one of `(`, `::`, `=>`, or `=`, found `!` - --> $DIR/cfg_select.rs:95:8 + --> $DIR/cfg_select.rs:96:8 | LL | cfg!() => {} | ^ expected one of `(`, `::`, `=>`, or `=` -error: aborting due to 9 previous errors; 1 warning emitted +warning: unexpected `cfg` condition name: `a` + --> $DIR/cfg_select.rs:90:5 + | +LL | a + 1 => {} + | ^ help: found config with similar value: `target_feature = "a"` + | + = help: expected names are: `FALSE` and `test` and 31 more + = help: to expect this configuration use `--check-cfg=cfg(a)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name: `cfg` + --> $DIR/cfg_select.rs:96:5 + | +LL | cfg!() => {} + | ^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(cfg)` + = note: see for more information about checking conditional configuration + +error: aborting due to 9 previous errors; 3 warnings emitted Some errors have detailed explanations: E0537, E0539. For more information about an error, try `rustc --explain E0537`. From 01576a6de101ca85a8b43f2c3db2028c876a355c Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 6 Dec 2025 10:38:15 +0100 Subject: [PATCH 356/585] Add regression test for nested cfgs --- tests/ui/check-cfg/nested-cfg.rs | 8 ++++++++ tests/ui/check-cfg/nested-cfg.stderr | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/ui/check-cfg/nested-cfg.rs create mode 100644 tests/ui/check-cfg/nested-cfg.stderr diff --git a/tests/ui/check-cfg/nested-cfg.rs b/tests/ui/check-cfg/nested-cfg.rs new file mode 100644 index 000000000000..2b3a21f88dc5 --- /dev/null +++ b/tests/ui/check-cfg/nested-cfg.rs @@ -0,0 +1,8 @@ +//@ check-pass + +#[cfg(unknown)] //~ WARN unexpected `cfg` condition name +#[cfg(false)] +#[cfg(unknown)] // Should not warn +fn foo() {} + +fn main() {} diff --git a/tests/ui/check-cfg/nested-cfg.stderr b/tests/ui/check-cfg/nested-cfg.stderr new file mode 100644 index 000000000000..6fdae732bbe5 --- /dev/null +++ b/tests/ui/check-cfg/nested-cfg.stderr @@ -0,0 +1,23 @@ +warning: unexpected `cfg` condition name: `unknown` + --> $DIR/nested-cfg.rs:3:7 + | +LL | #[cfg(unknown)] + | ^^^^^^^ + | + = help: expected names are: `FALSE` and `test` and 31 more + = help: to expect this configuration use `--check-cfg=cfg(unknown)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default +help: found config with similar value + | +LL - #[cfg(unknown)] +LL + #[cfg(target_os = "unknown")] + | +help: found config with similar value + | +LL - #[cfg(unknown)] +LL + #[cfg(target_vendor = "unknown")] + | + +warning: 1 warning emitted + From 1647f4495515c0dc327f7de431ebaafd1c80d7d8 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 21 Nov 2025 15:44:14 +0200 Subject: [PATCH 357/585] feat: Support fstat in linux refactor: rename `macos_fbsd_solarish_write_stat_buf` to `write_stat_buf` refactor: rename `macos_fbsd_solarish_fstat` to `fstat` feat: support `fstat` in linux test: testing support of `fstat` in linux fix: missed add `Os::Linux` for supported OSs in `fstat` feat: add nanosecond fields to file metadata in `EvalContextExtPrivate` add `fstat` to foreign items in unix enhance test of `fstat` fix the test --- .../miri/src/shims/unix/foreign_items.rs | 5 +++ .../src/shims/unix/freebsd/foreign_items.rs | 2 +- src/tools/miri/src/shims/unix/fs.rs | 28 +++++++-------- .../src/shims/unix/linux/foreign_items.rs | 6 +++- .../src/shims/unix/macos/foreign_items.rs | 4 +-- .../src/shims/unix/solarish/foreign_items.rs | 2 +- src/tools/miri/tests/pass-dep/libc/libc-fs.rs | 34 +++++++++++++++++++ 7 files changed, 61 insertions(+), 20 deletions(-) diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 114f1a321faa..95a0a063bfdd 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -345,6 +345,11 @@ fn emulate_foreign_item_inner( let result = this.symlink(target, linkpath)?; this.write_scalar(result, dest)?; } + "fstat" => { + let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let result = this.fstat(fd, buf)?; + this.write_scalar(result, dest)?; + } "rename" => { let [oldpath, newpath] = this.check_shim_sig( shim_sig!(extern "C" fn(*const _, *const _) -> i32), diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 413df85ee3aa..2a1969049cf7 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -150,7 +150,7 @@ fn emulate_foreign_item_inner( } "fstat" | "fstat@FBSD_1.0" => { let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.macos_fbsd_solarish_fstat(fd, buf)?; + let result = this.fstat(fd, buf)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r@FBSD_1.0" => { diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 16214d7ef14e..0b98ab34917d 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -118,7 +118,7 @@ fn flock<'tcx>( impl<'tcx> EvalContextExtPrivate<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn macos_fbsd_solarish_write_stat_buf( + fn write_stat_buf( &mut self, metadata: FileMetadata, buf_op: &OpTy<'tcx>, @@ -141,8 +141,11 @@ fn macos_fbsd_solarish_write_stat_buf( ("st_gid", metadata.gid.into()), ("st_rdev", 0), ("st_atime", access_sec.into()), + ("st_atime_nsec", access_nsec.into()), ("st_mtime", modified_sec.into()), + ("st_mtime_nsec", modified_nsec.into()), ("st_ctime", 0), + ("st_ctime_nsec", 0), ("st_size", metadata.size.into()), ("st_blocks", 0), ("st_blksize", 0), @@ -550,7 +553,7 @@ fn macos_fbsd_solarish_stat( Err(err) => return this.set_last_error_and_return_i32(err), }; - interp_ok(Scalar::from_i32(this.macos_fbsd_solarish_write_stat_buf(metadata, buf_op)?)) + interp_ok(Scalar::from_i32(this.write_stat_buf(metadata, buf_op)?)) } // `lstat` is used to get symlink metadata. @@ -583,22 +586,17 @@ fn macos_fbsd_solarish_lstat( Err(err) => return this.set_last_error_and_return_i32(err), }; - interp_ok(Scalar::from_i32(this.macos_fbsd_solarish_write_stat_buf(metadata, buf_op)?)) + interp_ok(Scalar::from_i32(this.write_stat_buf(metadata, buf_op)?)) } - fn macos_fbsd_solarish_fstat( - &mut self, - fd_op: &OpTy<'tcx>, - buf_op: &OpTy<'tcx>, - ) -> InterpResult<'tcx, Scalar> { + fn fstat(&mut self, fd_op: &OpTy<'tcx>, buf_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - if !matches!(&this.tcx.sess.target.os, Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos) - { - panic!( - "`macos_fbsd_solaris_fstat` should not be called on {}", - this.tcx.sess.target.os - ); + if !matches!( + &this.tcx.sess.target.os, + Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos | Os::Linux + ) { + panic!("`fstat` should not be called on {}", this.tcx.sess.target.os); } let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -614,7 +612,7 @@ fn macos_fbsd_solarish_fstat( Ok(metadata) => metadata, Err(err) => return this.set_last_error_and_return_i32(err), }; - interp_ok(Scalar::from_i32(this.macos_fbsd_solarish_write_stat_buf(metadata, buf_op)?)) + interp_ok(Scalar::from_i32(this.write_stat_buf(metadata, buf_op)?)) } fn linux_statx( diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 79052698f4ba..5ced0b7f32ef 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -53,7 +53,11 @@ fn emulate_foreign_item_inner( let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; this.write_scalar(result, dest)?; } - + "fstat" => { + let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let result = this.fstat(fd, buf)?; + this.write_scalar(result, dest)?; + } // epoll, eventfd "epoll_create1" => { let [flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 1b273593de63..731b9aa5d55f 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -56,9 +56,9 @@ fn emulate_foreign_item_inner( let result = this.macos_fbsd_solarish_lstat(path, buf)?; this.write_scalar(result, dest)?; } - "fstat" | "fstat64" | "fstat$INODE64" => { + "fstat$INODE64" => { let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.macos_fbsd_solarish_fstat(fd, buf)?; + let result = this.fstat(fd, buf)?; this.write_scalar(result, dest)?; } "opendir$INODE64" => { diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index 6335e6bc9662..d081a1f2d028 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -102,7 +102,7 @@ fn emulate_foreign_item_inner( } "fstat" | "fstat64" => { let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.macos_fbsd_solarish_fstat(fd, buf)?; + let result = this.fstat(fd, buf)?; this.write_scalar(result, dest)?; } "readdir" => { diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index 41c3e3a12246..b1872e807653 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -42,6 +42,7 @@ fn main() { test_posix_fallocate::(libc::posix_fallocate64); #[cfg(target_os = "linux")] test_sync_file_range(); + test_fstat(); test_isatty(); test_read_and_uninit(); test_nofollow_not_symlink(); @@ -452,6 +453,39 @@ fn test_sync_file_range() { assert_eq!(result_2, 0); } +fn test_fstat() { + use std::mem::MaybeUninit; + use std::os::unix::io::AsRawFd; + + let path = utils::prepare_with_content("miri_test_libc_fstat.txt", b"hello"); + let file = File::open(&path).unwrap(); + let fd = file.as_raw_fd(); + + let mut stat: libc::stat = unsafe { MaybeUninit::zeroed().assume_init() }; + let res = unsafe { libc::fstat(fd, &mut stat) }; + assert_eq!(res, 0); + + assert_eq!(stat.st_size, 5); + assert_eq!(stat.st_mode & libc::S_IFMT, libc::S_IFREG); + + let _st_nlink = stat.st_nlink; + let _st_blksize = stat.st_blksize; + let _st_blocks = stat.st_blocks; + let _st_ino = stat.st_ino; + let _st_dev = stat.st_dev; + let _st_uid = stat.st_uid; + let _st_gid = stat.st_gid; + let _st_rdev = stat.st_rdev; + let _st_atime = stat.st_atime; + let _st_mtime = stat.st_mtime; + let _st_ctime = stat.st_ctime; + let _st_atime_nsec = stat.st_atime_nsec; + let _st_mtime_nsec = stat.st_mtime_nsec; + let _st_ctime_nsec = stat.st_ctime_nsec; + + remove_file(&path).unwrap(); +} + fn test_isatty() { // Testing whether our isatty shim returns the right value would require controlling whether // these streams are actually TTYs, which is hard. From 8b9d1d7d80cc506ba25768eda5c9eabba3def7e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Dec 2025 11:23:47 +0100 Subject: [PATCH 358/585] use correct stat type and fix some redundancy --- src/tools/miri/src/shims/unix/freebsd/foreign_items.rs | 2 +- src/tools/miri/src/shims/unix/fs.rs | 9 +++++---- src/tools/miri/src/shims/unix/linux/foreign_items.rs | 5 ----- src/tools/miri/src/shims/unix/solarish/foreign_items.rs | 5 ----- src/tools/miri/tests/pass-dep/libc/libc-fs.rs | 6 ++++-- 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 2a1969049cf7..9f7a19269c17 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -148,7 +148,7 @@ fn emulate_foreign_item_inner( let result = this.macos_fbsd_solarish_lstat(path, buf)?; this.write_scalar(result, dest)?; } - "fstat" | "fstat@FBSD_1.0" => { + "fstat@FBSD_1.0" => { let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.fstat(fd, buf)?; this.write_scalar(result, dest)?; diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 0b98ab34917d..8329cd47bb76 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -130,7 +130,11 @@ fn write_stat_buf( let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); let mode = metadata.mode.to_uint(this.libc_ty_layout("mode_t").size)?; - let buf = this.deref_pointer_as(buf_op, this.libc_ty_layout("stat"))?; + // We do *not* use `deref_pointer_as` here since determining the right pointee type + // is highly non-trivial: it depends on which exact alias of the function was invoked + // (e.g. `fstat` vs `fstat64`), and then on FreeBSD it also depends on the ABI level + // which can be different between the libc used by std and the libc used by everyone else. + let buf = this.deref_pointer(buf_op)?; this.write_int_fields_named( &[ ("st_dev", metadata.dev.into()), @@ -156,9 +160,6 @@ fn write_stat_buf( if matches!(&this.tcx.sess.target.os, Os::MacOs | Os::FreeBsd) { this.write_int_fields_named( &[ - ("st_atime_nsec", access_nsec.into()), - ("st_mtime_nsec", modified_nsec.into()), - ("st_ctime_nsec", 0), ("st_birthtime", created_sec.into()), ("st_birthtime_nsec", created_nsec.into()), ("st_flags", 0), diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 5ced0b7f32ef..4c76b08a454e 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -53,11 +53,6 @@ fn emulate_foreign_item_inner( let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; this.write_scalar(result, dest)?; } - "fstat" => { - let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.fstat(fd, buf)?; - this.write_scalar(result, dest)?; - } // epoll, eventfd "epoll_create1" => { let [flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index d081a1f2d028..b5eca70c3bf0 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -100,11 +100,6 @@ fn emulate_foreign_item_inner( let result = this.macos_fbsd_solarish_lstat(path, buf)?; this.write_scalar(result, dest)?; } - "fstat" | "fstat64" => { - let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.fstat(fd, buf)?; - this.write_scalar(result, dest)?; - } "readdir" => { let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.readdir64("dirent", dirp)?; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index b1872e807653..3a4ac2a1b3ee 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -461,13 +461,15 @@ fn test_fstat() { let file = File::open(&path).unwrap(); let fd = file.as_raw_fd(); - let mut stat: libc::stat = unsafe { MaybeUninit::zeroed().assume_init() }; - let res = unsafe { libc::fstat(fd, &mut stat) }; + let mut stat = MaybeUninit::::uninit(); + let res = unsafe { libc::fstat(fd, stat.as_mut_ptr()) }; assert_eq!(res, 0); + let stat = unsafe { stat.assume_init_ref() }; assert_eq!(stat.st_size, 5); assert_eq!(stat.st_mode & libc::S_IFMT, libc::S_IFREG); + // Check that all fields are initialized. let _st_nlink = stat.st_nlink; let _st_blksize = stat.st_blksize; let _st_blocks = stat.st_blocks; From 44aaae38ac858cda6491c62cd8e897bb6e566f86 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Dec 2025 11:41:11 +0100 Subject: [PATCH 359/585] remove readdir_r on FreeBSD: it is deprecated, unused, and untested --- .../src/shims/unix/freebsd/foreign_items.rs | 6 ---- src/tools/miri/src/shims/unix/fs.rs | 33 +++---------------- .../src/shims/unix/macos/foreign_items.rs | 2 +- 3 files changed, 5 insertions(+), 36 deletions(-) diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 9f7a19269c17..c48301c72416 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -153,12 +153,6 @@ fn emulate_foreign_item_inner( let result = this.fstat(fd, buf)?; this.write_scalar(result, dest)?; } - "readdir_r" | "readdir_r@FBSD_1.0" => { - let [dirp, entry, result] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; - this.write_scalar(result, dest)?; - } "readdir" | "readdir@FBSD_1.0" => { let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.readdir64("dirent", dirp)?; diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 8329cd47bb76..650972be5574 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -1030,7 +1030,7 @@ fn readdir64(&mut self, dirent_type: &str, dirp_op: &OpTy<'tcx>) -> InterpResult interp_ok(Scalar::from_maybe_pointer(entry.unwrap_or_else(Pointer::null), this)) } - fn macos_fbsd_readdir_r( + fn macos_readdir_r( &mut self, dirp_op: &OpTy<'tcx>, entry_op: &OpTy<'tcx>, @@ -1038,9 +1038,7 @@ fn macos_fbsd_readdir_r( ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - if !matches!(&this.tcx.sess.target.os, Os::MacOs | Os::FreeBsd) { - panic!("`macos_fbsd_readdir_r` should not be called on {}", this.tcx.sess.target.os); - } + this.assert_target_os(Os::MacOs, "readdir_r"); let dirp = this.read_target_usize(dirp_op)?; let result_place = this.deref_pointer_as(result_op, this.machine.layouts.mut_raw_ptr)?; @@ -1096,39 +1094,16 @@ fn macos_fbsd_readdir_r( let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - // Common fields. this.write_int_fields_named( &[ ("d_reclen", 0), ("d_namlen", file_name_len.into()), ("d_type", file_type.into()), + ("d_ino", ino.into()), + ("d_seekoff", 0), ], &entry_place, )?; - // Special fields. - match this.tcx.sess.target.os { - Os::MacOs => { - #[rustfmt::skip] - this.write_int_fields_named( - &[ - ("d_ino", ino.into()), - ("d_seekoff", 0), - ], - &entry_place, - )?; - } - Os::FreeBsd => { - #[rustfmt::skip] - this.write_int_fields_named( - &[ - ("d_fileno", ino.into()), - ("d_off", 0), - ], - &entry_place, - )?; - } - _ => unreachable!(), - } this.write_scalar(this.read_scalar(entry_op)?, &result_place)?; Scalar::from_i32(0) diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 731b9aa5d55f..6e1b554afda6 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -69,7 +69,7 @@ fn emulate_foreign_item_inner( "readdir_r" | "readdir_r$INODE64" => { let [dirp, entry, result] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; + let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(result, dest)?; } "realpath$DARWIN_EXTSN" => { From a26b26ac6f44c9be593929545088e329dd6428df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Dec 2025 11:46:38 +0100 Subject: [PATCH 360/585] cleanup: the *64 functions are Linux-specific --- .../miri/src/shims/unix/foreign_items.rs | 71 +----------------- .../src/shims/unix/linux/foreign_items.rs | 74 +++++++++++++++++++ .../src/shims/unix/macos/foreign_items.rs | 4 +- .../src/shims/unix/solarish/foreign_items.rs | 4 +- src/tools/miri/tests/pass-dep/libc/libc-fs.rs | 2 +- 5 files changed, 80 insertions(+), 75 deletions(-) diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 95a0a063bfdd..378a8537fc73 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -235,33 +235,6 @@ fn emulate_foreign_item_inner( trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset); this.write(fd, buf, count, Some(offset), dest)?; } - "pread64" => { - let [fd, buf, count, offset] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off64_t) -> isize), - link_name, - abi, - args, - )?; - let fd = this.read_scalar(fd)?.to_i32()?; - let buf = this.read_pointer(buf)?; - let count = this.read_target_usize(count)?; - let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?; - this.read(fd, buf, count, Some(offset), dest)?; - } - "pwrite64" => { - let [fd, buf, n, offset] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, usize, libc::off64_t) -> isize), - link_name, - abi, - args, - )?; - let fd = this.read_scalar(fd)?.to_i32()?; - let buf = this.read_pointer(buf)?; - let count = this.read_target_usize(n)?; - let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?; - trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset); - this.write(fd, buf, count, Some(offset), dest)?; - } "close" => { let [fd] = this.check_shim_sig( shim_sig!(extern "C" fn(i32) -> i32), @@ -317,7 +290,7 @@ fn emulate_foreign_item_inner( } // File and file system access - "open" | "open64" => { + "open" => { // `open` is variadic, the third argument is only present when the second argument // has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set let ([path_raw, flag], varargs) = @@ -400,18 +373,6 @@ fn emulate_foreign_item_inner( let result = this.closedir(dirp)?; this.write_scalar(result, dest)?; } - "lseek64" => { - let [fd, offset, whence] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t), - link_name, - abi, - args, - )?; - let fd = this.read_scalar(fd)?.to_i32()?; - let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?; - let whence = this.read_scalar(whence)?.to_i32()?; - this.lseek64(fd, offset, whence, dest)?; - } "lseek" => { let [fd, offset, whence] = this.check_shim_sig( shim_sig!(extern "C" fn(i32, libc::off_t, i32) -> libc::off_t), @@ -424,18 +385,6 @@ fn emulate_foreign_item_inner( let whence = this.read_scalar(whence)?.to_i32()?; this.lseek64(fd, offset, whence, dest)?; } - "ftruncate64" => { - let [fd, length] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, libc::off64_t) -> i32), - link_name, - abi, - args, - )?; - let fd = this.read_scalar(fd)?.to_i32()?; - let length = this.read_scalar(length)?.to_int(length.layout.size)?; - let result = this.ftruncate64(fd, length)?; - this.write_scalar(result, dest)?; - } "ftruncate" => { let [fd, length] = this.check_shim_sig( shim_sig!(extern "C" fn(i32, libc::off_t) -> i32), @@ -516,24 +465,6 @@ fn emulate_foreign_item_inner( this.write_scalar(result, dest)?; } - "posix_fallocate64" => { - // posix_fallocate64 is only supported on Linux and Android - this.check_target_os(&[Os::Linux, Os::Android], link_name)?; - let [fd, offset, len] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, libc::off64_t, libc::off64_t) -> i32), - link_name, - abi, - args, - )?; - - let fd = this.read_scalar(fd)?.to_i32()?; - let offset = this.read_scalar(offset)?.to_i64()?; - let len = this.read_scalar(len)?.to_i64()?; - - let result = this.posix_fallocate(fd, offset, len)?; - this.write_scalar(result, dest)?; - } - "realpath" => { let [path, resolved_path] = this.check_shim_sig( shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _), diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 4c76b08a454e..a7cb2ed11b2b 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -36,6 +36,80 @@ fn emulate_foreign_item_inner( match link_name.as_str() { // File related shims + "open64" => { + // `open64` is variadic, the third argument is only present when the second argument + // has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set + let ([path_raw, flag], varargs) = + this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?; + let result = this.open(path_raw, flag, varargs)?; + this.write_scalar(result, dest)?; + } + "pread64" => { + let [fd, buf, count, offset] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off64_t) -> isize), + link_name, + abi, + args, + )?; + let fd = this.read_scalar(fd)?.to_i32()?; + let buf = this.read_pointer(buf)?; + let count = this.read_target_usize(count)?; + let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?; + this.read(fd, buf, count, Some(offset), dest)?; + } + "pwrite64" => { + let [fd, buf, n, offset] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *const _, usize, libc::off64_t) -> isize), + link_name, + abi, + args, + )?; + let fd = this.read_scalar(fd)?.to_i32()?; + let buf = this.read_pointer(buf)?; + let count = this.read_target_usize(n)?; + let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?; + trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset); + this.write(fd, buf, count, Some(offset), dest)?; + } + "lseek64" => { + let [fd, offset, whence] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t), + link_name, + abi, + args, + )?; + let fd = this.read_scalar(fd)?.to_i32()?; + let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?; + let whence = this.read_scalar(whence)?.to_i32()?; + this.lseek64(fd, offset, whence, dest)?; + } + "ftruncate64" => { + let [fd, length] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, libc::off64_t) -> i32), + link_name, + abi, + args, + )?; + let fd = this.read_scalar(fd)?.to_i32()?; + let length = this.read_scalar(length)?.to_int(length.layout.size)?; + let result = this.ftruncate64(fd, length)?; + this.write_scalar(result, dest)?; + } + "posix_fallocate64" => { + let [fd, offset, len] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, libc::off64_t, libc::off64_t) -> i32), + link_name, + abi, + args, + )?; + + let fd = this.read_scalar(fd)?.to_i32()?; + let offset = this.read_scalar(offset)?.to_i64()?; + let len = this.read_scalar(len)?.to_i64()?; + + let result = this.posix_fallocate(fd, offset, len)?; + this.write_scalar(result, dest)?; + } "readdir64" => { let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.readdir64("dirent64", dirp)?; diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 6e1b554afda6..ed22457ec01a 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -46,12 +46,12 @@ fn emulate_foreign_item_inner( let result = this.close(result)?; this.write_scalar(result, dest)?; } - "stat" | "stat64" | "stat$INODE64" => { + "stat" | "stat$INODE64" => { let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_solarish_stat(path, buf)?; this.write_scalar(result, dest)?; } - "lstat" | "lstat64" | "lstat$INODE64" => { + "lstat" | "lstat$INODE64" => { let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_solarish_lstat(path, buf)?; this.write_scalar(result, dest)?; diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index b5eca70c3bf0..ae7230877a71 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -90,12 +90,12 @@ fn emulate_foreign_item_inner( } // File related shims - "stat" | "stat64" => { + "stat" => { let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_solarish_stat(path, buf)?; this.write_scalar(result, dest)?; } - "lstat" | "lstat64" => { + "lstat" => { let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_solarish_lstat(path, buf)?; this.write_scalar(result, dest)?; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index 3a4ac2a1b3ee..99685d6d976b 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -38,7 +38,7 @@ fn main() { test_posix_fadvise(); #[cfg(not(target_os = "macos"))] test_posix_fallocate::(libc::posix_fallocate); - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(target_os = "linux")] test_posix_fallocate::(libc::posix_fallocate64); #[cfg(target_os = "linux")] test_sync_file_range(); From a2910ce5b494c211780d5ca296f99785082fae75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Fri, 5 Dec 2025 20:16:15 +0100 Subject: [PATCH 361/585] Update windows-gnullvm platform support doc --- .../src/platform-support/windows-gnullvm.md | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/src/doc/rustc/src/platform-support/windows-gnullvm.md b/src/doc/rustc/src/platform-support/windows-gnullvm.md index b469af015313..e5db656e89f7 100644 --- a/src/doc/rustc/src/platform-support/windows-gnullvm.md +++ b/src/doc/rustc/src/platform-support/windows-gnullvm.md @@ -2,9 +2,11 @@ **Tier: 2 (with host tools)** -Windows targets similar to `*-windows-gnu` but using UCRT as the runtime and various LLVM tools/libraries instead of GCC/Binutils. +Windows targets similar to `*-windows-gnu` but using UCRT as the runtime and various LLVM tools/libraries instead of +GCC/Binutils. Target triples available so far: + - `aarch64-pc-windows-gnullvm` - `i686-pc-windows-gnullvm` - `x86_64-pc-windows-gnullvm` @@ -16,10 +18,11 @@ Target triples available so far: ## Requirements -The easiest way to obtain these targets is cross-compilation, but native build from `x86_64-pc-windows-gnu` is possible with few hacks which I don't recommend. -Std support is expected to be on par with `*-windows-gnu`. +Building those targets requires an LLVM-based C toolchain, for example, [llvm-mingw][1] or [MSYS2][2] with CLANG* +environment. -Binaries for this target should be at least on par with `*-windows-gnu` in terms of requirements and functionality. +Binaries for this target should be at least on par with `*-windows-gnu` in terms of requirements and functionality, +except for implicit self-contained mode (explained in [the section below](#building-rust-programs)). Those targets follow Windows calling convention for `extern "C"`. @@ -27,37 +30,32 @@ Like with any other Windows target, created binaries are in PE format. ## Building the target -These targets can be easily cross-compiled -using [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) toolchain or [MSYS2 CLANG*](https://www.msys2.org/docs/environments/) environments. -Just fill `[target.*]` sections for both build and resulting compiler and set installation prefix in `bootstrap.toml`. -Then run `./x.py install`. -In my case I had ran `./x.py install --host x86_64-pc-windows-gnullvm --target x86_64-pc-windows-gnullvm` inside MSYS2 MINGW64 shell -so `x86_64-pc-windows-gnu` was my build toolchain. - -Native bootstrapping is doable in two ways: -- cross-compile gnullvm host toolchain and use it as build toolchain for the next build, -- copy libunwind libraries and rename them to mimic libgcc like here: https://github.com/msys2/MINGW-packages/blob/68e640756df2df6df6afa60f025e3f936e7b977c/mingw-w64-rust/PKGBUILD#L108-L109, stage0 compiler will be mostly broken but good enough to build the next stage. - -The second option might stop working anytime, so it's not recommended. +Both native and cross-compilation builds are supported and function similarly to other Rust targets. ## Building Rust programs -Rust does ship a pre-compiled std library for those targets. -That means one can easily cross-compile for those targets from other hosts if C proper toolchain is installed. +Rust ships both std and host tools for those targets. That allows using them as both the host and the target. -Alternatively full toolchain can be built as described in the previous section. +When used as the host and building pure Rust programs, no additional C toolchain is required. +The only requirements are to install `rust-mingw` component and to set `rust-lld` as the linker. +Otherwise, you will need to install the C toolchain mentioned previously. +There is no automatic fallback to `rust-lld` when the C toolchain is missing yet, but it may be added in the future. ## Testing -Created binaries work fine on Windows or Wine using native hardware. Testing AArch64 on x86_64 is problematic though and requires spending some time with QEMU. -Most of x86_64 testsuite does pass when cross-compiling, -with exception for `rustdoc` and `ui-fulldeps` that fail with and error regarding a missing library, -they do pass in native builds though. -The only failing test is std's `process::tests::test_proc_thread_attributes` for unknown reason. +Created binaries work fine on Windows and Linux with Wine using native hardware. +Testing AArch64 on x86_64 is problematic, though, and requires launching a whole AArch64 system with QEMU. + +Most of the x86_64 testsuite does pass, but because it isn't run on CI, different failures are expected over time. ## Cross-compilation toolchains and C code -Compatible C code can be built with Clang's `aarch64-pc-windows-gnu`, `i686-pc-windows-gnullvm` and `x86_64-pc-windows-gnu` targets as long as LLVM-based C toolchains are used. -Those include: -- [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) -- [MSYS2 with CLANG* environment](https://www.msys2.org/docs/environments) +Compatible C code can be built with Clang's `aarch64-pc-windows-gnu`, `i686-pc-windows-gnullvm` and +`x86_64-pc-windows-gnu` targets as long as LLVM-based C toolchains are used. Those include: + +- [llvm-mingw][1] +- [MSYS2][2] with CLANG* environment + +[1]: https://github.com/mstorsjo/llvm-mingw + +[2]: https://www.msys2.org/docs/environments From 7ad3301e03ec73dec2b304826a84e2eae461e2fc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Dec 2025 13:57:59 +0100 Subject: [PATCH 362/585] show span when there is an error invoking a global ctor/dtor or the thread main fn --- src/tools/miri/README.md | 1 + src/tools/miri/src/concurrency/thread.rs | 23 +++++++--- src/tools/miri/src/diagnostics.rs | 21 ++++++++- src/tools/miri/src/helpers.rs | 26 +++++++++-- src/tools/miri/src/lib.rs | 1 + src/tools/miri/src/shims/global_ctor.rs | 9 ++-- src/tools/miri/src/shims/tls.rs | 45 ++++++++++--------- .../miri/src/shims/unix/foreign_items.rs | 5 ++- .../src/shims/unix/macos/foreign_items.rs | 7 ++- .../libc_pthread_create_too_few_args.rs | 2 +- .../libc_pthread_create_too_few_args.stderr | 8 +++- .../libc_pthread_create_too_many_args.rs | 2 +- .../libc_pthread_create_too_many_args.stderr | 8 +++- .../concurrency/tls_pthread_dtor_wrong_abi.rs | 21 +++++++++ .../tls_pthread_dtor_wrong_abi.stderr | 13 ++++++ .../tests/fail/shims/ctor_wrong_ret_type.rs | 2 +- .../fail/shims/ctor_wrong_ret_type.stderr | 12 ++++- .../fail/shims/macos_tlv_atexit_wrong_abi.rs | 18 ++++++++ .../shims/macos_tlv_atexit_wrong_abi.stderr | 13 ++++++ 19 files changed, 188 insertions(+), 49 deletions(-) create mode 100644 src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.rs create mode 100644 src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.stderr create mode 100644 src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.rs create mode 100644 src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.stderr diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 1c6a2daa093d..32494141589a 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -624,6 +624,7 @@ Definite bugs found: * [Mockall reading uninitialized memory when mocking `std::io::Read::read`, even if all expectations are satisfied](https://github.com/asomers/mockall/issues/647) (caught by Miri running Tokio's test suite) * [`ReentrantLock` not correctly dealing with reuse of addresses for TLS storage of different threads](https://github.com/rust-lang/rust/pull/141248) * [Rare Deadlock in the thread (un)parking example code](https://github.com/rust-lang/rust/issues/145816) +* [`winit` registering a global constructor with the wrong ABI on Windows](https://github.com/rust-windowing/winit/issues/4435) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index c7ae335d0479..5016e3b66ca6 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -14,7 +14,7 @@ use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::Mutability; use rustc_middle::ty::layout::TyAndLayout; -use rustc_span::Span; +use rustc_span::{DUMMY_SP, Span}; use rustc_target::spec::Os; use crate::concurrency::GlobalDataRaceHandler; @@ -174,6 +174,10 @@ pub struct Thread<'tcx> { /// The virtual call stack. stack: Vec>>, + /// A span that explains where the thread (or more specifically, its current root + /// frame) "comes from". + pub(crate) origin_span: Span, + /// The function to call when the stack ran empty, to figure out what to do next. /// Conceptually, this is the interpreter implementation of the things that happen 'after' the /// Rust language entry point for this thread returns (usually implemented by the C or OS runtime). @@ -303,6 +307,7 @@ fn new(name: Option<&str>, on_stack_empty: Option>) -> state: ThreadState::Enabled, thread_name: name.map(|name| Vec::from(name.as_bytes())), stack: Vec::new(), + origin_span: DUMMY_SP, top_user_relevant_frame: None, join_status: ThreadJoinStatus::Joinable, unwind_payloads: Vec::new(), @@ -318,6 +323,7 @@ fn visit_provenance(&self, visit: &mut VisitWith<'_>) { unwind_payloads: panic_payload, last_error, stack, + origin_span: _, top_user_relevant_frame: _, state: _, thread_name: _, @@ -584,6 +590,10 @@ pub fn active_thread_ref(&self) -> &Thread<'tcx> { &self.threads[self.active_thread] } + pub fn thread_ref(&self, thread_id: ThreadId) -> &Thread<'tcx> { + &self.threads[thread_id] + } + /// Mark the thread as detached, which means that no other thread will try /// to join it and the thread is responsible for cleaning up. /// @@ -704,8 +714,9 @@ fn run_timeout_callback(&mut self) -> InterpResult<'tcx> { #[inline] fn run_on_stack_empty(&mut self) -> InterpResult<'tcx, Poll<()>> { let this = self.eval_context_mut(); - let mut callback = this - .active_thread_mut() + let active_thread = this.active_thread_mut(); + active_thread.origin_span = DUMMY_SP; // reset, the old value no longer applied + let mut callback = active_thread .on_stack_empty .take() .expect("`on_stack_empty` not set up, or already running"); @@ -891,11 +902,11 @@ fn start_regular_thread( let this = self.eval_context_mut(); // Create the new thread + let current_span = this.machine.current_user_relevant_span(); let new_thread_id = this.machine.threads.create_thread({ let mut state = tls::TlsDtorsState::default(); Box::new(move |m| state.on_stack_empty(m)) }); - let current_span = this.machine.current_user_relevant_span(); match &mut this.machine.data_race { GlobalDataRaceHandler::None => {} GlobalDataRaceHandler::Vclocks(data_race) => @@ -934,12 +945,12 @@ fn start_regular_thread( // it. let ret_place = this.allocate(ret_layout, MiriMemoryKind::Machine.into())?; - this.call_function( + this.call_thread_root_function( instance, start_abi, &[func_arg], Some(&ret_place), - ReturnContinuation::Stop { cleanup: true }, + current_span, )?; // Restore the old active thread frame. diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 8e252d306b29..01f77f261d70 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -444,7 +444,11 @@ pub fn report_result<'tcx>( write!(primary_msg, "{}", format_interp_error(ecx.tcx.dcx(), res)).unwrap(); if labels.is_empty() { - labels.push(format!("{} occurred here", title.unwrap_or("error"))); + labels.push(format!( + "{} occurred {}", + title.unwrap_or("error"), + if stacktrace.is_empty() { "due to this code" } else { "here" } + )); } report_msg( @@ -552,7 +556,14 @@ pub fn report_msg<'tcx>( thread: Option, machine: &MiriMachine<'tcx>, ) { - let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); + let span = match stacktrace.first() { + Some(fi) => fi.span, + None => + match thread { + Some(thread_id) => machine.threads.thread_ref(thread_id).origin_span, + None => DUMMY_SP, + }, + }; let sess = machine.tcx.sess; let level = match diag_level { DiagLevel::Error => Level::Error, @@ -620,6 +631,12 @@ pub fn report_msg<'tcx>( err.note(format!("{frame_info} at {span}")); } } + } else if stacktrace.len() == 0 && !span.is_dummy() { + err.note(format!( + "this {} occurred while pushing a call frame onto an empty stack", + level.to_str() + )); + err.note("the span indicates which code caused the function to be called, but may not be the literal call site"); } err.emit(); diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 383a4e2ea4b0..75b7e9f5966f 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -472,6 +472,22 @@ fn call_function( ) } + /// Call a function in an "empty" thread. + fn call_thread_root_function( + &mut self, + f: ty::Instance<'tcx>, + caller_abi: ExternAbi, + args: &[ImmTy<'tcx>], + dest: Option<&MPlaceTy<'tcx>>, + span: Span, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + assert!(this.active_thread_stack().is_empty()); + assert!(this.active_thread_ref().origin_span.is_dummy()); + this.active_thread_mut().origin_span = span; + this.call_function(f, caller_abi, args, dest, ReturnContinuation::Stop { cleanup: true }) + } + /// Visits the memory covered by `place`, sensitive to freezing: the 2nd parameter /// of `action` will be true if this is frozen, false if this is in an `UnsafeCell`. /// The range is relative to `place`. @@ -995,11 +1011,12 @@ fn expect_target_feature_for_intrinsic( interp_ok(()) } - /// Lookup an array of immediates from any linker sections matching the provided predicate. + /// Lookup an array of immediates from any linker sections matching the provided predicate, + /// with the spans of where they were found. fn lookup_link_section( &mut self, include_name: impl Fn(&str) -> bool, - ) -> InterpResult<'tcx, Vec>> { + ) -> InterpResult<'tcx, Vec<(ImmTy<'tcx>, Span)>> { let this = self.eval_context_mut(); let tcx = this.tcx.tcx; @@ -1012,6 +1029,7 @@ fn lookup_link_section( }; if include_name(link_section.as_str()) { let instance = ty::Instance::mono(tcx, def_id); + let span = tcx.def_span(def_id); let const_val = this.eval_global(instance).unwrap_or_else(|err| { panic!( "failed to evaluate static in required link_section: {def_id:?}\n{err:?}" @@ -1019,12 +1037,12 @@ fn lookup_link_section( }); match const_val.layout.ty.kind() { ty::FnPtr(..) => { - array.push(this.read_immediate(&const_val)?); + array.push((this.read_immediate(&const_val)?, span)); } ty::Array(elem_ty, _) if matches!(elem_ty.kind(), ty::FnPtr(..)) => { let mut elems = this.project_array_fields(&const_val)?; while let Some((_idx, elem)) = elems.next(this)? { - array.push(this.read_immediate(&elem)?); + array.push((this.read_immediate(&elem)?, span)); } } _ => diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index b30395b738b1..fe501b8d7b30 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -39,6 +39,7 @@ clippy::needless_question_mark, clippy::needless_lifetimes, clippy::too_long_first_doc_paragraph, + clippy::len_zero, // We don't use translatable diagnostics rustc::diagnostic_outside_of_impl, // We are not implementing queries here so it's fine diff --git a/src/tools/miri/src/shims/global_ctor.rs b/src/tools/miri/src/shims/global_ctor.rs index c56251bbe63a..d3296e4445f7 100644 --- a/src/tools/miri/src/shims/global_ctor.rs +++ b/src/tools/miri/src/shims/global_ctor.rs @@ -3,6 +3,7 @@ use std::task::Poll; use rustc_abi::ExternAbi; +use rustc_span::Span; use rustc_target::spec::BinaryFormat; use crate::*; @@ -15,7 +16,7 @@ enum GlobalCtorStatePriv<'tcx> { #[default] Init, /// The list of constructor functions that we still have to call. - Ctors(Vec>), + Ctors(Vec<(ImmTy<'tcx>, Span)>), Done, } @@ -67,19 +68,19 @@ pub fn on_stack_empty( break 'new_state Ctors(ctors); } Ctors(ctors) => { - if let Some(ctor) = ctors.pop() { + if let Some((ctor, span)) = ctors.pop() { let this = this.eval_context_mut(); let ctor = ctor.to_scalar().to_pointer(this)?; let thread_callback = this.get_ptr_fn(ctor)?.as_instance()?; // The signature of this function is `unsafe extern "C" fn()`. - this.call_function( + this.call_thread_root_function( thread_callback, ExternAbi::C { unwind: false }, &[], None, - ReturnContinuation::Stop { cleanup: true }, + span, )?; return interp_ok(Poll::Pending); // we stay in this state (but `ctors` got shorter) diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index 2159c41ab16c..3ecd9b1ead38 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -6,6 +6,7 @@ use rustc_abi::{ExternAbi, HasDataLayout, Size}; use rustc_middle::ty; +use rustc_span::Span; use rustc_target::spec::Os; use crate::*; @@ -17,7 +18,7 @@ pub struct TlsEntry<'tcx> { /// The data for this key. None is used to represent NULL. /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.) data: BTreeMap, - dtor: Option>, + dtor: Option<(ty::Instance<'tcx>, Span)>, } #[derive(Default, Debug)] @@ -38,7 +39,7 @@ pub struct TlsData<'tcx> { /// On macOS, each thread holds a list of destructor functions with their /// respective data arguments. - macos_thread_dtors: BTreeMap, Scalar)>>, + macos_thread_dtors: BTreeMap, Scalar, Span)>>, } impl<'tcx> Default for TlsData<'tcx> { @@ -57,7 +58,7 @@ impl<'tcx> TlsData<'tcx> { #[expect(clippy::arithmetic_side_effects)] pub fn create_tls_key( &mut self, - dtor: Option>, + dtor: Option<(ty::Instance<'tcx>, Span)>, max_size: Size, ) -> InterpResult<'tcx, TlsKey> { let new_key = self.next_key; @@ -126,8 +127,9 @@ pub fn add_macos_thread_dtor( thread: ThreadId, dtor: ty::Instance<'tcx>, data: Scalar, + span: Span, ) -> InterpResult<'tcx> { - self.macos_thread_dtors.entry(thread).or_default().push((dtor, data)); + self.macos_thread_dtors.entry(thread).or_default().push((dtor, data, span)); interp_ok(()) } @@ -154,7 +156,7 @@ fn fetch_tls_dtor( &mut self, key: Option, thread_id: ThreadId, - ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey, Span)> { use std::ops::Bound::*; let thread_local = &mut self.keys; @@ -172,11 +174,10 @@ fn fetch_tls_dtor( for (&key, TlsEntry { data, dtor }) in thread_local.range_mut((start, Unbounded)) { match data.entry(thread_id) { BTreeEntry::Occupied(entry) => { - if let Some(dtor) = dtor { + if let Some((dtor, span)) = dtor { // Set TLS data to NULL, and call dtor with old value. let data_scalar = entry.remove(); - let ret = Some((*dtor, data_scalar, key)); - return ret; + return Some((*dtor, data_scalar, key, *span)); } } BTreeEntry::Vacant(_) => {} @@ -205,7 +206,7 @@ fn visit_provenance(&self, visit: &mut VisitWith<'_>) { for scalar in keys.values().flat_map(|v| v.data.values()) { scalar.visit_provenance(visit); } - for (_, scalar) in macos_thread_dtors.values().flatten() { + for (_, scalar, _) in macos_thread_dtors.values().flatten() { scalar.visit_provenance(visit); } } @@ -222,7 +223,7 @@ enum TlsDtorsStatePriv<'tcx> { PthreadDtors(RunningDtorState), /// For Windows Dtors, we store the list of functions that we still have to call. /// These are functions from the magic `.CRT$XLB` linker section. - WindowsDtors(Vec>), + WindowsDtors(Vec<(ImmTy<'tcx>, Span)>), Done, } @@ -273,8 +274,8 @@ pub fn on_stack_empty( } } WindowsDtors(dtors) => { - if let Some(dtor) = dtors.pop() { - this.schedule_windows_tls_dtor(dtor)?; + if let Some((dtor, span)) = dtors.pop() { + this.schedule_windows_tls_dtor(dtor, span)?; return interp_ok(Poll::Pending); // we stay in this state (but `dtors` got shorter) } else { // No more destructors to run. @@ -297,7 +298,7 @@ impl<'tcx> EvalContextPrivExt<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Schedule TLS destructors for Windows. /// On windows, TLS destructors are managed by std. - fn lookup_windows_tls_dtors(&mut self) -> InterpResult<'tcx, Vec>> { + fn lookup_windows_tls_dtors(&mut self) -> InterpResult<'tcx, Vec<(ImmTy<'tcx>, Span)>> { let this = self.eval_context_mut(); // Windows has a special magic linker section that is run on certain events. @@ -305,7 +306,7 @@ fn lookup_windows_tls_dtors(&mut self) -> InterpResult<'tcx, Vec>> { interp_ok(this.lookup_link_section(|section| section == ".CRT$XLB")?) } - fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx>) -> InterpResult<'tcx> { + fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx>, span: Span) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let dtor = dtor.to_scalar().to_pointer(this)?; @@ -320,12 +321,12 @@ fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx>) -> InterpResult<'tcx> // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. // FIXME: `h` should be a handle to the current module and what `pv` should be is unknown // but both are ignored by std. - this.call_function( + this.call_thread_root_function( thread_callback, ExternAbi::System { unwind: false }, &[null_ptr.clone(), ImmTy::from_scalar(reason, this.machine.layouts.u32), null_ptr], None, - ReturnContinuation::Stop { cleanup: true }, + span, )?; interp_ok(()) } @@ -338,15 +339,15 @@ fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, Poll<()>> { // registers another destructor, it will be run next. // See https://github.com/apple-oss-distributions/dyld/blob/d552c40cd1de105f0ec95008e0e0c0972de43456/dyld/DyldRuntimeState.cpp#L2277 let dtor = this.machine.tls.macos_thread_dtors.get_mut(&thread_id).and_then(Vec::pop); - if let Some((instance, data)) = dtor { + if let Some((instance, data, span)) = dtor { trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id); - this.call_function( + this.call_thread_root_function( instance, ExternAbi::C { unwind: false }, &[ImmTy::from_scalar(data, this.machine.layouts.mut_raw_ptr)], None, - ReturnContinuation::Stop { cleanup: true }, + span, )?; return interp_ok(Poll::Pending); @@ -370,7 +371,7 @@ fn schedule_next_pthread_tls_dtor( // We ran each dtor once, start over from the beginning. None => this.machine.tls.fetch_tls_dtor(None, active_thread), }; - if let Some((instance, ptr, key)) = dtor { + if let Some((instance, ptr, key, span)) = dtor { state.last_key = Some(key); trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, active_thread); assert!( @@ -378,12 +379,12 @@ fn schedule_next_pthread_tls_dtor( "data can't be NULL when dtor is called!" ); - this.call_function( + this.call_thread_root_function( instance, ExternAbi::C { unwind: false }, &[ImmTy::from_scalar(ptr, this.machine.layouts.mut_raw_ptr)], None, - ReturnContinuation::Stop { cleanup: true }, + span, )?; return interp_ok(Poll::Pending); diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 378a8537fc73..64b8376ff4aa 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -634,7 +634,10 @@ fn emulate_foreign_item_inner( // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = if !this.ptr_is_null(dtor)? { - Some(this.get_ptr_fn(dtor)?.as_instance()?) + Some(( + this.get_ptr_fn(dtor)?.as_instance()?, + this.machine.current_user_relevant_span(), + )) } else { None }; diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index ed22457ec01a..dd7b95bdc82b 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -158,7 +158,12 @@ fn emulate_foreign_item_inner( let dtor = this.get_ptr_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?; let active_thread = this.active_thread(); - this.machine.tls.add_macos_thread_dtor(active_thread, dtor, data)?; + this.machine.tls.add_macos_thread_dtor( + active_thread, + dtor, + data, + this.machine.current_user_relevant_span(), + )?; } // Querying system information diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs index 520bc9572f86..6fec6500cc96 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs @@ -1,5 +1,4 @@ //@ignore-target: windows # No pthreads on Windows -//~^ERROR: calling a function with more arguments than it expected //! The thread function must have exactly one argument. @@ -17,6 +16,7 @@ fn main() { mem::transmute(thread_start); assert_eq!( libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), + //~^ERROR: calling a function with more arguments than it expected 0 ); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr index 4d5a80c828cd..fef91e85470d 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: calling a function with more arguments than it expected + --> tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs:LL:CC + | +LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code | - = note: Undefined Behavior occurred here - = note: (no span available) = 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 + = note: this error occurred while pushing a call frame onto an empty stack + = note: the span indicates which code caused the function to be called, but may not be the literal call site error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs index 92d8a765e511..cb55b0f92ee6 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs @@ -1,5 +1,4 @@ //@ignore-target: windows # No pthreads on Windows -//~^ERROR: calling a function with fewer arguments than it requires //! The thread function must have exactly one argument. @@ -17,6 +16,7 @@ fn main() { mem::transmute(thread_start); assert_eq!( libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), + //~^ERROR: calling a function with fewer arguments than it requires 0 ); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr index 1bc79411197c..4d70576d784c 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: calling a function with fewer arguments than it requires + --> tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs:LL:CC + | +LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code | - = note: Undefined Behavior occurred here - = note: (no span available) = 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 + = note: this error occurred while pushing a call frame onto an empty stack + = note: the span indicates which code caused the function to be called, but may not be the literal call site error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.rs b/src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.rs new file mode 100644 index 000000000000..b5eec2db201c --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.rs @@ -0,0 +1,21 @@ +//@ignore-target: windows # No pthreads on Windows + +use std::{mem, ptr}; + +pub type Key = libc::pthread_key_t; + +pub unsafe fn create(dtor: unsafe fn(*mut u8)) -> Key { + let mut key = 0; + assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0); + //~^ERROR: calling a function with calling convention "Rust" + key +} + +unsafe fn dtor(_ptr: *mut u8) {} + +fn main() { + unsafe { + let key = create(dtor); + libc::pthread_setspecific(key, ptr::without_provenance(1)); + } +} diff --git a/src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.stderr b/src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.stderr new file mode 100644 index 000000000000..32e92319cdf3 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.stderr @@ -0,0 +1,13 @@ +error: Undefined Behavior: calling a function with calling convention "Rust" using calling convention "C" + --> tests/fail-dep/concurrency/tls_pthread_dtor_wrong_abi.rs:LL:CC + | +LL | assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code + | + = 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 + = note: this error occurred while pushing a call frame onto an empty stack + = note: the span indicates which code caused the function to be called, but may not be the literal call site + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs index 1e10f682e71e..3629e4387e7f 100644 --- a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs +++ b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs @@ -1,5 +1,4 @@ unsafe extern "C" fn ctor() -> i32 { - //~^ERROR: calling a function with return type i32 passing return place of type () 0 } @@ -31,6 +30,7 @@ macro_rules! ctor { )] #[used] static $ident: unsafe extern "C" fn() -> i32 = $ctor; + //~^ERROR: calling a function with return type i32 passing return place of type () }; } diff --git a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr index 68c56044be88..1b4cd23e41a8 100644 --- a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr +++ b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr @@ -1,11 +1,19 @@ error: Undefined Behavior: calling a function with return type i32 passing return place of type () + --> tests/fail/shims/ctor_wrong_ret_type.rs:LL:CC + | +LL | static $ident: unsafe extern "C" fn() -> i32 = $ctor; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code +... +LL | ctor! { CTOR = ctor } + | --------------------- in this macro invocation | - = note: Undefined Behavior occurred here - = note: (no span available) = 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: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: this error occurred while pushing a call frame onto an empty stack + = note: the span indicates which code caused the function to be called, but may not be the literal call site + = note: this error originates in the macro `ctor` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.rs b/src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.rs new file mode 100644 index 000000000000..5d5cb749f896 --- /dev/null +++ b/src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.rs @@ -0,0 +1,18 @@ +//@only-target: darwin + +use std::{mem, ptr}; + +extern "C" { + fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8); +} + +fn register(dtor: unsafe fn(*mut u8)) { + unsafe { + _tlv_atexit(mem::transmute(dtor), ptr::null_mut()); + //~^ERROR: calling a function with calling convention "Rust" + } +} + +fn main() { + register(|_| ()); +} diff --git a/src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.stderr b/src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.stderr new file mode 100644 index 000000000000..0fc87f13f16d --- /dev/null +++ b/src/tools/miri/tests/fail/shims/macos_tlv_atexit_wrong_abi.stderr @@ -0,0 +1,13 @@ +error: Undefined Behavior: calling a function with calling convention "Rust" using calling convention "C" + --> tests/fail/shims/macos_tlv_atexit_wrong_abi.rs:LL:CC + | +LL | _tlv_atexit(mem::transmute(dtor), ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code + | + = 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 + = note: this error occurred while pushing a call frame onto an empty stack + = note: the span indicates which code caused the function to be called, but may not be the literal call site + +error: aborting due to 1 previous error + From a3a041da11202dd4c5fbbac4dbc1461e4c783f90 Mon Sep 17 00:00:00 2001 From: Justin Tracey Date: Sat, 6 Dec 2025 11:16:14 -0500 Subject: [PATCH 363/585] rustdoc book: mention inner doc attribute --- src/doc/rustdoc/src/write-documentation/the-doc-attribute.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index 4d7f1a4aafc9..3af53fa58e18 100644 --- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -4,8 +4,8 @@ The `#[doc]` attribute lets you control various aspects of how `rustdoc` does its job. The most basic function of `#[doc]` is to handle the actual documentation -text. That is, `///` is syntax sugar for `#[doc]`. This means that these two -are the same: +text. That is, `///` is syntax sugar for `#[doc]` (as is `//!` for `#![doc]`). +This means that these two are the same: ```rust,no_run /// This is a doc comment. From c788c7cb77509b8704da3174fe7c7ecad041f3ad Mon Sep 17 00:00:00 2001 From: irelaxcn Date: Sun, 7 Dec 2025 00:41:43 +0800 Subject: [PATCH 364/585] Fix `map_entry` FP when it would cause `MutexGuard` to be held across an await point. --- clippy_lints/src/entry.rs | 48 ++++++++++++++++++++++++++++++--------- tests/ui/entry.fixed | 24 ++++++++++++++++++++ tests/ui/entry.rs | 24 ++++++++++++++++++++ 3 files changed, 85 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index a5ec6777b434..bdfe2e49e66e 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -3,11 +3,12 @@ use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_expr; use clippy_utils::{ - SpanlessEq, can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, - peel_hir_expr_while, + SpanlessEq, can_move_expr_to_closure_no_visit, desugar_await, higher, is_expr_final_block_expr, + is_expr_used_or_unified, paths, peel_hir_expr_while, }; use core::fmt::{self, Write}; use rustc_errors::Applicability; +use rustc_hir::def_id::DefId; use rustc_hir::hir_id::HirIdSet; use rustc_hir::intravisit::{Visitor, walk_body, walk_expr}; use rustc_hir::{Block, Expr, ExprKind, HirId, Pat, Stmt, StmtKind, UnOp}; @@ -382,6 +383,8 @@ struct InsertSearcher<'cx, 'tcx> { loops: Vec, /// Local variables created in the expression. These don't need to be captured. locals: HirIdSet, + /// Whether the map is a non-async-aware `MutexGuard`. + map_is_mutex_guard: bool, } impl<'tcx> InsertSearcher<'_, 'tcx> { /// Visit the expression as a branch in control flow. Multiple insert calls can be used, but @@ -524,15 +527,22 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { ExprKind::If(cond_expr, then_expr, Some(else_expr)) => { self.is_single_insert = false; self.visit_non_tail_expr(cond_expr); - // Each branch may contain it's own insert expression. + // Each branch may contain its own insert expression. let mut is_map_used = self.visit_cond_arm(then_expr); is_map_used |= self.visit_cond_arm(else_expr); self.is_map_used = is_map_used; }, ExprKind::Match(scrutinee_expr, arms, _) => { + // If the map is a non-async-aware `MutexGuard` and + // `.await` expression appears alongside map insertion in the same `then` or `else` block, + // we cannot suggest using `entry()` because it would hold the lock across the await point, + // triggering `await_holding_lock` and risking deadlock. + if self.map_is_mutex_guard && desugar_await(expr).is_some() { + self.can_use_entry = false; + } self.is_single_insert = false; self.visit_non_tail_expr(scrutinee_expr); - // Each branch may contain it's own insert expression. + // Each branch may contain its own insert expression. let mut is_map_used = self.is_map_used; for arm in arms { self.visit_pat(arm.pat); @@ -725,16 +735,32 @@ fn find_insert_calls<'tcx>( edits: Vec::new(), loops: Vec::new(), locals: HirIdSet::default(), + map_is_mutex_guard: false, }; + // Check if the map is a non-async-aware `MutexGuard` + if let rustc_middle::ty::Adt(adt, _) = cx.typeck_results().expr_ty(contains_expr.map).kind() + && is_mutex_guard(cx, adt.did()) + { + s.map_is_mutex_guard = true; + } + s.visit_expr(expr); - let allow_insert_closure = s.allow_insert_closure; - let is_single_insert = s.is_single_insert; + if !s.can_use_entry { + return None; + } + let is_key_used_and_no_copy = s.is_key_used && !is_copy(cx, cx.typeck_results().expr_ty(contains_expr.key)); - let edits = s.edits; - s.can_use_entry.then_some(InsertSearchResults { - edits, - allow_insert_closure, - is_single_insert, + Some(InsertSearchResults { + edits: s.edits, + allow_insert_closure: s.allow_insert_closure, + is_single_insert: s.is_single_insert, is_key_used_and_no_copy, }) } + +fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool { + match cx.tcx.get_diagnostic_name(def_id) { + Some(name) => matches!(name, sym::MutexGuard | sym::RwLockReadGuard | sym::RwLockWriteGuard), + None => paths::PARKING_LOT_GUARDS.iter().any(|guard| guard.matches(cx, def_id)), + } +} diff --git a/tests/ui/entry.fixed b/tests/ui/entry.fixed index f2df9f0204ea..1e36ca4f1f09 100644 --- a/tests/ui/entry.fixed +++ b/tests/ui/entry.fixed @@ -248,4 +248,28 @@ mod issue14449 { } } +// Don't suggest when it would cause `MutexGuard` to be held across an await point. +mod issue_16173 { + use std::collections::HashMap; + use std::sync::Mutex; + + async fn f() {} + + async fn foo() { + let mu_map = Mutex::new(HashMap::new()); + if !mu_map.lock().unwrap().contains_key(&0) { + f().await; + mu_map.lock().unwrap().insert(0, 0); + } + + if mu_map.lock().unwrap().contains_key(&1) { + todo!(); + } else { + mu_map.lock().unwrap().insert(1, 42); + todo!(); + f().await; + } + } +} + fn main() {} diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index 166eea417ac2..b3da0ef3ffd6 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -254,4 +254,28 @@ pub fn f(meow: &Meow, x: String) { } } +// Don't suggest when it would cause `MutexGuard` to be held across an await point. +mod issue_16173 { + use std::collections::HashMap; + use std::sync::Mutex; + + async fn f() {} + + async fn foo() { + let mu_map = Mutex::new(HashMap::new()); + if !mu_map.lock().unwrap().contains_key(&0) { + f().await; + mu_map.lock().unwrap().insert(0, 0); + } + + if mu_map.lock().unwrap().contains_key(&1) { + todo!(); + } else { + mu_map.lock().unwrap().insert(1, 42); + todo!(); + f().await; + } + } +} + fn main() {} From bd2d4eb79e459487c80a98ccd7475253652e7b6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Pu=C4=8Dil?= Date: Sat, 6 Dec 2025 18:09:29 +0100 Subject: [PATCH 365/585] rustc book: fix `*-pc-windows-msvc` link label in sidebar As far as I know, `*-unknown-windows-msvc` is not a thing. At least if I search for "unknown-windows-msvc" in the entire [rust-lang](https://github.com/rust-lang) organization (https://github.com/search?q=org%3Arust-lang+%22unknown-windows-msvc%22++&type=code&state=open), it gives only this occurrence and 3 other occurrences in https://github.com/rust-lang/lld, which was archived in 2019. I believe `*-pc-windows-msvc` is the correct replacement because that is the name of the page the link points to: https://github.com/rust-lang/rust/blob/ba86c0460b0233319e01fd789a42a7276eade805/src/doc/rustc/src/platform-support/windows-msvc.md?plain=1#L1 --- src/doc/rustc/src/SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 3da3571c2718..832b5a69d47c 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -130,7 +130,7 @@ - [\*-unknown-openbsd](platform-support/openbsd.md) - [\*-unknown-redox](platform-support/redox.md) - [\*-unknown-uefi](platform-support/unknown-uefi.md) - - [\*-unknown-windows-msvc](platform-support/windows-msvc.md) + - [\*-pc-windows-msvc](platform-support/windows-msvc.md) - [\*-uwp-windows-msvc](platform-support/uwp-windows-msvc.md) - [\*-wrs-vxworks](platform-support/vxworks.md) - [wasm32-wasip1](platform-support/wasm32-wasip1.md) From 234df83fe309fc4c3a5c3c87393110b1a5c8274d Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sun, 28 Sep 2025 18:12:17 -0400 Subject: [PATCH 366/585] Add warn-by-default lint for visibility on `const _` declarations Add a warn-by-default `unused_visibility` lint for visibility qualifiers on `const _` declarations - e.g. `pub const _: () = ();`. These have no effect. --- .../rustc_ast_passes/src/ast_validation.rs | 15 +++++++++++-- compiler/rustc_lint/messages.ftl | 3 +++ compiler/rustc_lint/src/early/diagnostics.rs | 3 +++ compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/lints.rs | 7 +++++++ compiler/rustc_lint_defs/src/builtin.rs | 21 +++++++++++++++++++ compiler/rustc_lint_defs/src/lib.rs | 1 + .../absolute_paths.no_short.stderr | 6 +++--- .../ui-toml/absolute_paths/absolute_paths.rs | 2 +- tests/ui/consts/promoted_const_call3.rs | 4 ++-- tests/ui/consts/ptr_is_null.rs | 10 ++++----- ...-dont-override-forbid-in-same-scope.stderr | 18 ++++++++++++++++ tests/ui/lint/outer-forbid.stderr | 18 ++++++++++++++++ tests/ui/lint/unused-visibilities.fixed | 12 +++++++++++ tests/ui/lint/unused-visibilities.rs | 12 +++++++++++ tests/ui/lint/unused-visibilities.stderr | 20 ++++++++++++++++++ tests/ui/traits/const-traits/call.rs | 2 +- 17 files changed, 141 insertions(+), 14 deletions(-) create mode 100644 tests/ui/lint/unused-visibilities.fixed create mode 100644 tests/ui/lint/unused-visibilities.rs create mode 100644 tests/ui/lint/unused-visibilities.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 2790916891a1..06a35e691929 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -33,7 +33,7 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN, - PATTERNS_IN_FNS_WITHOUT_BODY, + PATTERNS_IN_FNS_WITHOUT_BODY, UNUSED_VISIBILITIES, }; use rustc_session::parse::feature_err; use rustc_span::{Ident, Span, kw, sym}; @@ -1339,7 +1339,7 @@ fn visit_item(&mut self, item: &'a Item) { } }); } - ItemKind::Const(box ConstItem { defaultness, rhs, .. }) => { + ItemKind::Const(box ConstItem { defaultness, ident, rhs, .. }) => { self.check_defaultness(item.span, *defaultness); if rhs.is_none() { self.dcx().emit_err(errors::ConstWithoutBody { @@ -1347,6 +1347,17 @@ fn visit_item(&mut self, item: &'a Item) { replace_span: self.ending_semi_or_hi(item.span), }); } + if ident.name == kw::Underscore + && !matches!(item.vis.kind, VisibilityKind::Inherited) + { + self.lint_buffer.buffer_lint( + UNUSED_VISIBILITIES, + item.id, + item.vis.span, + BuiltinLintDiag::UnusedVisibility(item.vis.span), + ) + } + visit::walk_item(self, item); } ItemKind::Static(box StaticItem { expr, safety, .. }) => { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 1bcdda96e13a..fac26b52176d 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -978,6 +978,9 @@ lint_unused_op = unused {$op} that must be used lint_unused_result = unused result of type `{$ty}` +lint_unused_visibilities = visibility qualifiers have no effect on `const _` declarations + .suggestion = remove the qualifier + lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expression or result lint_useless_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking them for null will always return false diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index b654bc848ecf..ff364e5f814a 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -302,6 +302,9 @@ pub fn decorate_builtin_lint( BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag) } + BuiltinLintDiag::UnusedVisibility(span) => { + lints::UnusedVisibility { span }.decorate_lint(diag) + } BuiltinLintDiag::AttributeLint(kind) => decorate_attribute_lint(sess, tcx, &kind, diag), } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index a5f9eabf89c4..4e7a3e405176 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -291,6 +291,7 @@ macro_rules! add_lint_group { "unused", UNUSED_IMPORTS, UNUSED_VARIABLES, + UNUSED_VISIBILITIES, UNUSED_ASSIGNMENTS, DEAD_CODE, UNUSED_MUT, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 4f28d503af3c..a10a5e7d5f26 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3191,3 +3191,10 @@ pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { #[suggestion_part(code = ")")] pub right: Span, } + +#[derive(LintDiagnostic)] +#[diag(lint_unused_visibilities)] +pub(crate) struct UnusedVisibility { + #[suggestion(style = "short", code = "", applicability = "machine-applicable")] + pub span: Span, +} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 2f0333160f52..e8bd8f8f7099 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -143,6 +143,7 @@ UNUSED_QUALIFICATIONS, UNUSED_UNSAFE, UNUSED_VARIABLES, + UNUSED_VISIBILITIES, USELESS_DEPRECATED, VARARGS_WITHOUT_PATTERN, WARNINGS, @@ -693,6 +694,26 @@ "detect variables which are not used in any way" } +declare_lint! { + /// The `unused_visibilities` lint detects visibility qualifiers (like `pub`) + /// on a `const _` item. + /// + /// ### Example + /// + /// ```rust + /// pub const _: () = {}; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// These qualifiers have no effect. + pub UNUSED_VISIBILITIES, + Warn, + "detect visibility qualifiers on `const _` items" +} + declare_lint! { /// The `unused_assignments` lint detects assignments that will never be read. /// diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 3c6e7d04a29d..19ba27a27eaf 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -696,6 +696,7 @@ pub enum BuiltinLintDiag { extern_crate: Symbol, local_crate: Symbol, }, + UnusedVisibility(Span), AttributeLint(AttributeLintKind), } diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr index 70d71f6c4ea1..c94b7777f3e9 100644 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr @@ -71,10 +71,10 @@ LL | impl core::fmt::Display for X | ^^^^^^^^^^^^^^^^^^ error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:113:14 + --> tests/ui-toml/absolute_paths/absolute_paths.rs:113:10 | -LL | pub const _: crate::S = { - | ^^^^^^^^ +LL | const _: crate::S = { + | ^^^^^^^^ error: consider bringing this path into scope with the `use` keyword --> tests/ui-toml/absolute_paths/absolute_paths.rs:114:9 diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs index c024f2f513ce..a3982b8f6540 100644 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs @@ -110,7 +110,7 @@ mod m1 { } //~[no_short]v absolute_paths -pub const _: crate::S = { +const _: crate::S = { let crate::S = m1::S; //~[no_short] absolute_paths crate::m1::S diff --git a/tests/ui/consts/promoted_const_call3.rs b/tests/ui/consts/promoted_const_call3.rs index dc05a3b58442..82e9eac31d5c 100644 --- a/tests/ui/consts/promoted_const_call3.rs +++ b/tests/ui/consts/promoted_const_call3.rs @@ -4,12 +4,12 @@ pub const fn id(x: T) -> T { x } //~^ ERROR: destructor of `String` cannot be evaluated at compile-time }; -pub const _: () = { +const _: () = { let _: &'static _ = &id(&String::new()); //~^ ERROR: destructor of `String` cannot be evaluated at compile-time }; -pub const _: () = { +const _: () = { let _: &'static _ = &std::mem::ManuallyDrop::new(String::new()); //~^ ERROR: temporary value dropped while borrowed }; diff --git a/tests/ui/consts/ptr_is_null.rs b/tests/ui/consts/ptr_is_null.rs index 8b41f5718e8d..9f8a1697fd70 100644 --- a/tests/ui/consts/ptr_is_null.rs +++ b/tests/ui/consts/ptr_is_null.rs @@ -5,12 +5,12 @@ const FOO: &usize = &42; -pub const _: () = assert!(!(FOO as *const usize).is_null()); +const _: () = assert!(!(FOO as *const usize).is_null()); -pub const _: () = assert!(!(42 as *const usize).is_null()); +const _: () = assert!(!(42 as *const usize).is_null()); -pub const _: () = assert!((0 as *const usize).is_null()); +const _: () = assert!((0 as *const usize).is_null()); -pub const _: () = assert!(std::ptr::null::().is_null()); +const _: () = assert!(std::ptr::null::().is_null()); -pub const _: () = assert!(!("foo" as *const str).is_null()); +const _: () = assert!(!("foo" as *const str).is_null()); diff --git a/tests/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr b/tests/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr index 77c8d1eab584..506791fd1726 100644 --- a/tests/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr +++ b/tests/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr @@ -413,3 +413,21 @@ note: the lint level is defined here LL | #![forbid(forbidden_lint_groups)] | ^^^^^^^^^^^^^^^^^^^^^ +Future breakage diagnostic: +error: warn(unused) incompatible with previous forbid + --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:22:13 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | #![deny(unused)] +LL | #![warn(unused)] + | ^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 +note: the lint level is defined here + --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:17:11 + | +LL | #![forbid(forbidden_lint_groups)] + | ^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/lint/outer-forbid.stderr b/tests/ui/lint/outer-forbid.stderr index 64a1077462ab..7810ca223f8a 100644 --- a/tests/ui/lint/outer-forbid.stderr +++ b/tests/ui/lint/outer-forbid.stderr @@ -453,3 +453,21 @@ note: the lint level is defined here LL | #![forbid(forbidden_lint_groups)] | ^^^^^^^^^^^^^^^^^^^^^ +Future breakage diagnostic: +error: allow(unused) incompatible with previous forbid + --> $DIR/outer-forbid.rs:25:9 + | +LL | #![forbid(unused, non_snake_case)] + | ------ `forbid` level set here +... +LL | #[allow(unused)] + | ^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 +note: the lint level is defined here + --> $DIR/outer-forbid.rs:18:11 + | +LL | #![forbid(forbidden_lint_groups)] + | ^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/lint/unused-visibilities.fixed b/tests/ui/lint/unused-visibilities.fixed new file mode 100644 index 000000000000..3dd7cde0c9e2 --- /dev/null +++ b/tests/ui/lint/unused-visibilities.fixed @@ -0,0 +1,12 @@ +//@ check-pass +//@ run-rustfix + +#![warn(unused_visibilities)] + + const _: () = {}; +//~^WARN visibility qualifiers have no effect on `const _` declarations + + const _: () = {}; +//~^WARN visibility qualifiers have no effect on `const _` declarations + +fn main() {} diff --git a/tests/ui/lint/unused-visibilities.rs b/tests/ui/lint/unused-visibilities.rs new file mode 100644 index 000000000000..51bcd34599ad --- /dev/null +++ b/tests/ui/lint/unused-visibilities.rs @@ -0,0 +1,12 @@ +//@ check-pass +//@ run-rustfix + +#![warn(unused_visibilities)] + +pub const _: () = {}; +//~^WARN visibility qualifiers have no effect on `const _` declarations + +pub(self) const _: () = {}; +//~^WARN visibility qualifiers have no effect on `const _` declarations + +fn main() {} diff --git a/tests/ui/lint/unused-visibilities.stderr b/tests/ui/lint/unused-visibilities.stderr new file mode 100644 index 000000000000..032e2821d987 --- /dev/null +++ b/tests/ui/lint/unused-visibilities.stderr @@ -0,0 +1,20 @@ +warning: visibility qualifiers have no effect on `const _` declarations + --> $DIR/unused-visibilities.rs:6:1 + | +LL | pub const _: () = {}; + | ^^^ help: remove the qualifier + | +note: the lint level is defined here + --> $DIR/unused-visibilities.rs:4:9 + | +LL | #![warn(unused_visibilities)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: visibility qualifiers have no effect on `const _` declarations + --> $DIR/unused-visibilities.rs:9:1 + | +LL | pub(self) const _: () = {}; + | ^^^^^^^^^ help: remove the qualifier + +warning: 2 warnings emitted + diff --git a/tests/ui/traits/const-traits/call.rs b/tests/ui/traits/const-traits/call.rs index b1080fe78bb5..360c08e1b7fe 100644 --- a/tests/ui/traits/const-traits/call.rs +++ b/tests/ui/traits/const-traits/call.rs @@ -3,7 +3,7 @@ #![feature(const_closures, const_trait_impl)] #![allow(incomplete_features)] -pub const _: () = { +const _: () = { assert!((const || true)()); //~^ ERROR }: [const] Fn()` is not satisfied }; From 8cc9c5ebb19a8d594ac36e2e33307f5def7b60fc Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sun, 28 Sep 2025 18:12:17 -0400 Subject: [PATCH 367/585] Add warn-by-default lint for visibility on `const _` declarations Add a warn-by-default `unused_visibility` lint for visibility qualifiers on `const _` declarations - e.g. `pub const _: () = ();`. These have no effect. --- tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr | 6 +++--- tests/ui-toml/absolute_paths/absolute_paths.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr b/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr index 70d71f6c4ea1..c94b7777f3e9 100644 --- a/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr +++ b/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr @@ -71,10 +71,10 @@ LL | impl core::fmt::Display for X | ^^^^^^^^^^^^^^^^^^ error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:113:14 + --> tests/ui-toml/absolute_paths/absolute_paths.rs:113:10 | -LL | pub const _: crate::S = { - | ^^^^^^^^ +LL | const _: crate::S = { + | ^^^^^^^^ error: consider bringing this path into scope with the `use` keyword --> tests/ui-toml/absolute_paths/absolute_paths.rs:114:9 diff --git a/tests/ui-toml/absolute_paths/absolute_paths.rs b/tests/ui-toml/absolute_paths/absolute_paths.rs index c024f2f513ce..a3982b8f6540 100644 --- a/tests/ui-toml/absolute_paths/absolute_paths.rs +++ b/tests/ui-toml/absolute_paths/absolute_paths.rs @@ -110,7 +110,7 @@ mod m1 { } //~[no_short]v absolute_paths -pub const _: crate::S = { +const _: crate::S = { let crate::S = m1::S; //~[no_short] absolute_paths crate::m1::S From 4cc2f952e41ac4c3bbd0e5e8737238f06529fb7b Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Tue, 30 Sep 2025 10:05:20 -0400 Subject: [PATCH 368/585] Elaborate lint explanation --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index e8bd8f8f7099..740530daf2bd 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -708,7 +708,7 @@ /// /// ### Explanation /// - /// These qualifiers have no effect. + /// These qualifiers have no effect, as `const _` items are unnameable. pub UNUSED_VISIBILITIES, Warn, "detect visibility qualifiers on `const _` items" From 6b5da2f17798a2232d793fc06daeb764a04b9386 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 3 Dec 2025 11:37:54 -0500 Subject: [PATCH 369/585] Don't warn when underscore is passed to macro --- compiler/rustc_ast_passes/src/ast_validation.rs | 1 + tests/ui/lint/unused-visibilities.fixed | 17 +++++++++++++++++ tests/ui/lint/unused-visibilities.rs | 17 +++++++++++++++++ tests/ui/lint/unused-visibilities.stderr | 13 ++++++++++++- 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 06a35e691929..ddb19f5e7915 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1349,6 +1349,7 @@ fn visit_item(&mut self, item: &'a Item) { } if ident.name == kw::Underscore && !matches!(item.vis.kind, VisibilityKind::Inherited) + && ident.span.eq_ctxt(item.vis.span) { self.lint_buffer.buffer_lint( UNUSED_VISIBILITIES, diff --git a/tests/ui/lint/unused-visibilities.fixed b/tests/ui/lint/unused-visibilities.fixed index 3dd7cde0c9e2..97c1a5c73249 100644 --- a/tests/ui/lint/unused-visibilities.fixed +++ b/tests/ui/lint/unused-visibilities.fixed @@ -9,4 +9,21 @@ const _: () = {}; //~^WARN visibility qualifiers have no effect on `const _` declarations +macro_rules! foo { + () => { + const _: () = {}; + //~^WARN visibility qualifiers have no effect on `const _` declarations + }; +} + +foo!(); + +macro_rules! bar { + ($tt:tt) => { + pub const $tt: () = {}; + }; +} + +bar!(_); + fn main() {} diff --git a/tests/ui/lint/unused-visibilities.rs b/tests/ui/lint/unused-visibilities.rs index 51bcd34599ad..4bcbd1201e4a 100644 --- a/tests/ui/lint/unused-visibilities.rs +++ b/tests/ui/lint/unused-visibilities.rs @@ -9,4 +9,21 @@ pub(self) const _: () = {}; //~^WARN visibility qualifiers have no effect on `const _` declarations +macro_rules! foo { + () => { + pub const _: () = {}; + //~^WARN visibility qualifiers have no effect on `const _` declarations + }; +} + +foo!(); + +macro_rules! bar { + ($tt:tt) => { + pub const $tt: () = {}; + }; +} + +bar!(_); + fn main() {} diff --git a/tests/ui/lint/unused-visibilities.stderr b/tests/ui/lint/unused-visibilities.stderr index 032e2821d987..f70d654b30b1 100644 --- a/tests/ui/lint/unused-visibilities.stderr +++ b/tests/ui/lint/unused-visibilities.stderr @@ -16,5 +16,16 @@ warning: visibility qualifiers have no effect on `const _` declarations LL | pub(self) const _: () = {}; | ^^^^^^^^^ help: remove the qualifier -warning: 2 warnings emitted +warning: visibility qualifiers have no effect on `const _` declarations + --> $DIR/unused-visibilities.rs:14:9 + | +LL | pub const _: () = {}; + | ^^^ help: remove the qualifier +... +LL | foo!(); + | ------ in this macro invocation + | + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 3 warnings emitted From 9e7200967eb051f1635e13196003c5d4d8c8ace0 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 5 Dec 2025 11:22:30 -0500 Subject: [PATCH 370/585] Add note to lint message --- compiler/rustc_lint/messages.ftl | 1 + compiler/rustc_lint/src/lints.rs | 1 + tests/ui/lint/unused-visibilities.stderr | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index fac26b52176d..5754bc9621a1 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -979,6 +979,7 @@ lint_unused_op = unused {$op} that must be used lint_unused_result = unused result of type `{$ty}` lint_unused_visibilities = visibility qualifiers have no effect on `const _` declarations + .note = there is no declared name for the qualifier to affect .suggestion = remove the qualifier lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expression or result diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index a10a5e7d5f26..1bec316ce45a 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3194,6 +3194,7 @@ pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { #[derive(LintDiagnostic)] #[diag(lint_unused_visibilities)] +#[note] pub(crate) struct UnusedVisibility { #[suggestion(style = "short", code = "", applicability = "machine-applicable")] pub span: Span, diff --git a/tests/ui/lint/unused-visibilities.stderr b/tests/ui/lint/unused-visibilities.stderr index f70d654b30b1..3aefb869dafd 100644 --- a/tests/ui/lint/unused-visibilities.stderr +++ b/tests/ui/lint/unused-visibilities.stderr @@ -4,6 +4,7 @@ warning: visibility qualifiers have no effect on `const _` declarations LL | pub const _: () = {}; | ^^^ help: remove the qualifier | + = note: there is no declared name for the qualifier to affect note: the lint level is defined here --> $DIR/unused-visibilities.rs:4:9 | @@ -15,6 +16,8 @@ warning: visibility qualifiers have no effect on `const _` declarations | LL | pub(self) const _: () = {}; | ^^^^^^^^^ help: remove the qualifier + | + = note: there is no declared name for the qualifier to affect warning: visibility qualifiers have no effect on `const _` declarations --> $DIR/unused-visibilities.rs:14:9 @@ -25,6 +28,7 @@ LL | pub const _: () = {}; LL | foo!(); | ------ in this macro invocation | + = note: there is no declared name for the qualifier to affect = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) warning: 3 warnings emitted From 43fa060c38e06df99985007ecfff8b86c9fad7c5 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sat, 6 Dec 2025 13:41:32 -0500 Subject: [PATCH 371/585] Expand lint note --- compiler/rustc_lint/messages.ftl | 2 +- tests/ui/lint/unused-visibilities.stderr | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 5754bc9621a1..bc1c246b8f03 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -979,7 +979,7 @@ lint_unused_op = unused {$op} that must be used lint_unused_result = unused result of type `{$ty}` lint_unused_visibilities = visibility qualifiers have no effect on `const _` declarations - .note = there is no declared name for the qualifier to affect + .note = `const _` does not declare a name, so there is nothing for the qualifier to apply to .suggestion = remove the qualifier lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expression or result diff --git a/tests/ui/lint/unused-visibilities.stderr b/tests/ui/lint/unused-visibilities.stderr index 3aefb869dafd..e5ff2a7fcae8 100644 --- a/tests/ui/lint/unused-visibilities.stderr +++ b/tests/ui/lint/unused-visibilities.stderr @@ -4,7 +4,7 @@ warning: visibility qualifiers have no effect on `const _` declarations LL | pub const _: () = {}; | ^^^ help: remove the qualifier | - = note: there is no declared name for the qualifier to affect + = note: `const _` does not declare a name, so there is nothing for the qualifier to apply to note: the lint level is defined here --> $DIR/unused-visibilities.rs:4:9 | @@ -17,7 +17,7 @@ warning: visibility qualifiers have no effect on `const _` declarations LL | pub(self) const _: () = {}; | ^^^^^^^^^ help: remove the qualifier | - = note: there is no declared name for the qualifier to affect + = note: `const _` does not declare a name, so there is nothing for the qualifier to apply to warning: visibility qualifiers have no effect on `const _` declarations --> $DIR/unused-visibilities.rs:14:9 @@ -28,7 +28,7 @@ LL | pub const _: () = {}; LL | foo!(); | ------ in this macro invocation | - = note: there is no declared name for the qualifier to affect + = note: `const _` does not declare a name, so there is nothing for the qualifier to apply to = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) warning: 3 warnings emitted From 7fdf06693a92d9d781cb794ef5b20e564f8b3eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 6 Dec 2025 22:02:23 +0100 Subject: [PATCH 372/585] Fix off-by-one staging output when testing the library --- src/bootstrap/src/core/build_steps/test.rs | 9 +++++++-- src/bootstrap/src/core/builder/cargo.rs | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 7e46b85ff9af..eb3ea1ab5120 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2818,10 +2818,15 @@ fn run_cargo_test<'a>( builder: &Builder<'_>, ) -> bool { let compiler = cargo.compiler(); + let stage = match cargo.mode() { + Mode::Std => compiler.stage, + _ => compiler.stage + 1, + }; + let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, target, builder); let _time = helpers::timeit(builder); - let _group = - description.into().and_then(|what| builder.msg_test(what, target, compiler.stage + 1)); + + let _group = description.into().and_then(|what| builder.msg_test(what, target, stage)); #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 093a754f1a4b..2ca52c72e5ec 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -98,6 +98,7 @@ pub struct Cargo { command: BootstrapCommand, args: Vec, compiler: Compiler, + mode: Mode, target: TargetSelection, rustflags: Rustflags, rustdocflags: Rustflags, @@ -141,6 +142,10 @@ pub fn compiler(&self) -> Compiler { self.compiler } + pub fn mode(&self) -> Mode { + self.mode + } + pub fn into_cmd(self) -> BootstrapCommand { self.into() } @@ -1404,6 +1409,7 @@ fn cargo( command: cargo, args: vec![], compiler, + mode, target, rustflags, rustdocflags, From 79893a050eb5b4e3104dcef8781924b83b483a1e Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Mon, 1 Dec 2025 19:02:25 +0900 Subject: [PATCH 373/585] cleaned up some tests merged tests/ui/issues/issue-2951.rs with tests/ui/type/type-parameter-names.rs Merged tests/ui/for-loop-while/break-continue-in-loop-while-contiditoin-1.rs with tests/ui/for-loop-while/break-continue-in-loop-while-contiditoin-2.rs Removed tests/ui/issues/issue-2383.rs duplicated of library\alloc\src\collections\vec_deque\tests.rs Removed tests/ui/issues/issue-20714.rs duplicated of tests/ui/empty/empty-struct-unit-expr.rs Added comment to tests/ui/match/match-option-result-mismatch.rs, tests/ui/numeric/ref-int.rs, tests/ui/box/self-assignment.rs --- tests/ui/box/self-assignment.rs | 8 ++-- tests/ui/empty/empty-struct-unit-expr.rs | 3 +- tests/ui/empty/empty-struct-unit-expr.stderr | 10 ++--- ...reak-continue-in-loop-while-condition-2.rs | 8 ---- ...-continue-in-loop-while-condition-2.stderr | 9 ---- ...break-continue-in-loop-while-condition.rs} | 32 +++++++++++--- ...k-continue-in-loop-while-condition.stderr} | 44 +++++++++++-------- tests/ui/issues/issue-20714.rs | 5 --- tests/ui/issues/issue-20714.stderr | 20 --------- tests/ui/issues/issue-2383.rs | 8 ---- tests/ui/issues/issue-2951.rs | 13 ------ tests/ui/issues/issue-2951.stderr | 20 --------- .../ui/match/match-option-result-mismatch.rs | 7 ++- .../match/match-option-result-mismatch.stderr | 7 +-- tests/ui/numeric/ref-int.rs | 1 + tests/ui/type/type-parameter-names.rs | 18 ++++++-- tests/ui/type/type-parameter-names.stderr | 21 ++++++++- 17 files changed, 106 insertions(+), 128 deletions(-) delete mode 100644 tests/ui/for-loop-while/break-continue-in-loop-while-condition-2.rs delete mode 100644 tests/ui/for-loop-while/break-continue-in-loop-while-condition-2.stderr rename tests/ui/for-loop-while/{break-continue-in-loop-while-condition-1.rs => break-continue-in-loop-while-condition.rs} (58%) rename tests/ui/for-loop-while/{break-continue-in-loop-while-condition-1.stderr => break-continue-in-loop-while-condition.stderr} (59%) delete mode 100644 tests/ui/issues/issue-20714.rs delete mode 100644 tests/ui/issues/issue-20714.stderr delete mode 100644 tests/ui/issues/issue-2383.rs delete mode 100644 tests/ui/issues/issue-2951.rs delete mode 100644 tests/ui/issues/issue-2951.stderr diff --git a/tests/ui/box/self-assignment.rs b/tests/ui/box/self-assignment.rs index 50c432288ce1..3689ddac5d10 100644 --- a/tests/ui/box/self-assignment.rs +++ b/tests/ui/box/self-assignment.rs @@ -1,8 +1,10 @@ //@ run-pass +//! regression test for + #![allow(dead_code)] pub fn main() { - let mut x: Box<_> = Box::new(3); - x = x; - assert_eq!(*x, 3); + let mut x: Box<_> = Box::new(3); + x = x; + assert_eq!(*x, 3); } diff --git a/tests/ui/empty/empty-struct-unit-expr.rs b/tests/ui/empty/empty-struct-unit-expr.rs index c71ea3bdce72..5a0d57edb13d 100644 --- a/tests/ui/empty/empty-struct-unit-expr.rs +++ b/tests/ui/empty/empty-struct-unit-expr.rs @@ -1,4 +1,5 @@ // Can't use unit struct as constructor function +// related issue //@ aux-build:empty-struct.rs @@ -8,7 +9,7 @@ struct Empty2; enum E { - Empty4 + Empty4, } fn main() { diff --git a/tests/ui/empty/empty-struct-unit-expr.stderr b/tests/ui/empty/empty-struct-unit-expr.stderr index e97209527fe3..511c144f926c 100644 --- a/tests/ui/empty/empty-struct-unit-expr.stderr +++ b/tests/ui/empty/empty-struct-unit-expr.stderr @@ -1,5 +1,5 @@ error[E0618]: expected function, found struct `Empty2` - --> $DIR/empty-struct-unit-expr.rs:15:14 + --> $DIR/empty-struct-unit-expr.rs:16:14 | LL | struct Empty2; | ------------- struct `Empty2` defined here @@ -16,9 +16,9 @@ LL + let e2 = Empty2; | error[E0618]: expected function, found enum variant `E::Empty4` - --> $DIR/empty-struct-unit-expr.rs:16:14 + --> $DIR/empty-struct-unit-expr.rs:17:14 | -LL | Empty4 +LL | Empty4, | ------ enum variant `E::Empty4` defined here ... LL | let e4 = E::Empty4(); @@ -33,7 +33,7 @@ LL + let e4 = E::Empty4; | error[E0618]: expected function, found struct `XEmpty2` - --> $DIR/empty-struct-unit-expr.rs:18:15 + --> $DIR/empty-struct-unit-expr.rs:19:15 | LL | let xe2 = XEmpty2(); | ^^^^^^^-- @@ -47,7 +47,7 @@ LL + let xe2 = XEmpty2; | error[E0618]: expected function, found enum variant `XE::XEmpty4` - --> $DIR/empty-struct-unit-expr.rs:19:15 + --> $DIR/empty-struct-unit-expr.rs:20:15 | LL | let xe4 = XE::XEmpty4(); | ^^^^^^^^^^^-- diff --git a/tests/ui/for-loop-while/break-continue-in-loop-while-condition-2.rs b/tests/ui/for-loop-while/break-continue-in-loop-while-condition-2.rs deleted file mode 100644 index dece55968b6a..000000000000 --- a/tests/ui/for-loop-while/break-continue-in-loop-while-condition-2.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[allow(unreachable_code)] - -fn main() { - loop { - break while continue { //~ ERROR E0590 - } - } -} diff --git a/tests/ui/for-loop-while/break-continue-in-loop-while-condition-2.stderr b/tests/ui/for-loop-while/break-continue-in-loop-while-condition-2.stderr deleted file mode 100644 index e1b5ae325120..000000000000 --- a/tests/ui/for-loop-while/break-continue-in-loop-while-condition-2.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0590]: `break` or `continue` with no label in the condition of a `while` loop - --> $DIR/issue-50802.rs:5:21 - | -LL | break while continue { - | ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0590`. diff --git a/tests/ui/for-loop-while/break-continue-in-loop-while-condition-1.rs b/tests/ui/for-loop-while/break-continue-in-loop-while-condition.rs similarity index 58% rename from tests/ui/for-loop-while/break-continue-in-loop-while-condition-1.rs rename to tests/ui/for-loop-while/break-continue-in-loop-while-condition.rs index e7f933ab22ea..d1fcb6dbb537 100644 --- a/tests/ui/for-loop-while/break-continue-in-loop-while-condition-1.rs +++ b/tests/ui/for-loop-while/break-continue-in-loop-while-condition.rs @@ -1,3 +1,6 @@ +//! regression test for #37576, #50802 +//! Tests that using unlabeled `break` or `continue` within a loop or while's condition. + fn main() { 'test_1: while break 'test_1 {} while break {} @@ -7,9 +10,13 @@ fn main() { while let true = break {} //~^ ERROR `break` or `continue` with no label - loop { 'test_3: while break 'test_3 {} } - loop { while break {} } - //~^ ERROR `break` or `continue` with no label + loop { + 'test_3: while break 'test_3 {} + } + loop { + while break {} + //~^ ERROR `break` or `continue` with no label + } loop { 'test_4: while break 'test_4 {} @@ -29,9 +36,13 @@ fn main() { while let true = continue {} //~^ ERROR `break` or `continue` with no label - loop { 'test_7: while continue 'test_7 {} } - loop { while continue {} } - //~^ ERROR `break` or `continue` with no label + loop { + 'test_7: while continue 'test_7 {} + } + loop { + while continue {} + //~^ ERROR `break` or `continue` with no label + } loop { 'test_8: while continue 'test_8 {} @@ -42,4 +53,13 @@ fn main() { //~^ ERROR `break` or `continue` with no label continue; } + + 'test_9: loop { + break while continue 'test_9 {}; + } + loop { + break while continue { + //~^ ERROR `break` or `continue` with no label + }; + } } diff --git a/tests/ui/for-loop-while/break-continue-in-loop-while-condition-1.stderr b/tests/ui/for-loop-while/break-continue-in-loop-while-condition.stderr similarity index 59% rename from tests/ui/for-loop-while/break-continue-in-loop-while-condition-1.stderr rename to tests/ui/for-loop-while/break-continue-in-loop-while-condition.stderr index d19e1f45393a..dac6dc2e30bc 100644 --- a/tests/ui/for-loop-while/break-continue-in-loop-while-condition-1.stderr +++ b/tests/ui/for-loop-while/break-continue-in-loop-while-condition.stderr @@ -1,51 +1,57 @@ error[E0590]: `break` or `continue` with no label in the condition of a `while` loop - --> $DIR/issue-37576.rs:3:11 + --> $DIR/break-continue-in-loop-while-condition.rs:6:11 | LL | while break {} | ^^^^^ unlabeled `break` in the condition of a `while` loop error[E0590]: `break` or `continue` with no label in the condition of a `while` loop - --> $DIR/issue-37576.rs:7:22 + --> $DIR/break-continue-in-loop-while-condition.rs:10:22 | LL | while let true = break {} | ^^^^^ unlabeled `break` in the condition of a `while` loop error[E0590]: `break` or `continue` with no label in the condition of a `while` loop - --> $DIR/issue-37576.rs:11:18 - | -LL | loop { while break {} } - | ^^^^^ unlabeled `break` in the condition of a `while` loop - -error[E0590]: `break` or `continue` with no label in the condition of a `while` loop - --> $DIR/issue-37576.rs:19:15 + --> $DIR/break-continue-in-loop-while-condition.rs:17:15 | LL | while break {} | ^^^^^ unlabeled `break` in the condition of a `while` loop error[E0590]: `break` or `continue` with no label in the condition of a `while` loop - --> $DIR/issue-37576.rs:25:11 + --> $DIR/break-continue-in-loop-while-condition.rs:26:15 + | +LL | while break {} + | ^^^^^ unlabeled `break` in the condition of a `while` loop + +error[E0590]: `break` or `continue` with no label in the condition of a `while` loop + --> $DIR/break-continue-in-loop-while-condition.rs:32:11 | LL | while continue {} | ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop error[E0590]: `break` or `continue` with no label in the condition of a `while` loop - --> $DIR/issue-37576.rs:29:22 + --> $DIR/break-continue-in-loop-while-condition.rs:36:22 | LL | while let true = continue {} | ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop error[E0590]: `break` or `continue` with no label in the condition of a `while` loop - --> $DIR/issue-37576.rs:33:18 - | -LL | loop { while continue {} } - | ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop - -error[E0590]: `break` or `continue` with no label in the condition of a `while` loop - --> $DIR/issue-37576.rs:41:15 + --> $DIR/break-continue-in-loop-while-condition.rs:43:15 | LL | while continue {} | ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop -error: aborting due to 8 previous errors +error[E0590]: `break` or `continue` with no label in the condition of a `while` loop + --> $DIR/break-continue-in-loop-while-condition.rs:52:15 + | +LL | while continue {} + | ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop + +error[E0590]: `break` or `continue` with no label in the condition of a `while` loop + --> $DIR/break-continue-in-loop-while-condition.rs:61:21 + | +LL | break while continue { + | ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0590`. diff --git a/tests/ui/issues/issue-20714.rs b/tests/ui/issues/issue-20714.rs deleted file mode 100644 index 3aa39bb7388f..000000000000 --- a/tests/ui/issues/issue-20714.rs +++ /dev/null @@ -1,5 +0,0 @@ -struct G; - -fn main() { - let g = G(); //~ ERROR: expected function, found struct `G` -} diff --git a/tests/ui/issues/issue-20714.stderr b/tests/ui/issues/issue-20714.stderr deleted file mode 100644 index f537a01582b6..000000000000 --- a/tests/ui/issues/issue-20714.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0618]: expected function, found struct `G` - --> $DIR/issue-20714.rs:4:13 - | -LL | struct G; - | -------- struct `G` defined here -... -LL | let g = G(); - | ^-- - | | - | call expression requires function - | -help: `G` is a unit struct, and does not take parentheses to be constructed - | -LL - let g = G(); -LL + let g = G; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0618`. diff --git a/tests/ui/issues/issue-2383.rs b/tests/ui/issues/issue-2383.rs deleted file mode 100644 index 5d60018ae673..000000000000 --- a/tests/ui/issues/issue-2383.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass - -use std::collections::VecDeque; - -pub fn main() { - let mut q = VecDeque::new(); - q.push_front(10); -} diff --git a/tests/ui/issues/issue-2951.rs b/tests/ui/issues/issue-2951.rs deleted file mode 100644 index e28516fa3073..000000000000 --- a/tests/ui/issues/issue-2951.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ dont-require-annotations: NOTE - -fn foo(x: T, y: U) { - let mut xx = x; - xx = y; - //~^ ERROR mismatched types - //~| NOTE expected type parameter `T`, found type parameter `U` - //~| NOTE expected type parameter `T` - //~| NOTE found type parameter `U` -} - -fn main() { -} diff --git a/tests/ui/issues/issue-2951.stderr b/tests/ui/issues/issue-2951.stderr deleted file mode 100644 index d4b45935bf9a..000000000000 --- a/tests/ui/issues/issue-2951.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-2951.rs:5:10 - | -LL | fn foo(x: T, y: U) { - | - - found type parameter - | | - | expected type parameter -LL | let mut xx = x; - | - expected due to this value -LL | xx = y; - | ^ expected type parameter `T`, found type parameter `U` - | - = note: expected type parameter `T` - found type parameter `U` - = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/match-option-result-mismatch.rs b/tests/ui/match/match-option-result-mismatch.rs index 7fdc6e179e47..e7c185cf09b8 100644 --- a/tests/ui/match/match-option-result-mismatch.rs +++ b/tests/ui/match/match-option-result-mismatch.rs @@ -1,6 +1,9 @@ +//! regression test for + fn main() { - match None { //~ NOTE this expression has type `Option<_>` - Err(_) => () + match None { + //~^ NOTE this expression has type `Option<_>` + Err(_) => (), //~^ ERROR mismatched types //~| NOTE expected enum `Option<_>` //~| NOTE found enum `Result<_, _>` diff --git a/tests/ui/match/match-option-result-mismatch.stderr b/tests/ui/match/match-option-result-mismatch.stderr index 2a757b44dc83..212d322fe2d9 100644 --- a/tests/ui/match/match-option-result-mismatch.stderr +++ b/tests/ui/match/match-option-result-mismatch.stderr @@ -1,16 +1,17 @@ error[E0308]: mismatched types - --> $DIR/issue-3680.rs:3:9 + --> $DIR/match-option-result-mismatch.rs:6:9 | LL | match None { | ---- this expression has type `Option<_>` -LL | Err(_) => () +LL | +LL | Err(_) => (), | ^^^^^^ expected `Option<_>`, found `Result<_, _>` | = note: expected enum `Option<_>` found enum `Result<_, _>` help: try wrapping the pattern in `Some` | -LL | Some(Err(_)) => () +LL | Some(Err(_)) => (), | +++++ + error: aborting due to 1 previous error diff --git a/tests/ui/numeric/ref-int.rs b/tests/ui/numeric/ref-int.rs index a4f9b3718446..da4f4fc07082 100644 --- a/tests/ui/numeric/ref-int.rs +++ b/tests/ui/numeric/ref-int.rs @@ -1,4 +1,5 @@ //@ run-pass +//! regression test for pub fn main() { let x = 1; diff --git a/tests/ui/type/type-parameter-names.rs b/tests/ui/type/type-parameter-names.rs index fbd1885f543f..0b427314f133 100644 --- a/tests/ui/type/type-parameter-names.rs +++ b/tests/ui/type/type-parameter-names.rs @@ -1,14 +1,24 @@ // Test that we print out the names of type parameters correctly in // our error messages. +// related issue //@ dont-require-annotations: NOTE fn foo(x: Foo) -> Bar { x -//~^ ERROR mismatched types -//~| NOTE expected type parameter `Bar`, found type parameter `Foo` -//~| NOTE expected type parameter `Bar` -//~| NOTE found type parameter `Foo` + //~^ ERROR mismatched types + //~| NOTE expected type parameter `Bar`, found type parameter `Foo` + //~| NOTE expected type parameter `Bar` + //~| NOTE found type parameter `Foo` +} + +fn bar(x: Foo, y: Bar) { + let mut xx = x; + xx = y; + //~^ ERROR mismatched types + //~| NOTE expected type parameter `Foo`, found type parameter `Bar` + //~| NOTE expected type parameter `Foo` + //~| NOTE found type parameter `Bar` } fn main() {} diff --git a/tests/ui/type/type-parameter-names.stderr b/tests/ui/type/type-parameter-names.stderr index 795a260688c4..f84449ef0d36 100644 --- a/tests/ui/type/type-parameter-names.stderr +++ b/tests/ui/type/type-parameter-names.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/type-parameter-names.rs:7:5 + --> $DIR/type-parameter-names.rs:8:5 | LL | fn foo(x: Foo) -> Bar { | --- --- --- expected `Bar` because of return type @@ -15,6 +15,23 @@ LL | x = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters = note: the caller chooses a type for `Bar` which can be different from `Foo` -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/type-parameter-names.rs:17:10 + | +LL | fn bar(x: Foo, y: Bar) { + | --- --- found type parameter + | | + | expected type parameter +LL | let mut xx = x; + | - expected due to this value +LL | xx = y; + | ^ expected type parameter `Foo`, found type parameter `Bar` + | + = note: expected type parameter `Foo` + found type parameter `Bar` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. From 5f9aca7e74ca901cd6e3fad6dbc6a5a14f160ea1 Mon Sep 17 00:00:00 2001 From: RustyYato Date: Fri, 5 Dec 2025 12:24:31 -0700 Subject: [PATCH 374/585] Add `#[inline]` to `Layout::is_size_align_valid` add Alignment::new_unchecked::precondition_check to allowlist --- library/core/src/alloc/layout.rs | 1 + tests/codegen-units/item-collection/opaque-return-impls.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 73d929fbc7f4..a4e25b8734a9 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -65,6 +65,7 @@ pub const fn from_size_align(size: usize, align: usize) -> Result bool { let Some(align) = Alignment::new(align) else { return false }; if size > Self::max_size_for_align(align) { diff --git a/tests/codegen-units/item-collection/opaque-return-impls.rs b/tests/codegen-units/item-collection/opaque-return-impls.rs index 1659b62175b7..d54951b933fd 100644 --- a/tests/codegen-units/item-collection/opaque-return-impls.rs +++ b/tests/codegen-units/item-collection/opaque-return-impls.rs @@ -47,6 +47,7 @@ pub fn foo2() -> Box { //~ MONO_ITEM fn std::alloc::Global::alloc_impl //~ MONO_ITEM fn std::boxed::Box::::new //~ MONO_ITEM fn std::alloc::Layout::from_size_align_unchecked::precondition_check +//~ MONO_ITEM fn std::ptr::Alignment::new_unchecked::precondition_check //~ MONO_ITEM fn std::ptr::NonNull::::new_unchecked::precondition_check struct Counter { From 85f7a6ed610933f32966483dc4aff2399928f3e9 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 7 Dec 2025 13:40:38 +1100 Subject: [PATCH 375/585] Move Android-related discovery out of `core::debuggers` While some of this information is needed by debugger discovery, it is also needed by non-debuginfo tests, so the code doesn't belong in the `debuggers` module. --- src/bootstrap/src/core/{debuggers => }/android.rs | 0 src/bootstrap/src/core/build_steps/test.rs | 11 ++++------- src/bootstrap/src/core/debuggers/mod.rs | 2 -- src/bootstrap/src/core/mod.rs | 1 + 4 files changed, 5 insertions(+), 9 deletions(-) rename src/bootstrap/src/core/{debuggers => }/android.rs (100%) diff --git a/src/bootstrap/src/core/debuggers/android.rs b/src/bootstrap/src/core/android.rs similarity index 100% rename from src/bootstrap/src/core/debuggers/android.rs rename to src/bootstrap/src/core/android.rs diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 7e46b85ff9af..64c8c1e56613 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -29,7 +29,7 @@ }; use crate::core::config::TargetSelection; use crate::core::config::flags::{Subcommand, get_completion, top_level_help}; -use crate::core::debuggers; +use crate::core::{android, debuggers}; use crate::utils::build_stamp::{self, BuildStamp}; use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{ @@ -2114,12 +2114,9 @@ fn run(self, builder: &Builder<'_>) { builder.config.python.as_ref().expect("python is required for running rustdoc tests"), ); - // FIXME(#148099): Currently we set these Android-related flags in all - // modes, even though they should only be needed in "debuginfo" mode, - // because the GDB-discovery code in compiletest currently assumes that - // `--android-cross-path` is always set for Android targets. - if let Some(debuggers::Android { adb_path, adb_test_dir, android_cross_path }) = - debuggers::discover_android(builder, target) + // Discover and set some flags related to running tests on Android targets. + if let Some(android::Android { adb_path, adb_test_dir, android_cross_path }) = + android::discover_android(builder, target) { cmd.arg("--adb-path").arg(adb_path); cmd.arg("--adb-test-dir").arg(adb_test_dir); diff --git a/src/bootstrap/src/core/debuggers/mod.rs b/src/bootstrap/src/core/debuggers/mod.rs index 011ce4081a43..a11eda8e686e 100644 --- a/src/bootstrap/src/core/debuggers/mod.rs +++ b/src/bootstrap/src/core/debuggers/mod.rs @@ -1,10 +1,8 @@ //! Code for discovering debuggers and debugger-related configuration, so that //! it can be passed to compiletest when running debuginfo tests. -pub(crate) use self::android::{Android, discover_android}; pub(crate) use self::gdb::{Gdb, discover_gdb}; pub(crate) use self::lldb::{Lldb, discover_lldb}; -mod android; mod gdb; mod lldb; diff --git a/src/bootstrap/src/core/mod.rs b/src/bootstrap/src/core/mod.rs index f27a09c81c55..4df2ed319da6 100644 --- a/src/bootstrap/src/core/mod.rs +++ b/src/bootstrap/src/core/mod.rs @@ -1,3 +1,4 @@ +pub(crate) mod android; pub(crate) mod build_steps; pub(crate) mod builder; pub(crate) mod config; From 8f35bd17cc4f88d3069a78d30890e1cfcf007ef1 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 6 Dec 2025 22:22:09 +1100 Subject: [PATCH 376/585] Move ambient gdb discovery from compiletest to bootstrap --- src/bootstrap/src/core/android.rs | 6 ++- src/bootstrap/src/core/build_steps/test.rs | 10 ++--- src/bootstrap/src/core/debuggers/gdb.rs | 37 ++++++++++++++++-- src/tools/compiletest/src/common.rs | 2 +- src/tools/compiletest/src/debuggers.rs | 38 ------------------- src/tools/compiletest/src/lib.rs | 4 +- .../compiletest/src/runtest/debuginfo.rs | 8 ++-- 7 files changed, 51 insertions(+), 54 deletions(-) diff --git a/src/bootstrap/src/core/android.rs b/src/bootstrap/src/core/android.rs index b1ad9ca555fb..60f7ca4dbcd0 100644 --- a/src/bootstrap/src/core/android.rs +++ b/src/bootstrap/src/core/android.rs @@ -10,11 +10,15 @@ pub(crate) struct Android { } pub(crate) fn discover_android(builder: &Builder<'_>, target: TargetSelection) -> Option { + if !target.contains("android") { + return None; + } + let adb_path = "adb"; // See . let adb_test_dir = "/data/local/tmp/work"; - let android_cross_path = if target.contains("android") && !builder.config.dry_run() { + let android_cross_path = if !builder.config.dry_run() { builder.cc(target).parent().unwrap().parent().unwrap().to_owned() } else { PathBuf::new() diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 64c8c1e56613..4237d39d7425 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2115,17 +2115,17 @@ fn run(self, builder: &Builder<'_>) { ); // Discover and set some flags related to running tests on Android targets. - if let Some(android::Android { adb_path, adb_test_dir, android_cross_path }) = - android::discover_android(builder, target) - { + let android = android::discover_android(builder, target); + if let Some(android::Android { adb_path, adb_test_dir, android_cross_path }) = &android { cmd.arg("--adb-path").arg(adb_path); cmd.arg("--adb-test-dir").arg(adb_test_dir); cmd.arg("--android-cross-path").arg(android_cross_path); } if mode == "debuginfo" { - if let Some(debuggers::Gdb { gdb }) = debuggers::discover_gdb(builder) { - cmd.arg("--gdb").arg(gdb); + if let Some(debuggers::Gdb { gdb }) = debuggers::discover_gdb(builder, android.as_ref()) + { + cmd.arg("--gdb").arg(gdb.as_ref()); } if let Some(debuggers::Lldb { lldb_exe, lldb_version }) = diff --git a/src/bootstrap/src/core/debuggers/gdb.rs b/src/bootstrap/src/core/debuggers/gdb.rs index ddad0909e4f0..2eb441ee9852 100644 --- a/src/bootstrap/src/core/debuggers/gdb.rs +++ b/src/bootstrap/src/core/debuggers/gdb.rs @@ -1,13 +1,42 @@ +use std::borrow::Cow; use std::path::Path; +use crate::core::android; use crate::core::builder::Builder; +use crate::utils::exec::BootstrapCommand; pub(crate) struct Gdb<'a> { - pub(crate) gdb: &'a Path, + pub(crate) gdb: Cow<'a, Path>, } -pub(crate) fn discover_gdb<'a>(builder: &'a Builder<'_>) -> Option> { - let gdb = builder.config.gdb.as_deref()?; +pub(crate) fn discover_gdb<'a>( + builder: &'a Builder<'_>, + android: Option<&android::Android>, +) -> Option> { + // If there's an explicitly-configured gdb, use that. + if let Some(gdb) = builder.config.gdb.as_deref() { + // FIXME(Zalathar): Consider returning None if gdb is an empty string, + // as a way to explicitly disable ambient gdb discovery. + let gdb = Cow::Borrowed(gdb); + return Some(Gdb { gdb }); + } - Some(Gdb { gdb }) + // Otherwise, fall back to whatever gdb is sitting around in PATH. + // (That's the historical behavior, but maybe we should require opt-in?) + + let gdb: Cow<'_, Path> = match android { + Some(android::Android { android_cross_path, .. }) => { + android_cross_path.join("bin/gdb").into() + } + None => Path::new("gdb").into(), + }; + + // Check whether an ambient gdb exists, by running `gdb --version`. + let output = { + let mut gdb_command = BootstrapCommand::new(gdb.as_ref()).allow_failure(); + gdb_command.arg("--version"); + gdb_command.run_capture(builder) + }; + + if output.is_success() { Some(Gdb { gdb }) } else { None } } diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index d8472691afdf..02b93593cbbd 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -566,7 +566,7 @@ pub struct Config { /// /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for /// `arm-linux-androideabi` target. - pub android_cross_path: Utf8PathBuf, + pub android_cross_path: Option, /// Extra parameter to run adb on `arm-linux-androideabi`. /// diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs index 791c5f03c21a..b0d0372454e2 100644 --- a/src/tools/compiletest/src/debuggers.rs +++ b/src/tools/compiletest/src/debuggers.rs @@ -54,15 +54,6 @@ pub(crate) fn configure_lldb(config: &Config) -> Option> { Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() })) } -/// Returns `true` if the given target is an Android target for the -/// purposes of GDB testing. -pub(crate) fn is_android_gdb_target(target: &str) -> bool { - matches!( - &target[..], - "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" - ) -} - /// Returns `true` if the given target is a MSVC target for the purposes of CDB testing. fn is_pc_windows_msvc_target(target: &str) -> bool { target.ends_with("-pc-windows-msvc") @@ -129,35 +120,6 @@ pub(crate) fn discover_cdb(cdb: Option, target: &str) -> Option, - target: &str, - android_cross_path: &Utf8Path, -) -> Option { - #[cfg(not(windows))] - const GDB_FALLBACK: &str = "gdb"; - #[cfg(windows)] - const GDB_FALLBACK: &str = "gdb.exe"; - - let fallback_gdb = || { - if is_android_gdb_target(target) { - let mut gdb_path = android_cross_path.to_string(); - gdb_path.push_str("/bin/gdb"); - gdb_path - } else { - GDB_FALLBACK.to_owned() - } - }; - - let gdb = match gdb { - None => fallback_gdb(), - Some(ref s) if s.is_empty() => fallback_gdb(), // may be empty if configure found no gdb - Some(ref s) => s.to_owned(), - }; - - Some(Utf8PathBuf::from(gdb)) -} - pub(crate) fn query_gdb_version(gdb: &Utf8Path) -> Option { let mut version_line = None; if let Ok(output) = Command::new(&gdb).arg("--version").output() { diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index acd0d70d081f..f3bd467db3e4 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -256,12 +256,12 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { } let target = opt_str2(matches.opt_str("target")); - let android_cross_path = opt_path(matches, "android-cross-path"); + let android_cross_path = matches.opt_str("android-cross-path").map(Utf8PathBuf::from); // FIXME: `cdb_version` is *derived* from cdb, but it's *not* technically a config! let cdb = debuggers::discover_cdb(matches.opt_str("cdb"), &target); let cdb_version = cdb.as_deref().and_then(debuggers::query_cdb_version); // FIXME: `gdb_version` is *derived* from gdb, but it's *not* technically a config! - let gdb = debuggers::discover_gdb(matches.opt_str("gdb"), &target, &android_cross_path); + let gdb = matches.opt_str("gdb").map(Utf8PathBuf::from); let gdb_version = gdb.as_deref().and_then(debuggers::query_gdb_version); // FIXME: `lldb_version` is *derived* from lldb, but it's *not* technically a config! let lldb = matches.opt_str("lldb").map(Utf8PathBuf::from); diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 5ef4366b68be..ac935910205b 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -8,7 +8,7 @@ use super::debugger::DebuggerCommands; use super::{Debugger, Emit, ProcRes, TestCx, Truncated, WillExecute}; -use crate::debuggers::{extract_gdb_version, is_android_gdb_target}; +use crate::debuggers::extract_gdb_version; impl TestCx<'_> { pub(super) fn run_debuginfo_test(&self) { @@ -122,13 +122,15 @@ fn run_debuginfo_gdb_test(&self) { let exe_file = self.make_exe_name(); let debugger_run_result; - if is_android_gdb_target(&self.config.target) { + // If bootstrap gave us an `--android-cross-path`, assume the target + // needs Android-specific handling. + if let Some(android_cross_path) = self.config.android_cross_path.as_deref() { cmds = cmds.replace("run", "continue"); // write debugger script let mut script_str = String::with_capacity(2048); script_str.push_str(&format!("set charset {}\n", Self::charset())); - script_str.push_str(&format!("set sysroot {}\n", &self.config.android_cross_path)); + script_str.push_str(&format!("set sysroot {android_cross_path}\n")); script_str.push_str(&format!("file {}\n", exe_file)); script_str.push_str("target remote :5039\n"); script_str.push_str(&format!( From d54fee82f43587656cfaea63ddba6fbd05005b83 Mon Sep 17 00:00:00 2001 From: Dawid Lachowicz Date: Sat, 6 Dec 2025 19:16:00 +0000 Subject: [PATCH 377/585] contracts: fix lowering final declaration without trailing semicolon Lowering for contract delcarations incorrectly handled the final declaration statement when it didn't end in a semicolon. This change fixes the issue. --- compiler/rustc_ast_lowering/src/contract.rs | 14 ++++++++++++- tests/ui/contracts/requires-block-stmt.rs | 22 +++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/ui/contracts/requires-block-stmt.rs diff --git a/compiler/rustc_ast_lowering/src/contract.rs b/compiler/rustc_ast_lowering/src/contract.rs index 56413160e04d..6cffd8e119b7 100644 --- a/compiler/rustc_ast_lowering/src/contract.rs +++ b/compiler/rustc_ast_lowering/src/contract.rs @@ -23,7 +23,7 @@ pub(super) fn lower_contract( // The order in which things are lowered is important! I.e to // refer to variables in contract_decls from postcond/precond, // we must lower it first! - let contract_decls = self.lower_stmts(&contract.declarations).0; + let contract_decls = self.lower_decls(contract); match (&contract.requires, &contract.ensures) { (Some(req), Some(ens)) => { @@ -124,6 +124,18 @@ pub(super) fn lower_contract( } } + fn lower_decls(&mut self, contract: &rustc_ast::FnContract) -> &'hir [rustc_hir::Stmt<'hir>] { + let (decls, decls_tail) = self.lower_stmts(&contract.declarations); + + if let Some(e) = decls_tail { + // include the tail expression in the declaration statements + let tail = self.stmt_expr(e.span, *e); + self.arena.alloc_from_iter(decls.into_iter().map(|d| *d).chain([tail].into_iter())) + } else { + decls + } + } + /// Lower the precondition check intrinsic. fn lower_precond(&mut self, req: &Box) -> rustc_hir::Stmt<'hir> { let lowered_req = self.lower_expr_mut(&req); diff --git a/tests/ui/contracts/requires-block-stmt.rs b/tests/ui/contracts/requires-block-stmt.rs new file mode 100644 index 000000000000..0f0801bb65f5 --- /dev/null +++ b/tests/ui/contracts/requires-block-stmt.rs @@ -0,0 +1,22 @@ +//@ run-pass +//@ compile-flags: -Zcontract-checks=yes + +#![expect(incomplete_features)] +#![feature(contracts)] +extern crate core; +use core::contracts::requires; + +// Compound statements (those using [ExpressionWithBlock] +// (https://doc.rust-lang.org/beta/reference/expressions.html#railroad-ExpressionWithBlock)) +// like blocks, if-expressions, and loops require no trailing semicolon. This +// regression test captures the case where the last statement in the contract +// declarations has no trailing semicolon. +#[requires( + {} + true +)] +fn foo() {} + +fn main() { + foo() +} From d53f7676d1685bf1b0de1c303cf497b22f189d81 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sat, 6 Dec 2025 23:22:33 +0900 Subject: [PATCH 378/585] Check associated type where-clauses for lifetimes --- compiler/rustc_ast_passes/src/feature_gate.rs | 15 +++++---------- ...associated-type-where-non-lifetime-const.rs | 13 +++++++++++++ ...ciated-type-where-non-lifetime-const.stderr | 13 +++++++++++++ .../associated-type-where-non-lifetime-type.rs | 18 ++++++++++++++++++ ...ociated-type-where-non-lifetime-type.stderr | 13 +++++++++++++ 5 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 tests/ui/associated-types/associated-type-where-non-lifetime-const.rs create mode 100644 tests/ui/associated-types/associated-type-where-non-lifetime-const.stderr create mode 100644 tests/ui/associated-types/associated-type-where-non-lifetime-type.rs create mode 100644 tests/ui/associated-types/associated-type-where-non-lifetime-type.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2d87d8c84d7c..ee868296d9dc 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -301,17 +301,12 @@ fn visit_ty(&mut self, ty: &'a ast::Ty) { visit::walk_ty(self, ty) } - fn visit_generics(&mut self, g: &'a ast::Generics) { - for predicate in &g.where_clause.predicates { - match &predicate.kind { - ast::WherePredicateKind::BoundPredicate(bound_pred) => { - // A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`). - self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params); - } - _ => {} - } + fn visit_where_predicate_kind(&mut self, kind: &'a ast::WherePredicateKind) { + if let ast::WherePredicateKind::BoundPredicate(bound) = kind { + // A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`). + self.check_late_bound_lifetime_defs(&bound.bound_generic_params); } - visit::walk_generics(self, g); + visit::walk_where_predicate_kind(self, kind); } fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) { diff --git a/tests/ui/associated-types/associated-type-where-non-lifetime-const.rs b/tests/ui/associated-types/associated-type-where-non-lifetime-const.rs new file mode 100644 index 000000000000..31bf139e39cd --- /dev/null +++ b/tests/ui/associated-types/associated-type-where-non-lifetime-const.rs @@ -0,0 +1,13 @@ +//! regression test for #148627 + +#![feature(associated_type_defaults)] + +trait Trait { + type Assoc2 + = () + where + for [(); C]: Copy; + //~^ ERROR: only lifetime parameters can be used in this context +} + +fn main() {} diff --git a/tests/ui/associated-types/associated-type-where-non-lifetime-const.stderr b/tests/ui/associated-types/associated-type-where-non-lifetime-const.stderr new file mode 100644 index 000000000000..bd1d6e13893a --- /dev/null +++ b/tests/ui/associated-types/associated-type-where-non-lifetime-const.stderr @@ -0,0 +1,13 @@ +error[E0658]: only lifetime parameters can be used in this context + --> $DIR/associated-type-where-non-lifetime-const.rs:9:19 + | +LL | for [(); C]: Copy; + | ^ + | + = note: see issue #108185 for more information + = help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/associated-types/associated-type-where-non-lifetime-type.rs b/tests/ui/associated-types/associated-type-where-non-lifetime-type.rs new file mode 100644 index 000000000000..d4624619e6d8 --- /dev/null +++ b/tests/ui/associated-types/associated-type-where-non-lifetime-type.rs @@ -0,0 +1,18 @@ +//! regression test for #149233 + +trait Foo { + type Bar<'a> + where + Self: Sized; + fn test(&self); +} +impl Foo for () { + type Bar<'a> + = () + where + for T:; + //~^ ERROR: only lifetime parameters can be used in this context + fn test(&self) {} +} + +fn main() {} diff --git a/tests/ui/associated-types/associated-type-where-non-lifetime-type.stderr b/tests/ui/associated-types/associated-type-where-non-lifetime-type.stderr new file mode 100644 index 000000000000..a8a71b929d95 --- /dev/null +++ b/tests/ui/associated-types/associated-type-where-non-lifetime-type.stderr @@ -0,0 +1,13 @@ +error[E0658]: only lifetime parameters can be used in this context + --> $DIR/associated-type-where-non-lifetime-type.rs:13:13 + | +LL | for T:; + | ^ + | + = note: see issue #108185 for more information + = help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 87f9ea206eb868963ccc80f53efdc84590fcbdc7 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Wed, 3 Dec 2025 15:40:02 +0100 Subject: [PATCH 379/585] add tests for tidy alphabetical blessing --- src/tools/tidy/src/alphabetical/tests.rs | 107 +++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/src/tools/tidy/src/alphabetical/tests.rs b/src/tools/tidy/src/alphabetical/tests.rs index 6a756a84cf99..7c3438df41a7 100644 --- a/src/tools/tidy/src/alphabetical/tests.rs +++ b/src/tools/tidy/src/alphabetical/tests.rs @@ -29,6 +29,23 @@ fn bad(lines: &str, expected_msg: &str) { test(lines, "bad", expected_msg, true); } +#[track_caller] +fn bless_test(before: &str, after: &str) { + let tempfile = tempfile::Builder::new().tempfile().unwrap(); + std::fs::write(tempfile.path(), before).unwrap(); + + let tidy_ctx = TidyCtx::new(Path::new("/aaaa"), false, TidyFlags::new(&["--bless".to_owned()])); + + let mut check = tidy_ctx.start_check("alphabetical-test"); + check_lines(tempfile.path(), before, &tidy_ctx, &mut check); + + assert!(!check.is_bad()); + let new = std::fs::read_to_string(tempfile.path()).unwrap(); + assert_eq!(new, after); + + good(&new); +} + #[test] fn test_no_markers() { let lines = "\ @@ -396,3 +413,93 @@ fn multiline() { "; good(lines); } + +#[test] +fn bless_smoke() { + let before = "\ + tidy-alphabetical-start + 08 + 1 + 11 + 03 + tidy-alphabetical-end + "; + let after = "\ + tidy-alphabetical-start + 1 + 03 + 08 + 11 + tidy-alphabetical-end + "; + + bless_test(before, after); +} + +#[test] +fn bless_multiline() { + let before = "\ + tidy-alphabetical-start + 08 { + z} + 08 { + x + } + 1 + 08 {y} + 02 + 11 ( + 0 + ) + 03 + addition + notaddition + tidy-alphabetical-end + "; + let after = "\ + tidy-alphabetical-start + 1 + 02 + 03 + addition + 08 { + x + } + 08 {y} + 08 { + z} + 11 ( + 0 + ) + notaddition + tidy-alphabetical-end + "; + + bless_test(before, after); +} + +#[test] +fn bless_funny_numbers() { + // Because `2` is indented it gets merged into one entry with `1` and gets + // interpreted by version sort as `12`, which is greater than `3`. + // + // This is neither a wanted nor an unwanted behavior, this test just checks + // that it hasn't changed. + + let before = "\ + tidy-alphabetical-start + 1 + 2 + 3 + tidy-alphabetical-end + "; + let after = "\ + tidy-alphabetical-start + 3 + 1 + 2 + tidy-alphabetical-end + "; + + bless_test(before, after); +} From 3bbd6ea19a57edcd45ad1558754c1b59aabd836e Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sun, 7 Dec 2025 13:45:49 +0100 Subject: [PATCH 380/585] attempt to fix tidyselftest on windows --- src/tools/tidy/src/alphabetical/tests.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/tools/tidy/src/alphabetical/tests.rs b/src/tools/tidy/src/alphabetical/tests.rs index 7c3438df41a7..4a1d263f1a4f 100644 --- a/src/tools/tidy/src/alphabetical/tests.rs +++ b/src/tools/tidy/src/alphabetical/tests.rs @@ -31,16 +31,19 @@ fn bad(lines: &str, expected_msg: &str) { #[track_caller] fn bless_test(before: &str, after: &str) { - let tempfile = tempfile::Builder::new().tempfile().unwrap(); - std::fs::write(tempfile.path(), before).unwrap(); + // NB: convert to a temporary *path* (closing the file), so that `check_lines` can then + // atomically replace the file with a blessed version (on windows that requires the file + // to not be open) + let temp_path = tempfile::Builder::new().tempfile().unwrap().into_temp_path(); + std::fs::write(&temp_path, before).unwrap(); - let tidy_ctx = TidyCtx::new(Path::new("/aaaa"), false, TidyFlags::new(&["--bless".to_owned()])); + let tidy_ctx = TidyCtx::new(Path::new("/"), false, TidyFlags::new(&["--bless".to_owned()])); let mut check = tidy_ctx.start_check("alphabetical-test"); - check_lines(tempfile.path(), before, &tidy_ctx, &mut check); + check_lines(&temp_path, before, &tidy_ctx, &mut check); assert!(!check.is_bad()); - let new = std::fs::read_to_string(tempfile.path()).unwrap(); + let new = std::fs::read_to_string(temp_path).unwrap(); assert_eq!(new, after); good(&new); From 0bd9a2fafc1e041b3fcf030264b19912f7dda0d3 Mon Sep 17 00:00:00 2001 From: Dawid Lachowicz Date: Sun, 7 Dec 2025 15:42:23 +0000 Subject: [PATCH 381/585] contracts: clean up feature flag warning duplicated across tests There is no need for every contracts test to assert the same warning for using the `contracts` feature flag, as such use `#![expect(incomplete_features)]` in the tests, and add one test to specifically check for the warning. --- tests/ui/contracts/associated-item.rs | 2 +- .../contracts/async-fn-contract-ice-145333.rs | 2 +- .../async-fn-contract-ice-145333.stderr | 11 +---------- .../contract-annotation-limitations.rs | 2 +- .../contract-annotation-limitations.stderr | 11 +---------- ...ct-attributes-generics.chk_const_fail.stderr | 11 ----------- ...act-attributes-generics.chk_fail_post.stderr | 11 ----------- ...ract-attributes-generics.chk_fail_pre.stderr | 11 ----------- ...contract-attributes-generics.chk_pass.stderr | 11 ----------- .../contracts/contract-attributes-generics.rs | 2 +- ...ntract-attributes-generics.unchk_pass.stderr | 11 ----------- ...ontract-attributes-nest.chk_fail_post.stderr | 11 ----------- ...contract-attributes-nest.chk_fail_pre.stderr | 11 ----------- .../contract-attributes-nest.chk_pass.stderr | 11 ----------- tests/ui/contracts/contract-attributes-nest.rs | 2 +- ...tract-attributes-nest.unchk_fail_post.stderr | 11 ----------- ...ntract-attributes-nest.unchk_fail_pre.stderr | 11 ----------- .../contract-attributes-nest.unchk_pass.stderr | 11 ----------- ...ontract-attributes-tail.chk_fail_post.stderr | 11 ----------- ...contract-attributes-tail.chk_fail_pre.stderr | 11 ----------- .../contract-attributes-tail.chk_pass.stderr | 11 ----------- tests/ui/contracts/contract-attributes-tail.rs | 2 +- ...tract-attributes-tail.unchk_fail_post.stderr | 11 ----------- ...ntract-attributes-tail.unchk_fail_pre.stderr | 11 ----------- .../contract-attributes-tail.unchk_pass.stderr | 11 ----------- .../contract-captures-via-closure-copy.rs | 2 +- .../contract-captures-via-closure-copy.stderr | 11 ----------- .../contract-captures-via-closure-noncopy.rs | 2 +- ...contract-captures-via-closure-noncopy.stderr | 11 +---------- .../contracts/contract-const-fn.all_pass.stderr | 11 ----------- tests/ui/contracts/contract-const-fn.rs | 2 +- .../contract-const-fn.runtime_fail_post.stderr | 11 ----------- .../contract-const-fn.runtime_fail_pre.stderr | 11 ----------- ...ntracts-disabled-side-effect-declarations.rs | 2 +- ...cts-disabled-side-effect-declarations.stderr | 11 ----------- .../contracts-disabled-side-effect-ensures.rs | 2 +- ...ontracts-disabled-side-effect-ensures.stderr | 11 ----------- ...ts-ensures-early-fn-exit.chk_fail_ret.stderr | 11 ----------- ...ts-ensures-early-fn-exit.chk_fail_try.stderr | 11 ----------- ...s-ensures-early-fn-exit.chk_fail_yeet.stderr | 11 ----------- ...tracts-ensures-early-fn-exit.chk_pass.stderr | 11 ----------- .../contracts-ensures-early-fn-exit.rs | 2 +- ...acts-ensures-early-fn-exit.unchk_pass.stderr | 11 ----------- ...cts-ensures-is-not-inherited-when-nesting.rs | 2 +- ...ensures-is-not-inherited-when-nesting.stderr | 11 ----------- ...ts-requires-is-not-inherited-when-nesting.rs | 2 +- ...equires-is-not-inherited-when-nesting.stderr | 11 ----------- .../declared-vars-referring-to-params.rs | 2 +- .../declared-vars-referring-to-params.stderr | 11 ----------- .../contracts/declared-vars-used-in-ensures.rs | 2 +- .../declared-vars-used-in-ensures.stderr | 11 ----------- ...eclared-vars-used-in-requires-and-ensures.rs | 2 +- ...red-vars-used-in-requires-and-ensures.stderr | 11 ----------- .../disallow-contract-annotation-on-non-fn.rs | 2 +- ...isallow-contract-annotation-on-non-fn.stderr | 11 +---------- tests/ui/contracts/empty-ensures.rs | 2 +- tests/ui/contracts/empty-ensures.stderr | 11 +---------- tests/ui/contracts/empty-requires.rs | 2 +- tests/ui/contracts/empty-requires.stderr | 11 +---------- tests/ui/contracts/incomplete-feature.rs | 17 +++++++++++++++++ ...ed-item.stderr => incomplete-feature.stderr} | 2 +- .../contract-lang-items.chk_fail_post.stderr | 11 ----------- .../contract-lang-items.chk_pass.stderr | 11 ----------- .../internal_machinery/contract-lang-items.rs | 2 +- .../contract-lang-items.unchk_pass.stderr | 11 ----------- .../internal_machinery/lowering/basics.rs | 2 +- .../internal_machinery/lowering/basics.stderr | 11 ----------- .../requires-bool-expr-with-semicolon.rs | 2 +- .../requires-bool-expr-with-semicolon.stderr | 11 +---------- .../contracts/requires-no-final-expression.rs | 2 +- .../requires-no-final-expression.stderr | 11 +---------- 71 files changed, 50 insertions(+), 512 deletions(-) delete mode 100644 tests/ui/contracts/contract-attributes-generics.chk_const_fail.stderr delete mode 100644 tests/ui/contracts/contract-attributes-generics.chk_fail_post.stderr delete mode 100644 tests/ui/contracts/contract-attributes-generics.chk_fail_pre.stderr delete mode 100644 tests/ui/contracts/contract-attributes-generics.chk_pass.stderr delete mode 100644 tests/ui/contracts/contract-attributes-generics.unchk_pass.stderr delete mode 100644 tests/ui/contracts/contract-attributes-nest.chk_fail_post.stderr delete mode 100644 tests/ui/contracts/contract-attributes-nest.chk_fail_pre.stderr delete mode 100644 tests/ui/contracts/contract-attributes-nest.chk_pass.stderr delete mode 100644 tests/ui/contracts/contract-attributes-nest.unchk_fail_post.stderr delete mode 100644 tests/ui/contracts/contract-attributes-nest.unchk_fail_pre.stderr delete mode 100644 tests/ui/contracts/contract-attributes-nest.unchk_pass.stderr delete mode 100644 tests/ui/contracts/contract-attributes-tail.chk_fail_post.stderr delete mode 100644 tests/ui/contracts/contract-attributes-tail.chk_fail_pre.stderr delete mode 100644 tests/ui/contracts/contract-attributes-tail.chk_pass.stderr delete mode 100644 tests/ui/contracts/contract-attributes-tail.unchk_fail_post.stderr delete mode 100644 tests/ui/contracts/contract-attributes-tail.unchk_fail_pre.stderr delete mode 100644 tests/ui/contracts/contract-attributes-tail.unchk_pass.stderr delete mode 100644 tests/ui/contracts/contract-captures-via-closure-copy.stderr delete mode 100644 tests/ui/contracts/contract-const-fn.all_pass.stderr delete mode 100644 tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr delete mode 100644 tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr delete mode 100644 tests/ui/contracts/contracts-disabled-side-effect-declarations.stderr delete mode 100644 tests/ui/contracts/contracts-disabled-side-effect-ensures.stderr delete mode 100644 tests/ui/contracts/contracts-ensures-early-fn-exit.chk_fail_ret.stderr delete mode 100644 tests/ui/contracts/contracts-ensures-early-fn-exit.chk_fail_try.stderr delete mode 100644 tests/ui/contracts/contracts-ensures-early-fn-exit.chk_fail_yeet.stderr delete mode 100644 tests/ui/contracts/contracts-ensures-early-fn-exit.chk_pass.stderr delete mode 100644 tests/ui/contracts/contracts-ensures-early-fn-exit.unchk_pass.stderr delete mode 100644 tests/ui/contracts/contracts-ensures-is-not-inherited-when-nesting.stderr delete mode 100644 tests/ui/contracts/contracts-requires-is-not-inherited-when-nesting.stderr delete mode 100644 tests/ui/contracts/declared-vars-referring-to-params.stderr delete mode 100644 tests/ui/contracts/declared-vars-used-in-ensures.stderr delete mode 100644 tests/ui/contracts/declared-vars-used-in-requires-and-ensures.stderr create mode 100644 tests/ui/contracts/incomplete-feature.rs rename tests/ui/contracts/{associated-item.stderr => incomplete-feature.stderr} (90%) delete mode 100644 tests/ui/contracts/internal_machinery/contract-lang-items.chk_fail_post.stderr delete mode 100644 tests/ui/contracts/internal_machinery/contract-lang-items.chk_pass.stderr delete mode 100644 tests/ui/contracts/internal_machinery/contract-lang-items.unchk_pass.stderr delete mode 100644 tests/ui/contracts/internal_machinery/lowering/basics.stderr diff --git a/tests/ui/contracts/associated-item.rs b/tests/ui/contracts/associated-item.rs index 4a2d05abbc53..86ff05f6c0f4 100644 --- a/tests/ui/contracts/associated-item.rs +++ b/tests/ui/contracts/associated-item.rs @@ -3,8 +3,8 @@ //@ compile-flags: --crate-type=lib //@ check-pass +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use extern crate core; diff --git a/tests/ui/contracts/async-fn-contract-ice-145333.rs b/tests/ui/contracts/async-fn-contract-ice-145333.rs index a6de8a786af9..e9e2877cd2de 100644 --- a/tests/ui/contracts/async-fn-contract-ice-145333.rs +++ b/tests/ui/contracts/async-fn-contract-ice-145333.rs @@ -1,7 +1,7 @@ //@ compile-flags: --crate-type=lib //@ edition: 2021 +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete #[core::contracts::ensures(|ret| *ret)] //~^ ERROR contract annotations are not yet supported on async or gen functions diff --git a/tests/ui/contracts/async-fn-contract-ice-145333.stderr b/tests/ui/contracts/async-fn-contract-ice-145333.stderr index 77f5379e6fb5..031cff5cad1b 100644 --- a/tests/ui/contracts/async-fn-contract-ice-145333.stderr +++ b/tests/ui/contracts/async-fn-contract-ice-145333.stderr @@ -4,14 +4,5 @@ error: contract annotations are not yet supported on async or gen functions LL | #[core::contracts::ensures(|ret| *ret)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/async-fn-contract-ice-145333.rs:3:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/contracts/contract-annotation-limitations.rs b/tests/ui/contracts/contract-annotation-limitations.rs index 10b3bacab5cf..0ecc1d15aa7b 100644 --- a/tests/ui/contracts/contract-annotation-limitations.rs +++ b/tests/ui/contracts/contract-annotation-limitations.rs @@ -1,8 +1,8 @@ //! Test for some of the existing limitations and the current error messages. //! Some of these limitations may be removed in the future. +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] #![allow(dead_code)] /// Represent a 5-star system. diff --git a/tests/ui/contracts/contract-annotation-limitations.stderr b/tests/ui/contracts/contract-annotation-limitations.stderr index 14338cf4b868..c0dc37fee4c4 100644 --- a/tests/ui/contracts/contract-annotation-limitations.stderr +++ b/tests/ui/contracts/contract-annotation-limitations.stderr @@ -10,14 +10,5 @@ error: contract annotations is only supported in functions with bodies LL | #[core::contracts::ensures(|ret| ret.is_none_or(Stars::is_valid))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-annotation-limitations.rs:4:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/contracts/contract-attributes-generics.chk_const_fail.stderr b/tests/ui/contracts/contract-attributes-generics.chk_const_fail.stderr deleted file mode 100644 index 0630811d4f7e..000000000000 --- a/tests/ui/contracts/contract-attributes-generics.chk_const_fail.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-generics.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-generics.chk_fail_post.stderr b/tests/ui/contracts/contract-attributes-generics.chk_fail_post.stderr deleted file mode 100644 index 0630811d4f7e..000000000000 --- a/tests/ui/contracts/contract-attributes-generics.chk_fail_post.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-generics.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-generics.chk_fail_pre.stderr b/tests/ui/contracts/contract-attributes-generics.chk_fail_pre.stderr deleted file mode 100644 index 0630811d4f7e..000000000000 --- a/tests/ui/contracts/contract-attributes-generics.chk_fail_pre.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-generics.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-generics.chk_pass.stderr b/tests/ui/contracts/contract-attributes-generics.chk_pass.stderr deleted file mode 100644 index 0630811d4f7e..000000000000 --- a/tests/ui/contracts/contract-attributes-generics.chk_pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-generics.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-generics.rs b/tests/ui/contracts/contract-attributes-generics.rs index 3763ce116f84..6fd4c0a9790b 100644 --- a/tests/ui/contracts/contract-attributes-generics.rs +++ b/tests/ui/contracts/contract-attributes-generics.rs @@ -16,8 +16,8 @@ //@ [chk_fail_post] compile-flags: -Zcontract-checks=yes //@ [chk_const_fail] compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] use std::ops::Sub; diff --git a/tests/ui/contracts/contract-attributes-generics.unchk_pass.stderr b/tests/ui/contracts/contract-attributes-generics.unchk_pass.stderr deleted file mode 100644 index 0630811d4f7e..000000000000 --- a/tests/ui/contracts/contract-attributes-generics.unchk_pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-generics.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-nest.chk_fail_post.stderr b/tests/ui/contracts/contract-attributes-nest.chk_fail_post.stderr deleted file mode 100644 index 9ca95b8bb01a..000000000000 --- a/tests/ui/contracts/contract-attributes-nest.chk_fail_post.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-nest.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-nest.chk_fail_pre.stderr b/tests/ui/contracts/contract-attributes-nest.chk_fail_pre.stderr deleted file mode 100644 index 9ca95b8bb01a..000000000000 --- a/tests/ui/contracts/contract-attributes-nest.chk_fail_pre.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-nest.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-nest.chk_pass.stderr b/tests/ui/contracts/contract-attributes-nest.chk_pass.stderr deleted file mode 100644 index 9ca95b8bb01a..000000000000 --- a/tests/ui/contracts/contract-attributes-nest.chk_pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-nest.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-nest.rs b/tests/ui/contracts/contract-attributes-nest.rs index d367687b84e3..89bd0a2b1136 100644 --- a/tests/ui/contracts/contract-attributes-nest.rs +++ b/tests/ui/contracts/contract-attributes-nest.rs @@ -16,8 +16,8 @@ //@ [chk_fail_pre] compile-flags: -Zcontract-checks=yes //@ [chk_fail_post] compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] #[core::contracts::requires(x.baz > 0)] #[core::contracts::ensures(|ret| *ret > 100)] diff --git a/tests/ui/contracts/contract-attributes-nest.unchk_fail_post.stderr b/tests/ui/contracts/contract-attributes-nest.unchk_fail_post.stderr deleted file mode 100644 index 9ca95b8bb01a..000000000000 --- a/tests/ui/contracts/contract-attributes-nest.unchk_fail_post.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-nest.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-nest.unchk_fail_pre.stderr b/tests/ui/contracts/contract-attributes-nest.unchk_fail_pre.stderr deleted file mode 100644 index 9ca95b8bb01a..000000000000 --- a/tests/ui/contracts/contract-attributes-nest.unchk_fail_pre.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-nest.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-nest.unchk_pass.stderr b/tests/ui/contracts/contract-attributes-nest.unchk_pass.stderr deleted file mode 100644 index 9ca95b8bb01a..000000000000 --- a/tests/ui/contracts/contract-attributes-nest.unchk_pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-nest.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-tail.chk_fail_post.stderr b/tests/ui/contracts/contract-attributes-tail.chk_fail_post.stderr deleted file mode 100644 index f87e7e19fa3d..000000000000 --- a/tests/ui/contracts/contract-attributes-tail.chk_fail_post.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-tail.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-tail.chk_fail_pre.stderr b/tests/ui/contracts/contract-attributes-tail.chk_fail_pre.stderr deleted file mode 100644 index f87e7e19fa3d..000000000000 --- a/tests/ui/contracts/contract-attributes-tail.chk_fail_pre.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-tail.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-tail.chk_pass.stderr b/tests/ui/contracts/contract-attributes-tail.chk_pass.stderr deleted file mode 100644 index f87e7e19fa3d..000000000000 --- a/tests/ui/contracts/contract-attributes-tail.chk_pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-tail.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-tail.rs b/tests/ui/contracts/contract-attributes-tail.rs index 43edfe5e803f..361725474099 100644 --- a/tests/ui/contracts/contract-attributes-tail.rs +++ b/tests/ui/contracts/contract-attributes-tail.rs @@ -16,8 +16,8 @@ //@ [chk_fail_pre] compile-flags: -Zcontract-checks=yes //@ [chk_fail_post] compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] #[core::contracts::requires(x.baz > 0)] #[core::contracts::ensures(|ret| *ret > 100)] diff --git a/tests/ui/contracts/contract-attributes-tail.unchk_fail_post.stderr b/tests/ui/contracts/contract-attributes-tail.unchk_fail_post.stderr deleted file mode 100644 index f87e7e19fa3d..000000000000 --- a/tests/ui/contracts/contract-attributes-tail.unchk_fail_post.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-tail.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-tail.unchk_fail_pre.stderr b/tests/ui/contracts/contract-attributes-tail.unchk_fail_pre.stderr deleted file mode 100644 index f87e7e19fa3d..000000000000 --- a/tests/ui/contracts/contract-attributes-tail.unchk_fail_pre.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-tail.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-attributes-tail.unchk_pass.stderr b/tests/ui/contracts/contract-attributes-tail.unchk_pass.stderr deleted file mode 100644 index f87e7e19fa3d..000000000000 --- a/tests/ui/contracts/contract-attributes-tail.unchk_pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-attributes-tail.rs:19:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-captures-via-closure-copy.rs b/tests/ui/contracts/contract-captures-via-closure-copy.rs index bc7e5b9b6f10..a5453503b4bd 100644 --- a/tests/ui/contracts/contract-captures-via-closure-copy.rs +++ b/tests/ui/contracts/contract-captures-via-closure-copy.rs @@ -1,8 +1,8 @@ //@ run-crash //@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] struct Baz { baz: i32 diff --git a/tests/ui/contracts/contract-captures-via-closure-copy.stderr b/tests/ui/contracts/contract-captures-via-closure-copy.stderr deleted file mode 100644 index d92db601608f..000000000000 --- a/tests/ui/contracts/contract-captures-via-closure-copy.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-captures-via-closure-copy.rs:4:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-captures-via-closure-noncopy.rs b/tests/ui/contracts/contract-captures-via-closure-noncopy.rs index 1ec2feb045a3..c7aa72d2b0f6 100644 --- a/tests/ui/contracts/contract-captures-via-closure-noncopy.rs +++ b/tests/ui/contracts/contract-captures-via-closure-noncopy.rs @@ -1,8 +1,8 @@ //@ edition:2015..2021 //@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] struct Baz { baz: i32 diff --git a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr index 29adeaec3e16..5f55faed80c8 100644 --- a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr +++ b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr @@ -1,12 +1,3 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-captures-via-closure-noncopy.rs:4:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `Baz: std::marker::Copy` is not satisfied in `{closure@$DIR/contract-captures-via-closure-noncopy.rs:13:42: 13:57}` --> $DIR/contract-captures-via-closure-noncopy.rs:13:1 | @@ -32,6 +23,6 @@ LL + #[derive(Copy)] LL | struct Baz { | -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/contracts/contract-const-fn.all_pass.stderr b/tests/ui/contracts/contract-const-fn.all_pass.stderr deleted file mode 100644 index e5b1df655823..000000000000 --- a/tests/ui/contracts/contract-const-fn.all_pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-const-fn.rs:17:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-const-fn.rs b/tests/ui/contracts/contract-const-fn.rs index fe8dd37b1f52..c79ab33e8ec8 100644 --- a/tests/ui/contracts/contract-const-fn.rs +++ b/tests/ui/contracts/contract-const-fn.rs @@ -14,8 +14,8 @@ //@ [all_pass] compile-flags: -Zcontract-checks=yes //@ [runtime_fail_pre] compile-flags: -Zcontract-checks=yes //@ [runtime_fail_post] compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] extern crate core; use core::contracts::*; diff --git a/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr b/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr deleted file mode 100644 index e5b1df655823..000000000000 --- a/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-const-fn.rs:17:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr b/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr deleted file mode 100644 index e5b1df655823..000000000000 --- a/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-const-fn.rs:17:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs b/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs index fc07729e9132..4b2d4a80237f 100644 --- a/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs +++ b/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs @@ -1,6 +1,6 @@ //@ run-pass +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] extern crate core; use core::contracts::requires; diff --git a/tests/ui/contracts/contracts-disabled-side-effect-declarations.stderr b/tests/ui/contracts/contracts-disabled-side-effect-declarations.stderr deleted file mode 100644 index 4c8a12538433..000000000000 --- a/tests/ui/contracts/contracts-disabled-side-effect-declarations.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contracts-disabled-side-effect-declarations.rs:2:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs b/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs index a3a77b0de9a2..1488b8f8d3fd 100644 --- a/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs +++ b/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs @@ -1,6 +1,6 @@ //@ run-pass +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] extern crate core; use core::contracts::ensures; diff --git a/tests/ui/contracts/contracts-disabled-side-effect-ensures.stderr b/tests/ui/contracts/contracts-disabled-side-effect-ensures.stderr deleted file mode 100644 index dd9ebe9bd355..000000000000 --- a/tests/ui/contracts/contracts-disabled-side-effect-ensures.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contracts-disabled-side-effect-ensures.rs:2:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contracts-ensures-early-fn-exit.chk_fail_ret.stderr b/tests/ui/contracts/contracts-ensures-early-fn-exit.chk_fail_ret.stderr deleted file mode 100644 index d693fad446a4..000000000000 --- a/tests/ui/contracts/contracts-ensures-early-fn-exit.chk_fail_ret.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contracts-ensures-early-fn-exit.rs:16:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contracts-ensures-early-fn-exit.chk_fail_try.stderr b/tests/ui/contracts/contracts-ensures-early-fn-exit.chk_fail_try.stderr deleted file mode 100644 index d693fad446a4..000000000000 --- a/tests/ui/contracts/contracts-ensures-early-fn-exit.chk_fail_try.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contracts-ensures-early-fn-exit.rs:16:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contracts-ensures-early-fn-exit.chk_fail_yeet.stderr b/tests/ui/contracts/contracts-ensures-early-fn-exit.chk_fail_yeet.stderr deleted file mode 100644 index d693fad446a4..000000000000 --- a/tests/ui/contracts/contracts-ensures-early-fn-exit.chk_fail_yeet.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contracts-ensures-early-fn-exit.rs:16:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contracts-ensures-early-fn-exit.chk_pass.stderr b/tests/ui/contracts/contracts-ensures-early-fn-exit.chk_pass.stderr deleted file mode 100644 index d693fad446a4..000000000000 --- a/tests/ui/contracts/contracts-ensures-early-fn-exit.chk_pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contracts-ensures-early-fn-exit.rs:16:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contracts-ensures-early-fn-exit.rs b/tests/ui/contracts/contracts-ensures-early-fn-exit.rs index 44ae07d8c95c..71c69fa83ccb 100644 --- a/tests/ui/contracts/contracts-ensures-early-fn-exit.rs +++ b/tests/ui/contracts/contracts-ensures-early-fn-exit.rs @@ -13,8 +13,8 @@ //@ [chk_fail_yeet] compile-flags: -Zcontract-checks=yes //! This test ensures that ensures clauses are checked for different return points of a function. +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] #![feature(yeet_expr)] /// This ensures will fail in different return points depending on the input. diff --git a/tests/ui/contracts/contracts-ensures-early-fn-exit.unchk_pass.stderr b/tests/ui/contracts/contracts-ensures-early-fn-exit.unchk_pass.stderr deleted file mode 100644 index d693fad446a4..000000000000 --- a/tests/ui/contracts/contracts-ensures-early-fn-exit.unchk_pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contracts-ensures-early-fn-exit.rs:16:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contracts-ensures-is-not-inherited-when-nesting.rs b/tests/ui/contracts/contracts-ensures-is-not-inherited-when-nesting.rs index f01a852fbff3..0fc9e5590f02 100644 --- a/tests/ui/contracts/contracts-ensures-is-not-inherited-when-nesting.rs +++ b/tests/ui/contracts/contracts-ensures-is-not-inherited-when-nesting.rs @@ -1,7 +1,7 @@ //@ run-pass //@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] #[core::contracts::ensures(|ret| *ret > 0)] fn outer() -> i32 { diff --git a/tests/ui/contracts/contracts-ensures-is-not-inherited-when-nesting.stderr b/tests/ui/contracts/contracts-ensures-is-not-inherited-when-nesting.stderr deleted file mode 100644 index 49a372b53c7d..000000000000 --- a/tests/ui/contracts/contracts-ensures-is-not-inherited-when-nesting.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contracts-ensures-is-not-inherited-when-nesting.rs:3:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/contracts-requires-is-not-inherited-when-nesting.rs b/tests/ui/contracts/contracts-requires-is-not-inherited-when-nesting.rs index 2c2a4a697855..3ac539adb247 100644 --- a/tests/ui/contracts/contracts-requires-is-not-inherited-when-nesting.rs +++ b/tests/ui/contracts/contracts-requires-is-not-inherited-when-nesting.rs @@ -1,7 +1,7 @@ //@ run-pass //@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] struct Outer { outer: std::cell::Cell } diff --git a/tests/ui/contracts/contracts-requires-is-not-inherited-when-nesting.stderr b/tests/ui/contracts/contracts-requires-is-not-inherited-when-nesting.stderr deleted file mode 100644 index 48898c4434ad..000000000000 --- a/tests/ui/contracts/contracts-requires-is-not-inherited-when-nesting.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contracts-requires-is-not-inherited-when-nesting.rs:3:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/declared-vars-referring-to-params.rs b/tests/ui/contracts/declared-vars-referring-to-params.rs index 52885da048e2..d915dc09cfe2 100644 --- a/tests/ui/contracts/declared-vars-referring-to-params.rs +++ b/tests/ui/contracts/declared-vars-referring-to-params.rs @@ -1,7 +1,7 @@ //@ run-pass //@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] extern crate core; use core::contracts::{ensures, requires}; diff --git a/tests/ui/contracts/declared-vars-referring-to-params.stderr b/tests/ui/contracts/declared-vars-referring-to-params.stderr deleted file mode 100644 index 0ad9064e8606..000000000000 --- a/tests/ui/contracts/declared-vars-referring-to-params.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/declared-vars-referring-to-params.rs:3:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/declared-vars-used-in-ensures.rs b/tests/ui/contracts/declared-vars-used-in-ensures.rs index 9703709e2b8e..ddab57483668 100644 --- a/tests/ui/contracts/declared-vars-used-in-ensures.rs +++ b/tests/ui/contracts/declared-vars-used-in-ensures.rs @@ -1,7 +1,7 @@ //@ run-pass //@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] extern crate core; use core::contracts::{ensures, requires}; diff --git a/tests/ui/contracts/declared-vars-used-in-ensures.stderr b/tests/ui/contracts/declared-vars-used-in-ensures.stderr deleted file mode 100644 index 000a1b239932..000000000000 --- a/tests/ui/contracts/declared-vars-used-in-ensures.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/declared-vars-used-in-ensures.rs:3:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.rs b/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.rs index e066a95314a9..6b7896101ca0 100644 --- a/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.rs +++ b/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.rs @@ -1,7 +1,7 @@ //@ run-pass //@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] extern crate core; use core::contracts::{ensures, requires}; diff --git a/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.stderr b/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.stderr deleted file mode 100644 index 52b163553fba..000000000000 --- a/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/declared-vars-used-in-requires-and-ensures.rs:3:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/disallow-contract-annotation-on-non-fn.rs b/tests/ui/contracts/disallow-contract-annotation-on-non-fn.rs index 69be906782a6..fecac593f0e5 100644 --- a/tests/ui/contracts/disallow-contract-annotation-on-non-fn.rs +++ b/tests/ui/contracts/disallow-contract-annotation-on-non-fn.rs @@ -1,7 +1,7 @@ //! Checks for compilation errors related to adding contracts to non-function items. +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] #![allow(dead_code)] #[core::contracts::requires(true)] diff --git a/tests/ui/contracts/disallow-contract-annotation-on-non-fn.stderr b/tests/ui/contracts/disallow-contract-annotation-on-non-fn.stderr index 0a7fff8183e0..864e94997a2e 100644 --- a/tests/ui/contracts/disallow-contract-annotation-on-non-fn.stderr +++ b/tests/ui/contracts/disallow-contract-annotation-on-non-fn.stderr @@ -40,14 +40,5 @@ error: contract annotations can only be used on functions LL | #[core::contracts::requires(true)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/disallow-contract-annotation-on-non-fn.rs:3:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 7 previous errors diff --git a/tests/ui/contracts/empty-ensures.rs b/tests/ui/contracts/empty-ensures.rs index d897f27bf6c9..0a5239111786 100644 --- a/tests/ui/contracts/empty-ensures.rs +++ b/tests/ui/contracts/empty-ensures.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] extern crate core; use core::contracts::ensures; diff --git a/tests/ui/contracts/empty-ensures.stderr b/tests/ui/contracts/empty-ensures.stderr index 407a253bd856..6a19d234b52c 100644 --- a/tests/ui/contracts/empty-ensures.stderr +++ b/tests/ui/contracts/empty-ensures.stderr @@ -1,12 +1,3 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/empty-ensures.rs:2:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: expected a `Fn(&_)` closure, found `()` --> $DIR/empty-ensures.rs:8:1 | @@ -20,6 +11,6 @@ LL | #[ensures()] note: required by a bound in `build_check_ensures` --> $SRC_DIR/core/src/contracts.rs:LL:COL -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/contracts/empty-requires.rs b/tests/ui/contracts/empty-requires.rs index e3c72dcd66a1..dedcc10d52cb 100644 --- a/tests/ui/contracts/empty-requires.rs +++ b/tests/ui/contracts/empty-requires.rs @@ -1,7 +1,7 @@ //@ dont-require-annotations: NOTE //@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] extern crate core; use core::contracts::requires; diff --git a/tests/ui/contracts/empty-requires.stderr b/tests/ui/contracts/empty-requires.stderr index b48e547b8cda..702b8a23c55e 100644 --- a/tests/ui/contracts/empty-requires.stderr +++ b/tests/ui/contracts/empty-requires.stderr @@ -1,18 +1,9 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/empty-requires.rs:3:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types --> $DIR/empty-requires.rs:9:1 | LL | #[requires()] | ^^^^^^^^^^^^^ expected `bool`, found `()` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/contracts/incomplete-feature.rs b/tests/ui/contracts/incomplete-feature.rs new file mode 100644 index 000000000000..f1351e2f87e3 --- /dev/null +++ b/tests/ui/contracts/incomplete-feature.rs @@ -0,0 +1,17 @@ +//@ run-pass +//@ compile-flags: -Zcontract-checks=yes + +// This test specifically checks that the [incomplete_features] warning is +// emitted when the `contracts` feature gate is enabled, so that it can be +// marked as `expect`ed in other tests in order to reduce duplication. +#![feature(contracts)] +//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +extern crate core; +use core::contracts::requires; + +#[requires(true)] +fn foo() {} + +fn main() { + foo() +} diff --git a/tests/ui/contracts/associated-item.stderr b/tests/ui/contracts/incomplete-feature.stderr similarity index 90% rename from tests/ui/contracts/associated-item.stderr rename to tests/ui/contracts/incomplete-feature.stderr index 20651026b87a..7683926df073 100644 --- a/tests/ui/contracts/associated-item.stderr +++ b/tests/ui/contracts/incomplete-feature.stderr @@ -1,5 +1,5 @@ warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/associated-item.rs:6:12 + --> $DIR/incomplete-feature.rs:7:12 | LL | #![feature(contracts)] | ^^^^^^^^^ diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.chk_fail_post.stderr b/tests/ui/contracts/internal_machinery/contract-lang-items.chk_fail_post.stderr deleted file mode 100644 index acce6b1fbc72..000000000000 --- a/tests/ui/contracts/internal_machinery/contract-lang-items.chk_fail_post.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-lang-items.rs:8:12 - | -LL | #![feature(contracts)] // to access core::contracts - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.chk_pass.stderr b/tests/ui/contracts/internal_machinery/contract-lang-items.chk_pass.stderr deleted file mode 100644 index acce6b1fbc72..000000000000 --- a/tests/ui/contracts/internal_machinery/contract-lang-items.chk_pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-lang-items.rs:8:12 - | -LL | #![feature(contracts)] // to access core::contracts - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.rs b/tests/ui/contracts/internal_machinery/contract-lang-items.rs index ad88ebfe22e3..d67560103644 100644 --- a/tests/ui/contracts/internal_machinery/contract-lang-items.rs +++ b/tests/ui/contracts/internal_machinery/contract-lang-items.rs @@ -5,8 +5,8 @@ // //@ [chk_fail_post] run-crash +#![expect(incomplete_features)] #![feature(contracts)] // to access core::contracts -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] #![feature(contracts_internals)] // to access check_requires lang item #![feature(core_intrinsics)] fn foo(x: Baz) -> i32 { diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.unchk_pass.stderr b/tests/ui/contracts/internal_machinery/contract-lang-items.unchk_pass.stderr deleted file mode 100644 index acce6b1fbc72..000000000000 --- a/tests/ui/contracts/internal_machinery/contract-lang-items.unchk_pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/contract-lang-items.rs:8:12 - | -LL | #![feature(contracts)] // to access core::contracts - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/internal_machinery/lowering/basics.rs b/tests/ui/contracts/internal_machinery/lowering/basics.rs index 9160517a7932..7b3a769af825 100644 --- a/tests/ui/contracts/internal_machinery/lowering/basics.rs +++ b/tests/ui/contracts/internal_machinery/lowering/basics.rs @@ -1,6 +1,6 @@ //@ run-pass +#![expect(incomplete_features)] #![feature(contracts, cfg_contract_checks, contracts_internals, core_intrinsics)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] extern crate core; diff --git a/tests/ui/contracts/internal_machinery/lowering/basics.stderr b/tests/ui/contracts/internal_machinery/lowering/basics.stderr deleted file mode 100644 index 118229694a90..000000000000 --- a/tests/ui/contracts/internal_machinery/lowering/basics.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/basics.rs:2:12 - | -LL | #![feature(contracts, cfg_contract_checks, contracts_internals, core_intrinsics)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/contracts/requires-bool-expr-with-semicolon.rs b/tests/ui/contracts/requires-bool-expr-with-semicolon.rs index d0b3ed661ed6..3a1a6549a343 100644 --- a/tests/ui/contracts/requires-bool-expr-with-semicolon.rs +++ b/tests/ui/contracts/requires-bool-expr-with-semicolon.rs @@ -1,7 +1,7 @@ //@ dont-require-annotations: NOTE //@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] extern crate core; use core::contracts::requires; diff --git a/tests/ui/contracts/requires-bool-expr-with-semicolon.stderr b/tests/ui/contracts/requires-bool-expr-with-semicolon.stderr index fd38fa4edcf5..559c710b1456 100644 --- a/tests/ui/contracts/requires-bool-expr-with-semicolon.stderr +++ b/tests/ui/contracts/requires-bool-expr-with-semicolon.stderr @@ -1,18 +1,9 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/requires-bool-expr-with-semicolon.rs:3:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types --> $DIR/requires-bool-expr-with-semicolon.rs:9:1 | LL | #[requires(true;)] | ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/contracts/requires-no-final-expression.rs b/tests/ui/contracts/requires-no-final-expression.rs index 474b29d63ba6..0188a9f607a3 100644 --- a/tests/ui/contracts/requires-no-final-expression.rs +++ b/tests/ui/contracts/requires-no-final-expression.rs @@ -1,7 +1,7 @@ //@ dont-require-annotations: NOTE //@ compile-flags: -Zcontract-checks=yes +#![expect(incomplete_features)] #![feature(contracts)] -//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] extern crate core; use core::contracts::requires; diff --git a/tests/ui/contracts/requires-no-final-expression.stderr b/tests/ui/contracts/requires-no-final-expression.stderr index 0db164857394..ae71ee3c996c 100644 --- a/tests/ui/contracts/requires-no-final-expression.stderr +++ b/tests/ui/contracts/requires-no-final-expression.stderr @@ -1,18 +1,9 @@ -warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/requires-no-final-expression.rs:3:12 - | -LL | #![feature(contracts)] - | ^^^^^^^^^ - | - = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types --> $DIR/requires-no-final-expression.rs:9:1 | LL | #[requires(let y = 1;)] | ^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. From ae8429c4a9038853de20f0613c04998fa5a7cc57 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sun, 7 Dec 2025 12:17:17 -0600 Subject: [PATCH 382/585] mailmap: add binarycat --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 1118955016bd..a586e7047769 100644 --- a/.mailmap +++ b/.mailmap @@ -83,6 +83,7 @@ Ben Sago Ben Striegel Benjamin Jackman Benoît Cortier +binarycat lolbinarycat Bheesham Persaud Bheesham Persaud bjorn3 <17426603+bjorn3@users.noreply.github.com> bjorn3 <17426603+bjorn3@users.noreply.github.com> From 22a7457d12d7eb268e3d8b0ba50f6cd7153af9b4 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 5 Dec 2025 19:50:20 +0900 Subject: [PATCH 383/585] Cleaned up some tests Merged tests/ui/typeck/non-function-call-error-2 with tests/ui/typeck/non-function-call-error Add comment to tests/ui/traits/normalize-associated-type-in-where-clause.rs Merged tests/ui/privacy/private-item-simple-2.rs with tests/ui/privacy/private-item-simple.rs Merged tests/ui/str/str-add-operator-2.rs with tests/ui/str/str-add-operator.rs Add comment to tests/ui/imports/duplicate-empty-imports.rs Add comment to tests/ui/for-loop-while/nested-loop-break-unit.rs Add comment to tests/ui/match/match-ref-option-pattern.rs Add comment to tests/ui/closures/simple-capture-and-call.rs Add comment to tests/ui/type/never-type-inference-fail.rs Add comment to tests/ui/match/match-stack-overflow-72933.rs --- tests/ui/closures/simple-capture-and-call.rs | 9 +++---- .../for-loop-while/nested-loop-break-unit.rs | 1 + tests/ui/imports/duplicate-empty-imports.rs | 1 + tests/ui/match/match-ref-option-pattern.rs | 1 + tests/ui/match/match-stack-overflow-72933-.rs | 3 ++- tests/ui/privacy/private-item-simple-2.rs | 10 -------- tests/ui/privacy/private-item-simple-2.stderr | 15 ------------ tests/ui/privacy/private-item-simple.rs | 6 +++++ tests/ui/privacy/private-item-simple.stderr | 18 +++++++++++--- tests/ui/str/str-add-operator-2.rs | 5 ---- tests/ui/str/str-add-operator-2.stderr | 18 -------------- tests/ui/str/str-add-operator.rs | 1 + tests/ui/str/str-add-operator.stderr | 2 +- ...rmalize-associated-type-in-where-clause.rs | 18 +++++++------- tests/ui/type/never-type-inference-fail.rs | 2 ++ .../ui/type/never-type-inference-fail.stderr | 2 +- tests/ui/typeck/non-function-call-error-2.rs | 7 ------ .../typeck/non-function-call-error-2.stderr | 23 ------------------ tests/ui/typeck/non-function-call-error.rs | 10 ++++++++ .../ui/typeck/non-function-call-error.stderr | 24 +++++++++++++++++-- 20 files changed, 77 insertions(+), 99 deletions(-) delete mode 100644 tests/ui/privacy/private-item-simple-2.rs delete mode 100644 tests/ui/privacy/private-item-simple-2.stderr delete mode 100644 tests/ui/str/str-add-operator-2.rs delete mode 100644 tests/ui/str/str-add-operator-2.stderr delete mode 100644 tests/ui/typeck/non-function-call-error-2.rs delete mode 100644 tests/ui/typeck/non-function-call-error-2.stderr diff --git a/tests/ui/closures/simple-capture-and-call.rs b/tests/ui/closures/simple-capture-and-call.rs index 39d657573db7..112324eb7204 100644 --- a/tests/ui/closures/simple-capture-and-call.rs +++ b/tests/ui/closures/simple-capture-and-call.rs @@ -1,7 +1,8 @@ +//! regression test for issue #1895 //@ run-pass -pub fn main() { - let x = 1_usize; - let y = || x; - let _z = y(); +fn main() { + let x = 1_usize; + let y = || x; + let _z = y(); } diff --git a/tests/ui/for-loop-while/nested-loop-break-unit.rs b/tests/ui/for-loop-while/nested-loop-break-unit.rs index ad5721495090..b31d9ee8f50d 100644 --- a/tests/ui/for-loop-while/nested-loop-break-unit.rs +++ b/tests/ui/for-loop-while/nested-loop-break-unit.rs @@ -1,3 +1,4 @@ +//! regression test for issue #2642 //@ run-pass #![allow(dead_code)] diff --git a/tests/ui/imports/duplicate-empty-imports.rs b/tests/ui/imports/duplicate-empty-imports.rs index d395ac677e75..7768dcfbbdac 100644 --- a/tests/ui/imports/duplicate-empty-imports.rs +++ b/tests/ui/imports/duplicate-empty-imports.rs @@ -1,3 +1,4 @@ +//! regression test for issue #47673 //@ check-pass #![allow(unused_imports)] diff --git a/tests/ui/match/match-ref-option-pattern.rs b/tests/ui/match/match-ref-option-pattern.rs index 0860d0f59260..a6de2361503a 100644 --- a/tests/ui/match/match-ref-option-pattern.rs +++ b/tests/ui/match/match-ref-option-pattern.rs @@ -1,3 +1,4 @@ +//! regression test for issue #3500 //@ run-pass pub fn main() { diff --git a/tests/ui/match/match-stack-overflow-72933-.rs b/tests/ui/match/match-stack-overflow-72933-.rs index 6d091a910819..0883278be839 100644 --- a/tests/ui/match/match-stack-overflow-72933-.rs +++ b/tests/ui/match/match-stack-overflow-72933-.rs @@ -1,6 +1,7 @@ +//! regression test for issue #72933 //@ build-pass // ignore-tidy-filelength -#![crate_type="rlib"] +#![crate_type = "rlib"] fn banana(v: &str) -> u32 { match v { diff --git a/tests/ui/privacy/private-item-simple-2.rs b/tests/ui/privacy/private-item-simple-2.rs deleted file mode 100644 index 9dea54ea779e..000000000000 --- a/tests/ui/privacy/private-item-simple-2.rs +++ /dev/null @@ -1,10 +0,0 @@ -use zoo::fly; //~ ERROR: function `fly` is private - -mod zoo { - fn fly() {} -} - - -fn main() { - fly(); -} diff --git a/tests/ui/privacy/private-item-simple-2.stderr b/tests/ui/privacy/private-item-simple-2.stderr deleted file mode 100644 index cf839a131406..000000000000 --- a/tests/ui/privacy/private-item-simple-2.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0603]: function `fly` is private - --> $DIR/issue-3993.rs:1:10 - | -LL | use zoo::fly; - | ^^^ private function - | -note: the function `fly` is defined here - --> $DIR/issue-3993.rs:4:5 - | -LL | fn fly() {} - | ^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/privacy/private-item-simple.rs b/tests/ui/privacy/private-item-simple.rs index 1f718ed9201a..68b20991a626 100644 --- a/tests/ui/privacy/private-item-simple.rs +++ b/tests/ui/privacy/private-item-simple.rs @@ -1,3 +1,5 @@ +//! regression test for issue #3993 + mod a { fn f() {} } @@ -5,3 +7,7 @@ fn f() {} fn main() { a::f(); //~ ERROR function `f` is private } + +fn foo() { + use a::f; //~ ERROR function `f` is private +} diff --git a/tests/ui/privacy/private-item-simple.stderr b/tests/ui/privacy/private-item-simple.stderr index 330d892e939d..95165857940e 100644 --- a/tests/ui/privacy/private-item-simple.stderr +++ b/tests/ui/privacy/private-item-simple.stderr @@ -1,15 +1,27 @@ error[E0603]: function `f` is private - --> $DIR/private-item-simple.rs:6:8 + --> $DIR/private-item-simple.rs:12:12 + | +LL | use a::f; + | ^ private function + | +note: the function `f` is defined here + --> $DIR/private-item-simple.rs:4:5 + | +LL | fn f() {} + | ^^^^^^ + +error[E0603]: function `f` is private + --> $DIR/private-item-simple.rs:8:8 | LL | a::f(); | ^ private function | note: the function `f` is defined here - --> $DIR/private-item-simple.rs:2:5 + --> $DIR/private-item-simple.rs:4:5 | LL | fn f() {} | ^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/str/str-add-operator-2.rs b/tests/ui/str/str-add-operator-2.rs deleted file mode 100644 index 61e096622252..000000000000 --- a/tests/ui/str/str-add-operator-2.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let b = "hello"; - println!("🦀🦀🦀🦀🦀"); let _a = b + ", World!"; - //~^ ERROR E0369 -} diff --git a/tests/ui/str/str-add-operator-2.stderr b/tests/ui/str/str-add-operator-2.stderr deleted file mode 100644 index 4fca0296e437..000000000000 --- a/tests/ui/str/str-add-operator-2.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0369]: cannot add `&str` to `&str` - --> $DIR/issue-47380.rs:3:35 - | -LL | println!("🦀🦀🦀🦀🦀"); let _a = b + ", World!"; - | - ^ ---------- &str - | | | - | | `+` cannot be used to concatenate two `&str` strings - | &str - | - = note: string concatenation requires an owned `String` on the left -help: create an owned `String` from a string reference - | -LL | println!("🦀🦀🦀🦀🦀"); let _a = b.to_owned() + ", World!"; - | +++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/str/str-add-operator.rs b/tests/ui/str/str-add-operator.rs index 7a2e0fe6d21d..9c489f2091f8 100644 --- a/tests/ui/str/str-add-operator.rs +++ b/tests/ui/str/str-add-operator.rs @@ -1,3 +1,4 @@ +//! regression test for issue #47377, #47380 // ignore-tidy-tab fn main() { let b = "hello"; diff --git a/tests/ui/str/str-add-operator.stderr b/tests/ui/str/str-add-operator.stderr index 12e5c15d77fc..2354819d7fa1 100644 --- a/tests/ui/str/str-add-operator.stderr +++ b/tests/ui/str/str-add-operator.stderr @@ -1,5 +1,5 @@ error[E0369]: cannot add `&str` to `&str` - --> $DIR/issue-47377.rs:4:14 + --> $DIR/str-add-operator.rs:5:14 | LL | let _a = b + ", World!"; | - ^ ---------- &str diff --git a/tests/ui/traits/normalize-associated-type-in-where-clause.rs b/tests/ui/traits/normalize-associated-type-in-where-clause.rs index d7761b50b4c4..25ca4a41aa85 100644 --- a/tests/ui/traits/normalize-associated-type-in-where-clause.rs +++ b/tests/ui/traits/normalize-associated-type-in-where-clause.rs @@ -1,30 +1,30 @@ //@ run-pass -// regression test for issue #50825 -// Check that the feature gate normalizes associated types. +//! regression test for issue #50825, #51044 +//! Check that the feature gate normalizes associated types. #![allow(dead_code)] struct Foo(T); struct Duck; struct Quack; -trait Hello where A: Animal { +trait Hello +where + A: Animal, +{ } trait Animal { type Noise; } -trait Loud { -} +trait Loud {} -impl Loud for f32 { -} +impl Loud for f32 {} impl Animal for Duck { type Noise = Quack; } -impl Hello for Foo where f32: Loud<::Noise> { -} +impl Hello for Foo where f32: Loud<::Noise> {} fn main() {} diff --git a/tests/ui/type/never-type-inference-fail.rs b/tests/ui/type/never-type-inference-fail.rs index 82cf49de8227..76ee3c5f5d56 100644 --- a/tests/ui/type/never-type-inference-fail.rs +++ b/tests/ui/type/never-type-inference-fail.rs @@ -1,3 +1,5 @@ +//! regression test for issue #2151 + fn main() { let x = panic!(); //~ ERROR type annotations needed x.clone(); diff --git a/tests/ui/type/never-type-inference-fail.stderr b/tests/ui/type/never-type-inference-fail.stderr index b130f162414d..1d2457103f1c 100644 --- a/tests/ui/type/never-type-inference-fail.stderr +++ b/tests/ui/type/never-type-inference-fail.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/issue-2151.rs:2:9 + --> $DIR/never-type-inference-fail.rs:4:9 | LL | let x = panic!(); | ^ diff --git a/tests/ui/typeck/non-function-call-error-2.rs b/tests/ui/typeck/non-function-call-error-2.rs deleted file mode 100644 index 0b78fc1bb7fa..000000000000 --- a/tests/ui/typeck/non-function-call-error-2.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn func(i: i32) { - i(); //~ERROR expected function, found `i32` -} -fn main() { - let i = 0i32; - i(); //~ERROR expected function, found `i32` -} diff --git a/tests/ui/typeck/non-function-call-error-2.stderr b/tests/ui/typeck/non-function-call-error-2.stderr deleted file mode 100644 index f64b61aaeb05..000000000000 --- a/tests/ui/typeck/non-function-call-error-2.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0618]: expected function, found `i32` - --> $DIR/issue-10969.rs:2:5 - | -LL | fn func(i: i32) { - | - `i` has type `i32` -LL | i(); - | ^-- - | | - | call expression requires function - -error[E0618]: expected function, found `i32` - --> $DIR/issue-10969.rs:6:5 - | -LL | let i = 0i32; - | - `i` has type `i32` -LL | i(); - | ^-- - | | - | call expression requires function - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0618`. diff --git a/tests/ui/typeck/non-function-call-error.rs b/tests/ui/typeck/non-function-call-error.rs index 197a19c038c4..c61cf93d138a 100644 --- a/tests/ui/typeck/non-function-call-error.rs +++ b/tests/ui/typeck/non-function-call-error.rs @@ -1,9 +1,19 @@ +//! Regression test for issue #10969, #22468 + fn main() { let foo = "bar"; let x = foo("baz"); //~^ ERROR: expected function, found `&str` + + let i = 0i32; + i(); + //~^ ERROR expected function, found `i32` } fn foo(file: &str) -> bool { true } + +fn func(i: i32) { + i(); //~ERROR expected function, found `i32` +} diff --git a/tests/ui/typeck/non-function-call-error.stderr b/tests/ui/typeck/non-function-call-error.stderr index 052888d2029b..f4797ac3d8b7 100644 --- a/tests/ui/typeck/non-function-call-error.stderr +++ b/tests/ui/typeck/non-function-call-error.stderr @@ -1,5 +1,5 @@ error[E0618]: expected function, found `&str` - --> $DIR/issue-22468.rs:3:13 + --> $DIR/non-function-call-error.rs:5:13 | LL | let foo = "bar"; | --- `foo` has type `&str` @@ -11,6 +11,26 @@ LL | let x = foo("baz"); LL | fn foo(file: &str) -> bool { | -------------------------- this function of the same name is available here, but it's shadowed by the local binding -error: aborting due to 1 previous error +error[E0618]: expected function, found `i32` + --> $DIR/non-function-call-error.rs:9:5 + | +LL | let i = 0i32; + | - `i` has type `i32` +LL | i(); + | ^-- + | | + | call expression requires function + +error[E0618]: expected function, found `i32` + --> $DIR/non-function-call-error.rs:18:5 + | +LL | fn func(i: i32) { + | - `i` has type `i32` +LL | i(); + | ^-- + | | + | call expression requires function + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0618`. From f8bbf2ca0685b3d14795823bfff50ac2a0332d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 27 Nov 2025 12:21:35 +0100 Subject: [PATCH 384/585] split out blob decode trait --- compiler/rustc_hir/src/definitions.rs | 8 +- compiler/rustc_hir/src/lang_items.rs | 4 +- compiler/rustc_hir/src/stability.rs | 10 +- compiler/rustc_hir/src/version.rs | 4 +- compiler/rustc_macros/src/lib.rs | 13 +- compiler/rustc_macros/src/serialize.rs | 17 +- compiler/rustc_metadata/src/locator.rs | 1 + compiler/rustc_metadata/src/rmeta/decoder.rs | 296 ++++++++++++------ .../src/rmeta/decoder/cstore_impl.rs | 11 +- .../src/rmeta/def_path_hash_map.rs | 7 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/mod.rs | 11 +- compiler/rustc_metadata/src/rmeta/table.rs | 7 +- compiler/rustc_middle/src/middle/mod.rs | 4 +- .../rustc_middle/src/query/on_disk_cache.rs | 54 ++-- compiler/rustc_middle/src/ty/mod.rs | 6 +- compiler/rustc_session/src/config.rs | 6 +- compiler/rustc_session/src/cstore.rs | 6 +- compiler/rustc_session/src/options.rs | 8 +- compiler/rustc_span/src/def_id.rs | 4 +- compiler/rustc_span/src/edition.rs | 4 +- compiler/rustc_span/src/lib.rs | 45 +-- compiler/rustc_target/src/spec/mod.rs | 6 +- 23 files changed, 331 insertions(+), 203 deletions(-) diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 07d5bcdd6ee9..01f84c90ec7a 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -11,7 +11,7 @@ use rustc_data_structures::unord::UnordMap; use rustc_hashes::Hash64; use rustc_index::IndexVec; -use rustc_macros::{Decodable, Encodable}; +use rustc_macros::{BlobDecodable, Decodable, Encodable}; use rustc_span::{Symbol, kw, sym}; use tracing::{debug, instrument}; @@ -127,7 +127,7 @@ pub struct Definitions { /// A unique identifier that we can use to lookup a definition /// precisely. It combines the index of the definition's parent (if /// any) with a `DisambiguatedDefPathData`. -#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)] +#[derive(Copy, Clone, PartialEq, Debug, Encodable, BlobDecodable)] pub struct DefKey { /// The parent path. pub parent: Option, @@ -176,7 +176,7 @@ pub fn get_opt_name(&self) -> Option { /// between them. This introduces some artificial ordering dependency /// but means that if you have, e.g., two impls for the same type in /// the same module, they do get distinct `DefId`s. -#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)] +#[derive(Copy, Clone, PartialEq, Debug, Encodable, BlobDecodable)] pub struct DisambiguatedDefPathData { pub data: DefPathData, pub disambiguator: u32, @@ -270,7 +270,7 @@ pub fn to_filename_friendly_no_crate(&self) -> String { } /// New variants should only be added in synchronization with `enum DefKind`. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, BlobDecodable)] pub enum DefPathData { // Root: these should only be used for the root nodes, because // they are treated specially by the `def_path` function. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 51e798d1e83b..4ac3e4e83e80 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -10,7 +10,7 @@ use rustc_ast::attr::AttributeExt; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic}; use rustc_span::{Span, Symbol, kw, sym}; use crate::def_id::DefId; @@ -75,7 +75,7 @@ macro_rules! language_item_table { $( $(#[$attr:meta])* $variant:ident, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )* ) => { /// A representation of all the valid lang items in Rust. - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)] + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, BlobDecodable)] pub enum LangItem { $( #[doc = concat!("The `", stringify!($name), "` lang item.")] diff --git a/compiler/rustc_hir/src/stability.rs b/compiler/rustc_hir/src/stability.rs index 2b3a2a793163..9297f8e6cdcd 100644 --- a/compiler/rustc_hir/src/stability.rs +++ b/compiler/rustc_hir/src/stability.rs @@ -1,6 +1,6 @@ use std::num::NonZero; -use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; +use rustc_macros::{BlobDecodable, Decodable, Encodable, HashStable_Generic, PrintAttribute}; use rustc_span::{ErrorGuaranteed, Symbol, sym}; use crate::RustcVersion; @@ -21,7 +21,7 @@ /// /// - `#[stable]` /// - `#[unstable]` -#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Encodable, BlobDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(HashStable_Generic, PrintAttribute)] pub struct Stability { pub level: StabilityLevel, @@ -103,7 +103,7 @@ pub fn is_const_stable(&self) -> bool { } /// The available stability levels. -#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] +#[derive(Encodable, BlobDecodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] #[derive(HashStable_Generic, PrintAttribute)] pub enum StabilityLevel { /// `#[unstable]` @@ -146,7 +146,7 @@ pub enum StabilityLevel { } /// Rust release in which a feature is stabilized. -#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)] +#[derive(Encodable, BlobDecodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)] #[derive(HashStable_Generic, PrintAttribute)] pub enum StableSince { /// also stores the original symbol for printing @@ -172,7 +172,7 @@ pub fn stable_since(&self) -> Option { } } -#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] +#[derive(Encodable, BlobDecodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] #[derive(HashStable_Generic, PrintAttribute)] pub enum UnstableReason { None, diff --git a/compiler/rustc_hir/src/version.rs b/compiler/rustc_hir/src/version.rs index bc2c38a49350..03182088d4c0 100644 --- a/compiler/rustc_hir/src/version.rs +++ b/compiler/rustc_hir/src/version.rs @@ -4,12 +4,12 @@ use rustc_error_messages::{DiagArgValue, IntoDiagArg}; use rustc_macros::{ - Decodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version, + BlobDecodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version, }; use crate::attrs::PrintAttribute; -#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Encodable, BlobDecodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(HashStable_Generic, PrintAttribute)] pub struct RustcVersion { pub major: u16, diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index a6f53d92e100..9f55143ecf53 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -78,7 +78,18 @@ pub fn extension(attr: TokenStream, input: TokenStream) -> TokenStream { decl_derive!([Encodable] => serialize::encodable_derive); decl_derive!([TyDecodable] => serialize::type_decodable_derive); decl_derive!([TyEncodable] => serialize::type_encodable_derive); -decl_derive!([MetadataDecodable] => serialize::meta_decodable_derive); +decl_derive!([MetadataDecodable] => + /// This constrains the decoder to be specifically the decoder that can decode LazyArrays in metadata. + /// Therefore, we only use this on things containing LazyArray really. + /// Anything else should either be `NoContext`, if possible `BlobDecodable`, or otherwise just `Decodable`. + serialize::meta_decodable_derive +); +decl_derive!([BlobDecodable] => + /// For anything that is "simple" to decode, without needing anything but the original data, + /// but for which the Decoder can customize some things + /// (unlike Decodable_NoContext which individual decoders can't customize). + serialize::blob_decodable_derive +); decl_derive!([MetadataEncodable] => serialize::meta_encodable_derive); decl_derive!( [TypeFoldable, attributes(type_foldable)] => diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index c7aaaf0da467..abf566288df4 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -16,14 +16,21 @@ pub(super) fn type_decodable_derive( decodable_body(s, decoder_ty) } +pub(super) fn blob_decodable_derive( + mut s: synstructure::Structure<'_>, +) -> proc_macro2::TokenStream { + let decoder_ty = quote! { __D }; + s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_span::BlobDecoder }); + s.add_bounds(synstructure::AddBounds::Generics); + + decodable_body(s, decoder_ty) +} + pub(super) fn meta_decodable_derive( mut s: synstructure::Structure<'_>, ) -> proc_macro2::TokenStream { - if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { - s.add_impl_generic(parse_quote! { 'tcx }); - } - s.add_impl_generic(parse_quote! { '__a }); - let decoder_ty = quote! { DecodeContext<'__a, 'tcx> }; + let decoder_ty = quote! { __D }; + s.add_impl_generic(parse_quote! { #decoder_ty: LazyDecoder }); s.add_bounds(synstructure::AddBounds::Generics); decodable_body(s, decoder_ty) diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 9fef22f9558d..6a441706a22b 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -224,6 +224,7 @@ use rustc_data_structures::svh::Svh; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_fs_util::try_canonicalize; +use rustc_middle::ty::TyCtxt; use rustc_session::cstore::CrateSource; use rustc_session::filesearch::FileSearch; use rustc_session::search_paths::PathKind; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 25e7574d3b37..b1cac381e05b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1,6 +1,7 @@ // Decoding metadata from a single crate's metadata use std::iter::TrustedLen; +use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; use std::sync::{Arc, OnceLock}; use std::{io, mem}; @@ -33,7 +34,8 @@ use rustc_session::cstore::{CrateSource, ExternCrate}; use rustc_span::hygiene::HygieneDecodeContext; use rustc_span::{ - BytePos, ByteSymbol, DUMMY_SP, Pos, SpanData, SpanDecoder, Symbol, SyntaxContext, kw, + BlobDecoder, BytePos, ByteSymbol, DUMMY_SP, Pos, SpanData, SpanDecoder, Symbol, SyntaxContext, + kw, }; use tracing::debug; @@ -154,22 +156,106 @@ struct ImportedSourceFile { translated_source_file: Arc, } -pub(super) struct DecodeContext<'a, 'tcx> { +/// Decode context used when we just have a blob, +/// and we still have to read the header etc. +pub(super) struct BlobDecodeContext<'a> { opaque: MemDecoder<'a>, - cdata: Option>, blob: &'a MetadataBlob, + lazy_state: LazyState, +} + +/// trait for anything containing `LazyState` and is a decoder. +// TODO: might need to live in rustc_middle +pub(super) trait LazyDecoder: BlobDecoder { + fn set_lazy_state(&mut self, state: LazyState); + fn get_lazy_state(&self) -> LazyState; + + fn read_lazy(&mut self) -> LazyValue { + self.read_lazy_offset_then(|pos| LazyValue::from_position(pos)) + } + + fn read_lazy_array(&mut self, len: usize) -> LazyArray { + self.read_lazy_offset_then(|pos| LazyArray::from_position_and_num_elems(pos, len)) + } + + fn read_lazy_table(&mut self, width: usize, len: usize) -> LazyTable { + self.read_lazy_offset_then(|pos| LazyTable::from_position_and_encoded_size(pos, width, len)) + } + + #[inline] + fn read_lazy_offset_then(&mut self, f: impl Fn(NonZero) -> T) -> T { + let distance = self.read_usize(); + let position = match self.get_lazy_state() { + LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"), + LazyState::NodeStart(start) => { + let start = start.get(); + assert!(distance <= start); + start - distance + } + LazyState::Previous(last_pos) => last_pos.get() + distance, + }; + let position = NonZero::new(position).unwrap(); + self.set_lazy_state(LazyState::Previous(position)); + f(position) + } +} + +impl<'a> LazyDecoder for BlobDecodeContext<'a> { + fn set_lazy_state(&mut self, state: LazyState) { + self.lazy_state = state; + } + + fn get_lazy_state(&self) -> LazyState { + self.lazy_state + } +} + +/// This is the decode context used when crate metadata was already read. +/// Decoding of some types, like `Span` require some information to already been read. +pub(super) struct MetadataDecodeContext<'a, 'tcx> { + blob_decoder: BlobDecodeContext<'a>, + cdata: Option>, sess: Option<&'tcx Session>, tcx: Option>, - lazy_state: LazyState, - // Used for decoding interpret::AllocIds in a cached & thread-safe manner. alloc_decoding_session: Option>, } +impl<'a, 'tcx> LazyDecoder for MetadataDecodeContext<'a, 'tcx> { + fn set_lazy_state(&mut self, state: LazyState) { + self.lazy_state = state; + } + + fn get_lazy_state(&self) -> LazyState { + self.lazy_state + } +} + +impl<'a, 'tcx> DerefMut for MetadataDecodeContext<'a, 'tcx> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.blob_decoder + } +} + +impl<'a, 'tcx> Deref for MetadataDecodeContext<'a, 'tcx> { + type Target = BlobDecodeContext<'a>; + + fn deref(&self) -> &Self::Target { + &self.blob_decoder + } +} + +pub(super) trait BlobMetadata<'a, 'tcx>: Copy { + type Context: BlobDecoder + LazyDecoder; + + fn blob(self) -> &'a MetadataBlob; + fn decoder(self, pos: usize) -> Self::Context; +} + /// Abstract over the various ways one can create metadata decoders. pub(super) trait Metadata<'a, 'tcx>: Copy { - fn blob(self) -> &'a MetadataBlob; + fn _blob(self) -> &'a MetadataBlob; fn cdata(self) -> Option> { None @@ -180,23 +266,25 @@ fn sess(self) -> Option<&'tcx Session> { fn tcx(self) -> Option> { None } +} - fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> { +impl<'a, 'tcx, T> BlobMetadata<'a, 'tcx> for T +where + T: Metadata<'a, 'tcx>, +{ + type Context = MetadataDecodeContext<'a, 'tcx>; + + fn blob(self) -> &'a MetadataBlob { + self._blob() + } + + fn decoder(self, pos: usize) -> MetadataDecodeContext<'a, 'tcx> { let tcx = self.tcx(); - DecodeContext { - // FIXME: This unwrap should never panic because we check that it won't when creating - // `MetadataBlob`. Ideally we'd just have a `MetadataDecoder` and hand out subslices of - // it as we do elsewhere in the compiler using `MetadataDecoder::split_at`. But we own - // the data for the decoder so holding onto the `MemDecoder` too would make us a - // self-referential struct which is downright goofy because `MetadataBlob` is already - // self-referential. Probably `MemDecoder` should contain an `OwnedSlice`, but that - // demands a significant refactoring due to our crate graph. - opaque: MemDecoder::new(self.blob(), pos).unwrap(), + MetadataDecodeContext { + blob_decoder: self.blob().decoder(pos), cdata: self.cdata(), - blob: self.blob(), sess: self.sess().or(tcx.map(|tcx| tcx.sess)), tcx, - lazy_state: LazyState::NoNode, alloc_decoding_session: self .cdata() .map(|cdata| cdata.cdata.alloc_decoding_state.new_decoding_session()), @@ -204,16 +292,32 @@ fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob { - #[inline] +impl<'a, 'tcx> BlobMetadata<'a, 'tcx> for &'a MetadataBlob { + type Context = BlobDecodeContext<'a>; + fn blob(self) -> &'a MetadataBlob { self } + + fn decoder(self, pos: usize) -> Self::Context { + BlobDecodeContext { + // FIXME: This unwrap should never panic because we check that it won't when creating + // `MetadataBlob`. Ideally we'd just have a `MetadataDecoder` and hand out subslices of + // it as we do elsewhere in the compiler using `MetadataDecoder::split_at`. But we own + // the data for the decoder so holding onto the `MemDecoder` too would make us a + // self-referential struct which is downright goofy because `MetadataBlob` is already + // self-referential. Probably `MemDecoder` should contain an `OwnedSlice`, but that + // demands a significant refactoring due to our crate graph. + opaque: MemDecoder::new(self, pos).unwrap(), + lazy_state: LazyState::NoNode, + blob: self.blob(), + } + } } impl<'a, 'tcx> Metadata<'a, 'tcx> for CrateMetadataRef<'a> { #[inline] - fn blob(self) -> &'a MetadataBlob { + fn _blob(self) -> &'a MetadataBlob { &self.cdata.blob } #[inline] @@ -224,7 +328,7 @@ fn cdata(self) -> Option> { impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, &'tcx Session) { #[inline] - fn blob(self) -> &'a MetadataBlob { + fn _blob(self) -> &'a MetadataBlob { &self.0.cdata.blob } #[inline] @@ -239,7 +343,7 @@ fn sess(self) -> Option<&'tcx Session> { impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, TyCtxt<'tcx>) { #[inline] - fn blob(self) -> &'a MetadataBlob { + fn _blob(self) -> &'a MetadataBlob { &self.0.cdata.blob } #[inline] @@ -254,23 +358,23 @@ fn tcx(self) -> Option> { impl LazyValue { #[inline] - fn decode<'a, 'tcx, M: Metadata<'a, 'tcx>>(self, metadata: M) -> T::Value<'tcx> + fn decode<'a, 'tcx, M: BlobMetadata<'a, 'tcx>>(self, metadata: M) -> T::Value<'tcx> where - T::Value<'tcx>: Decodable>, + T::Value<'tcx>: Decodable, { let mut dcx = metadata.decoder(self.position.get()); - dcx.lazy_state = LazyState::NodeStart(self.position); + dcx.set_lazy_state(LazyState::NodeStart(self.position)); T::Value::decode(&mut dcx) } } -struct DecodeIterator<'a, 'tcx, T> { +struct DecodeIterator { elem_counter: std::ops::Range, - dcx: DecodeContext<'a, 'tcx>, + dcx: D, _phantom: PhantomData T>, } -impl<'a, 'tcx, T: Decodable>> Iterator for DecodeIterator<'a, 'tcx, T> { +impl> Iterator for DecodeIterator { type Item = T; #[inline(always)] @@ -284,35 +388,30 @@ fn size_hint(&self) -> (usize, Option) { } } -impl<'a, 'tcx, T: Decodable>> ExactSizeIterator - for DecodeIterator<'a, 'tcx, T> -{ +impl> ExactSizeIterator for DecodeIterator { fn len(&self) -> usize { self.elem_counter.len() } } -unsafe impl<'a, 'tcx, T: Decodable>> TrustedLen - for DecodeIterator<'a, 'tcx, T> -{ -} +unsafe impl> TrustedLen for DecodeIterator {} impl LazyArray { #[inline] - fn decode<'a, 'tcx, M: Metadata<'a, 'tcx>>( + fn decode<'a, 'tcx, M: BlobMetadata<'a, 'tcx>>( self, metadata: M, - ) -> DecodeIterator<'a, 'tcx, T::Value<'tcx>> + ) -> DecodeIterator, M::Context> where - T::Value<'tcx>: Decodable>, + T::Value<'tcx>: Decodable, { let mut dcx = metadata.decoder(self.position.get()); - dcx.lazy_state = LazyState::NodeStart(self.position); + dcx.set_lazy_state(LazyState::NodeStart(self.position)); DecodeIterator { elem_counter: (0..self.num_elems), dcx, _phantom: PhantomData } } } -impl<'a, 'tcx> DecodeContext<'a, 'tcx> { +impl<'a, 'tcx> MetadataDecodeContext<'a, 'tcx> { #[inline] fn tcx(&self) -> TyCtxt<'tcx> { let Some(tcx) = self.tcx else { @@ -324,11 +423,6 @@ fn tcx(&self) -> TyCtxt<'tcx> { tcx } - #[inline] - pub(crate) fn blob(&self) -> &'a MetadataBlob { - self.blob - } - #[inline] fn cdata(&self) -> CrateMetadataRef<'a> { debug_assert!(self.cdata.is_some(), "missing CrateMetadata in DecodeContext"); @@ -339,34 +433,12 @@ fn cdata(&self) -> CrateMetadataRef<'a> { fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum { self.cdata().map_encoded_cnum_to_current(cnum) } +} +impl<'a> BlobDecodeContext<'a> { #[inline] - fn read_lazy_offset_then(&mut self, f: impl Fn(NonZero) -> T) -> T { - let distance = self.read_usize(); - let position = match self.lazy_state { - LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"), - LazyState::NodeStart(start) => { - let start = start.get(); - assert!(distance <= start); - start - distance - } - LazyState::Previous(last_pos) => last_pos.get() + distance, - }; - let position = NonZero::new(position).unwrap(); - self.lazy_state = LazyState::Previous(position); - f(position) - } - - fn read_lazy(&mut self) -> LazyValue { - self.read_lazy_offset_then(|pos| LazyValue::from_position(pos)) - } - - fn read_lazy_array(&mut self, len: usize) -> LazyArray { - self.read_lazy_offset_then(|pos| LazyArray::from_position_and_num_elems(pos, len)) - } - - fn read_lazy_table(&mut self, width: usize, len: usize) -> LazyTable { - self.read_lazy_offset_then(|pos| LazyTable::from_position_and_encoded_size(pos, width, len)) + pub(crate) fn blob(&self) -> &'a MetadataBlob { + self.blob } #[inline] @@ -397,7 +469,7 @@ fn decode_symbol_or_byte_symbol( } } -impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { +impl<'a, 'tcx> TyDecoder<'tcx> for MetadataDecodeContext<'a, 'tcx> { const CLEAR_CROSS_CRATE: bool = true; #[inline] @@ -426,12 +498,12 @@ fn with_position(&mut self, pos: usize, f: F) -> R where F: FnOnce(&mut Self) -> R, { - let new_opaque = self.opaque.split_at(pos); - let old_opaque = mem::replace(&mut self.opaque, new_opaque); - let old_state = mem::replace(&mut self.lazy_state, LazyState::NoNode); + let new_opaque = self.blob_decoder.opaque.split_at(pos); + let old_opaque = mem::replace(&mut self.blob_decoder.opaque, new_opaque); + let old_state = mem::replace(&mut self.blob_decoder.lazy_state, LazyState::NoNode); let r = f(self); - self.opaque = old_opaque; - self.lazy_state = old_state; + self.blob_decoder.opaque = old_opaque; + self.blob_decoder.lazy_state = old_state; r } @@ -444,14 +516,14 @@ fn decode_alloc_id(&mut self) -> rustc_middle::mir::interpret::AllocId { } } -impl<'a, 'tcx> Decodable> for ExpnIndex { +impl<'a, 'tcx> Decodable> for ExpnIndex { #[inline] - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> ExpnIndex { + fn decode(d: &mut MetadataDecodeContext<'a, 'tcx>) -> ExpnIndex { ExpnIndex::from_u32(d.read_u32()) } } -impl<'a, 'tcx> SpanDecoder for DecodeContext<'a, 'tcx> { +impl<'a, 'tcx> SpanDecoder for MetadataDecodeContext<'a, 'tcx> { fn decode_attr_id(&mut self) -> rustc_span::AttrId { let sess = self.sess.expect("can't decode AttrId without Session"); sess.psess.attr_id_generator.mk_attr_id() @@ -462,10 +534,6 @@ fn decode_crate_num(&mut self) -> CrateNum { self.map_encoded_cnum_to_current(cnum) } - fn decode_def_index(&mut self) -> DefIndex { - DefIndex::from_u32(self.read_u32()) - } - fn decode_def_id(&mut self) -> DefId { DefId { krate: Decodable::decode(self), index: Decodable::decode(self) } } @@ -554,7 +622,25 @@ fn decode_span(&mut self) -> Span { }; data.span() } +} +impl<'a, 'tcx> BlobDecoder for MetadataDecodeContext<'a, 'tcx> { + fn decode_def_index(&mut self) -> DefIndex { + self.blob_decoder.decode_def_index() + } + fn decode_symbol(&mut self) -> Symbol { + self.blob_decoder.decode_symbol() + } + + fn decode_byte_symbol(&mut self) -> ByteSymbol { + self.blob_decoder.decode_byte_symbol() + } +} + +impl<'a> BlobDecoder for BlobDecodeContext<'a> { + fn decode_def_index(&mut self) -> DefIndex { + DefIndex::from_u32(self.read_u32()) + } fn decode_symbol(&mut self) -> Symbol { self.decode_symbol_or_byte_symbol( Symbol::new, @@ -572,8 +658,8 @@ fn decode_byte_symbol(&mut self) -> ByteSymbol { } } -impl<'a, 'tcx> Decodable> for SpanData { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SpanData { +impl<'a, 'tcx> Decodable> for SpanData { + fn decode(decoder: &mut MetadataDecodeContext<'a, 'tcx>) -> SpanData { let tag = SpanTag::decode(decoder); let ctxt = tag.context().unwrap_or_else(|| SyntaxContext::decode(decoder)); @@ -677,43 +763,50 @@ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SpanData { } } -impl<'a, 'tcx> Decodable> for &'tcx [(ty::Clause<'tcx>, Span)] { - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { +impl<'a, 'tcx> Decodable> for &'tcx [(ty::Clause<'tcx>, Span)] { + fn decode(d: &mut MetadataDecodeContext<'a, 'tcx>) -> Self { ty::codec::RefDecodable::decode(d) } } -impl<'a, 'tcx, T> Decodable> for LazyValue { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self { +impl Decodable for LazyValue { + fn decode(decoder: &mut D) -> Self { decoder.read_lazy() } } -impl<'a, 'tcx, T> Decodable> for LazyArray { +impl Decodable for LazyArray { #[inline] - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self { + fn decode(decoder: &mut D) -> Self { let len = decoder.read_usize(); if len == 0 { LazyArray::default() } else { decoder.read_lazy_array(len) } } } -impl<'a, 'tcx, I: Idx, T> Decodable> for LazyTable { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self { +impl Decodable for LazyTable { + fn decode(decoder: &mut D) -> Self { let width = decoder.read_usize(); let len = decoder.read_usize(); decoder.read_lazy_table(width, len) } } -implement_ty_decoder!(DecodeContext<'a, 'tcx>); +mod meta { + use super::*; + implement_ty_decoder!(MetadataDecodeContext<'a, 'tcx>); +} +mod blob { + use super::*; + implement_ty_decoder!(BlobDecodeContext<'a>); +} impl MetadataBlob { pub(crate) fn check_compatibility( &self, cfg_version: &'static str, ) -> Result<(), Option> { - if !self.blob().starts_with(METADATA_HEADER) { - if self.blob().starts_with(b"rust") { + if !self.starts_with(METADATA_HEADER) { + if self.starts_with(b"rust") { return Err(Some("".to_owned())); } return Err(None); @@ -731,7 +824,7 @@ pub(crate) fn check_compatibility( fn root_pos(&self) -> NonZero { let offset = METADATA_HEADER.len(); - let pos_bytes = self.blob()[offset..][..8].try_into().unwrap(); + let pos_bytes = self[offset..][..8].try_into().unwrap(); let pos = u64::from_le_bytes(pos_bytes); NonZero::new(pos as usize).unwrap() } @@ -1897,11 +1990,12 @@ pub(crate) fn new( }; // Need `CrateMetadataRef` to decode `DefId`s in simplified types. + let cref = CrateMetadataRef { cdata: &cdata, cstore }; cdata.incoherent_impls = cdata .root .incoherent_impls - .decode(CrateMetadataRef { cdata: &cdata, cstore }) - .map(|incoherent_impls| (incoherent_impls.self_ty, incoherent_impls.impls)) + .decode(cref) + .map(|incoherent_impls| (incoherent_impls.self_ty.decode(cref), incoherent_impls.impls)) .collect(); cdata diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 4831395f3164..24cfdc05e5cb 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -15,12 +15,13 @@ use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::util::Providers; +use rustc_serialize::Decoder; use rustc_session::cstore::{CrateStore, ExternCrate}; use rustc_session::{Session, StableCrateId}; use rustc_span::hygiene::ExpnId; use rustc_span::{Span, Symbol, kw}; -use super::{Decodable, DecodeContext, DecodeIterator}; +use super::{Decodable, DecodeIterator}; use crate::creader::{CStore, LoadedMacro}; use crate::rmeta::AttrFlags; use crate::rmeta::table::IsDefault; @@ -65,8 +66,8 @@ fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Result>> ProcessQueryValue<'tcx, &'tcx [T]> - for Option> +impl<'tcx, D: Decoder, T: Copy + Decodable> ProcessQueryValue<'tcx, &'tcx [T]> + for Option> { #[inline(always)] fn process_decoded(self, tcx: TyCtxt<'tcx>, err: impl Fn() -> !) -> &'tcx [T] { @@ -74,8 +75,8 @@ fn process_decoded(self, tcx: TyCtxt<'tcx>, err: impl Fn() -> !) -> &'tcx [T] { } } -impl<'a, 'tcx, T: Copy + Decodable>> - ProcessQueryValue<'tcx, Option<&'tcx [T]>> for Option> +impl<'tcx, D: Decoder, T: Copy + Decodable> ProcessQueryValue<'tcx, Option<&'tcx [T]>> + for Option> { #[inline(always)] fn process_decoded(self, tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> Option<&'tcx [T]> { diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs index a17b3e1047d0..949d7630f673 100644 --- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs +++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs @@ -3,7 +3,8 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::def_id::{DefIndex, DefPathHash}; -use crate::rmeta::{DecodeContext, EncodeContext}; +use crate::rmeta::EncodeContext; +use crate::rmeta::decoder::BlobDecodeContext; pub(crate) enum DefPathHashMapRef<'tcx> { OwnedFromMetadata(odht::HashTable), @@ -40,8 +41,8 @@ fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) { } } -impl<'a, 'tcx> Decodable> for DefPathHashMapRef<'static> { - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefPathHashMapRef<'static> { +impl<'a> Decodable> for DefPathHashMapRef<'static> { + fn decode(d: &mut BlobDecodeContext<'a>) -> DefPathHashMapRef<'static> { let len = d.read_usize(); let pos = d.position(); let o = d.blob().bytes().clone().slice(|blob| &blob[pos..pos + len]); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4085fd5e70f1..94bba9445610 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2205,7 +2205,7 @@ fn encode_incoherent_impls(&mut self) -> LazyArray { .incoherent_impls .iter() .map(|(&simp, impls)| IncoherentImpls { - self_ty: simp, + self_ty: self.lazy(simp), impls: self.lazy_array(impls.iter().map(|def_id| def_id.local_def_index)), }) .collect(); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index ac042c2ca75d..b1b9bcfcc506 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -1,8 +1,8 @@ use std::marker::PhantomData; use std::num::NonZero; +use decoder::LazyDecoder; pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob, TargetModifiers}; -use decoder::{DecodeContext, Metadata}; use def_path_hash_map::DefPathHashMapRef; use encoder::EncodeContext; pub use encoder::{EncodedMetadata, encode_metadata, rendered_const}; @@ -19,7 +19,8 @@ use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; use rustc_macros::{ - Decodable, Encodable, MetadataDecodable, MetadataEncodable, TyDecodable, TyEncodable, + BlobDecodable, Decodable, Encodable, MetadataDecodable, MetadataEncodable, TyDecodable, + TyEncodable, }; use rustc_middle::metadata::ModChild; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -201,7 +202,7 @@ pub(crate) struct ProcMacroData { /// See #76720 for more details. /// /// If you do modify this struct, also bump the [`METADATA_VERSION`] constant. -#[derive(MetadataEncodable, MetadataDecodable)] +#[derive(MetadataEncodable, BlobDecodable)] pub(crate) struct CrateHeader { pub(crate) triple: TargetTuple, pub(crate) hash: Svh, @@ -323,7 +324,7 @@ fn decode_from_cdata(self, cdata: CrateMetadataRef<'_>) -> DefId { } } -#[derive(Encodable, Decodable)] +#[derive(Encodable, BlobDecodable)] pub(crate) struct CrateDep { pub name: Symbol, pub hash: Svh, @@ -341,7 +342,7 @@ pub(crate) struct TraitImpls { #[derive(MetadataEncodable, MetadataDecodable)] pub(crate) struct IncoherentImpls { - self_ty: SimplifiedType, + self_ty: LazyValue, impls: LazyArray, } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 4ce313f32a75..aaaed76bda9d 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -1,6 +1,7 @@ use rustc_hir::def::CtorOf; use rustc_index::Idx; +use crate::rmeta::decoder::BlobMetadata; use crate::rmeta::*; pub(super) trait IsDefault: Default { @@ -522,7 +523,11 @@ fn trailing_zeros(x: &[u8]) -> usize { for<'tcx> T::Value<'tcx>: FixedSizeEncoding, { /// Given the metadata, extract out the value at a particular index (if any). - pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(&self, metadata: M, i: I) -> T::Value<'tcx> { + pub(super) fn get<'a, 'tcx, M: BlobMetadata<'a, 'tcx>>( + &self, + metadata: M, + i: I, + ) -> T::Value<'tcx> { // Access past the end of the table returns a Default if i.index() >= self.len { return Default::default(); diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 9091d492c26b..5739d132b66c 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -6,11 +6,11 @@ pub mod lang_items; pub mod lib_features { use rustc_data_structures::unord::UnordMap; - use rustc_macros::{HashStable, TyDecodable, TyEncodable}; + use rustc_macros::{BlobDecodable, Encodable, HashStable}; use rustc_span::{Span, Symbol}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] - #[derive(HashStable, TyEncodable, TyDecodable)] + #[derive(HashStable, Encodable, BlobDecodable)] pub enum FeatureStability { AcceptedSince(Symbol), Unstable { old_name: Option }, diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index e8952d0492d1..c882d5d499bd 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -20,8 +20,8 @@ }; use rustc_span::source_map::Spanned; use rustc_span::{ - BytePos, ByteSymbol, CachingSourceMapView, ExpnData, ExpnHash, Pos, RelativeBytePos, - SourceFile, Span, SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, + BlobDecoder, BytePos, ByteSymbol, CachingSourceMapView, ExpnData, ExpnHash, Pos, + RelativeBytePos, SourceFile, Span, SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, }; use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; @@ -672,36 +672,12 @@ fn decode_span(&mut self) -> Span { Span::new(lo, hi, ctxt, parent) } - fn decode_symbol(&mut self) -> Symbol { - self.decode_symbol_or_byte_symbol( - Symbol::new, - |this| Symbol::intern(this.read_str()), - |opaque| Symbol::intern(opaque.read_str()), - ) - } - - fn decode_byte_symbol(&mut self) -> ByteSymbol { - self.decode_symbol_or_byte_symbol( - ByteSymbol::new, - |this| ByteSymbol::intern(this.read_byte_str()), - |opaque| ByteSymbol::intern(opaque.read_byte_str()), - ) - } - fn decode_crate_num(&mut self) -> CrateNum { let stable_id = StableCrateId::decode(self); let cnum = self.tcx.stable_crate_id_to_crate_num(stable_id); cnum } - // This impl makes sure that we get a runtime error when we try decode a - // `DefIndex` that is not contained in a `DefId`. Such a case would be problematic - // because we would not know how to transform the `DefIndex` to the current - // context. - fn decode_def_index(&mut self) -> DefIndex { - panic!("trying to decode `DefIndex` outside the context of a `DefId`") - } - // Both the `CrateNum` and the `DefIndex` of a `DefId` can change in between two // compilation sessions. We use the `DefPathHash`, which is stable across // sessions, to map the old `DefId` to the new one. @@ -725,6 +701,32 @@ fn decode_attr_id(&mut self) -> rustc_span::AttrId { } } +impl<'a, 'tcx> BlobDecoder for CacheDecoder<'a, 'tcx> { + fn decode_symbol(&mut self) -> Symbol { + self.decode_symbol_or_byte_symbol( + Symbol::new, + |this| Symbol::intern(this.read_str()), + |opaque| Symbol::intern(opaque.read_str()), + ) + } + + fn decode_byte_symbol(&mut self) -> ByteSymbol { + self.decode_symbol_or_byte_symbol( + ByteSymbol::new, + |this| ByteSymbol::intern(this.read_byte_str()), + |opaque| ByteSymbol::intern(opaque.read_byte_str()), + ) + } + + // This impl makes sure that we get a runtime error when we try decode a + // `DefIndex` that is not contained in a `DefId`. Such a case would be problematic + // because we would not know how to transform the `DefIndex` to the current + // context. + fn decode_def_index(&mut self) -> DefIndex { + panic!("trying to decode `DefIndex` outside the context of a `DefId`") + } +} + impl<'a, 'tcx> Decodable> for &'tcx UnordSet { #[inline] fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d3e0fbb955c4..b4c20d7cadf9 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -41,8 +41,8 @@ use rustc_index::IndexVec; use rustc_index::bit_set::BitMatrix; use rustc_macros::{ - Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, - extension, + BlobDecodable, Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, + TypeVisitable, extension, }; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::{Decodable, Encodable}; @@ -264,7 +264,7 @@ pub fn is_async(self) -> bool { } } -#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)] +#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, BlobDecodable, HashStable)] pub enum Visibility { /// Visible everywhere (including in other crates). Public, diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f97a29e064b6..9b19961fcee4 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -21,7 +21,7 @@ use rustc_errors::{ColorConfig, DiagArgValue, DiagCtxtFlags, IntoDiagArg}; use rustc_feature::UnstableFeatures; use rustc_hashes::Hash64; -use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_macros::{BlobDecodable, Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::{DEFAULT_EDITION, EDITION_NAME_LIST, Edition, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; use rustc_span::{ @@ -543,7 +543,7 @@ pub fn enabled(&self) -> bool { } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)] -#[derive(Encodable, Decodable)] +#[derive(Encodable, BlobDecodable)] pub enum SymbolManglingVersion { Legacy, V0, @@ -1521,7 +1521,7 @@ pub enum EntryFnType { }, } -#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)] +#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, BlobDecodable)] #[derive(HashStable_Generic)] pub enum CrateType { Executable, diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 30f6256a75ef..8aef4b179f88 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -12,7 +12,7 @@ CrateNum, DefId, LOCAL_CRATE, LocalDefId, StableCrateId, StableCrateIdMap, }; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; -use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_macros::{BlobDecodable, Decodable, Encodable, HashStable_Generic}; use rustc_span::{Span, Symbol}; use crate::search_paths::PathKind; @@ -36,7 +36,7 @@ pub fn paths(&self) -> impl Iterator { } } -#[derive(Encodable, Decodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] +#[derive(Encodable, BlobDecodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] #[derive(HashStable_Generic)] pub enum CrateDepKind { /// A dependency that is only used for its macros. @@ -59,7 +59,7 @@ pub fn macros_only(self) -> bool { } } -#[derive(Copy, Debug, PartialEq, Clone, Encodable, Decodable, HashStable_Generic)] +#[derive(Copy, Debug, PartialEq, Clone, Encodable, BlobDecodable, HashStable_Generic)] pub enum LinkagePreference { RequireDynamic, RequireStatic, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 872a48efa366..d9792142a884 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -10,7 +10,7 @@ use rustc_errors::{ColorConfig, LanguageIdentifier, TerminalUrl}; use rustc_feature::UnstableFeatures; use rustc_hashes::Hash64; -use rustc_macros::{Decodable, Encodable}; +use rustc_macros::{BlobDecodable, Encodable}; use rustc_span::edition::Edition; use rustc_span::{RealFileName, SourceFileHashAlgorithm}; use rustc_target::spec::{ @@ -75,7 +75,7 @@ pub struct ExtendedTargetModifierInfo { /// A recorded -Zopt_name=opt_value (or -Copt_name=opt_value) /// which alter the ABI or effectiveness of exploit mitigations. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, BlobDecodable)] pub struct TargetModifier { /// Option enum value pub opt: OptionsTargetModifiers, @@ -248,7 +248,7 @@ macro_rules! top_level_tmod_enum { ($user_value:ident){$($pout:tt)*}; ) => { #[allow(non_camel_case_types)] - #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Encodable, Decodable)] + #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Encodable, BlobDecodable)] pub enum OptionsTargetModifiers { $($variant($substruct_enum)),* } @@ -520,7 +520,7 @@ macro_rules! tmod_enum { ($user_value:ident){$($pout:tt)*}; ) => { #[allow(non_camel_case_types)] - #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Encodable, Decodable)] + #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Encodable, BlobDecodable)] pub enum $tmod_enum_name { $($eout),* } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 77f01548bca2..484e626d4638 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -7,7 +7,7 @@ use rustc_data_structures::unhash::Unhasher; use rustc_hashes::Hash64; use rustc_index::Idx; -use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_macros::{BlobDecodable, Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Encodable}; use crate::{HashStableContext, SpanDecoder, SpanEncoder, Symbol}; @@ -141,7 +141,7 @@ impl StableOrd for DefPathHash { /// For more information on the possibility of hash collisions in rustc, /// see the discussion in [`DefId`]. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -#[derive(Hash, HashStable_Generic, Encodable, Decodable)] +#[derive(Hash, HashStable_Generic, Encodable, BlobDecodable)] pub struct StableCrateId(pub(crate) Hash64); impl StableCrateId { diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs index 28335734f4de..a27c5f62c1e5 100644 --- a/compiler/rustc_span/src/edition.rs +++ b/compiler/rustc_span/src/edition.rs @@ -1,10 +1,10 @@ use std::fmt; use std::str::FromStr; -use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic}; /// The edition of the compiler. (See [RFC 2052](https://github.com/rust-lang/rfcs/blob/master/text/2052-epochs.md).) -#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, Encodable, Decodable, Eq)] +#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, Encodable, BlobDecodable, Eq)] #[derive(HashStable_Generic)] pub enum Edition { // When adding new editions, be sure to do the following: diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 31f82860b73d..c6490b358ef8 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1296,20 +1296,37 @@ fn encode(&self, _s: &mut E) { } } -/// This trait is used to allow decoder specific encodings of certain types. -/// It is similar to rustc_type_ir's TyDecoder. -pub trait SpanDecoder: Decoder { - fn decode_span(&mut self) -> Span; +pub trait BlobDecoder: Decoder { fn decode_symbol(&mut self) -> Symbol; fn decode_byte_symbol(&mut self) -> ByteSymbol; + fn decode_def_index(&mut self) -> DefIndex; +} + +/// This trait is used to allow decoder specific encodings of certain types. +/// It is similar to rustc_type_ir's TyDecoder. +pub trait SpanDecoder: BlobDecoder { + fn decode_span(&mut self) -> Span; fn decode_expn_id(&mut self) -> ExpnId; fn decode_syntax_context(&mut self) -> SyntaxContext; fn decode_crate_num(&mut self) -> CrateNum; - fn decode_def_index(&mut self) -> DefIndex; fn decode_def_id(&mut self) -> DefId; fn decode_attr_id(&mut self) -> AttrId; } +impl BlobDecoder for MemDecoder<'_> { + fn decode_symbol(&mut self) -> Symbol { + Symbol::intern(self.read_str()) + } + + fn decode_byte_symbol(&mut self) -> ByteSymbol { + ByteSymbol::intern(self.read_byte_str()) + } + + fn decode_def_index(&mut self) -> DefIndex { + panic!("cannot decode `DefIndex` with `MemDecoder`"); + } +} + impl SpanDecoder for MemDecoder<'_> { fn decode_span(&mut self) -> Span { let lo = Decodable::decode(self); @@ -1318,14 +1335,6 @@ fn decode_span(&mut self) -> Span { Span::new(lo, hi, SyntaxContext::root(), None) } - fn decode_symbol(&mut self) -> Symbol { - Symbol::intern(self.read_str()) - } - - fn decode_byte_symbol(&mut self) -> ByteSymbol { - ByteSymbol::intern(self.read_byte_str()) - } - fn decode_expn_id(&mut self) -> ExpnId { panic!("cannot decode `ExpnId` with `MemDecoder`"); } @@ -1338,10 +1347,6 @@ fn decode_crate_num(&mut self) -> CrateNum { CrateNum::from_u32(self.read_u32()) } - fn decode_def_index(&mut self) -> DefIndex { - panic!("cannot decode `DefIndex` with `MemDecoder`"); - } - fn decode_def_id(&mut self) -> DefId { DefId { krate: Decodable::decode(self), index: Decodable::decode(self) } } @@ -1357,13 +1362,13 @@ fn decode(s: &mut D) -> Span { } } -impl Decodable for Symbol { +impl Decodable for Symbol { fn decode(s: &mut D) -> Symbol { s.decode_symbol() } } -impl Decodable for ByteSymbol { +impl Decodable for ByteSymbol { fn decode(s: &mut D) -> ByteSymbol { s.decode_byte_symbol() } @@ -1387,7 +1392,7 @@ fn decode(s: &mut D) -> CrateNum { } } -impl Decodable for DefIndex { +impl Decodable for DefIndex { fn decode(s: &mut D) -> DefIndex { s.decode_def_index() } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 424026bdceab..c76e345bb7b6 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -52,7 +52,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_error_messages::{DiagArgValue, IntoDiagArg, into_diag_arg_using_display}; use rustc_fs_util::try_canonicalize; -use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_macros::{BlobDecodable, Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::{Symbol, kw, sym}; use serde_json::Value; @@ -830,7 +830,7 @@ pub fn is_cc_enabled(self) -> bool { } crate::target_spec_enum! { - #[derive(Encodable, Decodable, HashStable_Generic)] + #[derive(Encodable, BlobDecodable, HashStable_Generic)] pub enum PanicStrategy { Unwind = "unwind", Abort = "abort", @@ -840,7 +840,7 @@ pub enum PanicStrategy { parse_error_type = "panic strategy"; } -#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)] +#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, BlobDecodable, HashStable_Generic)] pub enum OnBrokenPipe { Default, Kill, From 40a77eb1a2f3327630a9a6b883aa1dc62f70a430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 27 Nov 2025 17:27:12 +0100 Subject: [PATCH 385/585] make cdata required --- compiler/rustc_metadata/src/rmeta/decoder.rs | 58 ++++++++------------ 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index b1cac381e05b..5bc61e431d03 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -214,12 +214,12 @@ fn get_lazy_state(&self) -> LazyState { /// Decoding of some types, like `Span` require some information to already been read. pub(super) struct MetadataDecodeContext<'a, 'tcx> { blob_decoder: BlobDecodeContext<'a>, - cdata: Option>, + cdata: CrateMetadataRef<'a>, sess: Option<&'tcx Session>, tcx: Option>, // Used for decoding interpret::AllocIds in a cached & thread-safe manner. - alloc_decoding_session: Option>, + alloc_decoding_session: AllocDecodingSession<'a>, } impl<'a, 'tcx> LazyDecoder for MetadataDecodeContext<'a, 'tcx> { @@ -257,9 +257,7 @@ pub(super) trait BlobMetadata<'a, 'tcx>: Copy { pub(super) trait Metadata<'a, 'tcx>: Copy { fn _blob(self) -> &'a MetadataBlob; - fn cdata(self) -> Option> { - None - } + fn cdata(self) -> CrateMetadataRef<'a>; fn sess(self) -> Option<&'tcx Session> { None } @@ -280,14 +278,13 @@ fn blob(self) -> &'a MetadataBlob { fn decoder(self, pos: usize) -> MetadataDecodeContext<'a, 'tcx> { let tcx = self.tcx(); + let cdata = self.cdata(); MetadataDecodeContext { blob_decoder: self.blob().decoder(pos), - cdata: self.cdata(), + cdata, sess: self.sess().or(tcx.map(|tcx| tcx.sess)), tcx, - alloc_decoding_session: self - .cdata() - .map(|cdata| cdata.cdata.alloc_decoding_state.new_decoding_session()), + alloc_decoding_session: cdata.cdata.alloc_decoding_state.new_decoding_session(), } } } @@ -321,8 +318,8 @@ fn _blob(self) -> &'a MetadataBlob { &self.cdata.blob } #[inline] - fn cdata(self) -> Option> { - Some(self) + fn cdata(self) -> CrateMetadataRef<'a> { + self } } @@ -332,8 +329,8 @@ fn _blob(self) -> &'a MetadataBlob { &self.0.cdata.blob } #[inline] - fn cdata(self) -> Option> { - Some(self.0) + fn cdata(self) -> CrateMetadataRef<'a> { + self.0 } #[inline] fn sess(self) -> Option<&'tcx Session> { @@ -347,8 +344,8 @@ fn _blob(self) -> &'a MetadataBlob { &self.0.cdata.blob } #[inline] - fn cdata(self) -> Option> { - Some(self.0) + fn cdata(self) -> CrateMetadataRef<'a> { + self.0 } #[inline] fn tcx(self) -> Option> { @@ -423,15 +420,9 @@ fn tcx(&self) -> TyCtxt<'tcx> { tcx } - #[inline] - fn cdata(&self) -> CrateMetadataRef<'a> { - debug_assert!(self.cdata.is_some(), "missing CrateMetadata in DecodeContext"); - self.cdata.unwrap() - } - #[inline] fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum { - self.cdata().map_encoded_cnum_to_current(cnum) + self.cdata.map_encoded_cnum_to_current(cnum) } } @@ -483,7 +474,7 @@ fn cached_ty_for_shorthand(&mut self, shorthand: usize, or_insert_with: F) -> { let tcx = self.tcx(); - let key = ty::CReaderCacheKey { cnum: Some(self.cdata().cnum), pos: shorthand }; + let key = ty::CReaderCacheKey { cnum: Some(self.cdata.cnum), pos: shorthand }; if let Some(&ty) = tcx.ty_rcache.borrow().get(&key) { return ty; @@ -508,11 +499,8 @@ fn with_position(&mut self, pos: usize, f: F) -> R } fn decode_alloc_id(&mut self) -> rustc_middle::mir::interpret::AllocId { - if let Some(alloc_decoding_session) = self.alloc_decoding_session { - alloc_decoding_session.decode_alloc_id(self) - } else { - bug!("Attempting to decode interpret::AllocId without CrateMetadata") - } + let ads = self.alloc_decoding_session; + ads.decode_alloc_id(self) } } @@ -539,8 +527,7 @@ fn decode_def_id(&mut self) -> DefId { } fn decode_syntax_context(&mut self) -> SyntaxContext { - let cdata = self.cdata(); - + let cdata = self.cdata; let Some(sess) = self.sess else { bug!( "Cannot decode SyntaxContext without Session.\ @@ -561,7 +548,7 @@ fn decode_syntax_context(&mut self) -> SyntaxContext { } fn decode_expn_id(&mut self) -> ExpnId { - let local_cdata = self.cdata(); + let local_cdata = self.cdata; let Some(sess) = self.sess else { bug!( @@ -712,18 +699,17 @@ fn decode(decoder: &mut MetadataDecodeContext<'a, 'tcx>) -> SpanData { // we can call `imported_source_file` for the proper crate, and binary search // through the returned slice using our span. let source_file = if tag.kind() == SpanKind::Local { - decoder.cdata().imported_source_file(metadata_index, sess) + decoder.cdata.imported_source_file(metadata_index, sess) } else { // When we encode a proc-macro crate, all `Span`s should be encoded // with `TAG_VALID_SPAN_LOCAL` - if decoder.cdata().root.is_proc_macro_crate() { + if decoder.cdata.root.is_proc_macro_crate() { // Decode `CrateNum` as u32 - using `CrateNum::decode` will ICE // since we don't have `cnum_map` populated. let cnum = u32::decode(decoder); panic!( "Decoding of crate {:?} tried to access proc-macro dep {:?}", - decoder.cdata().root.header.name, - cnum + decoder.cdata.root.header.name, cnum ); } // tag is TAG_VALID_SPAN_FOREIGN, checked by `debug_assert` above @@ -733,7 +719,7 @@ fn decode(decoder: &mut MetadataDecodeContext<'a, 'tcx>) -> SpanData { cnum ); - let foreign_data = decoder.cdata().cstore.get_crate_data(cnum); + let foreign_data = decoder.cdata.cstore.get_crate_data(cnum); foreign_data.imported_source_file(metadata_index, sess) }; From 395b508ce6213bd5deb2c7876679cea05495f2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 27 Nov 2025 17:38:44 +0100 Subject: [PATCH 386/585] remove unnecessary method --- compiler/rustc_metadata/src/rmeta/decoder.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 5bc61e431d03..ba19be36efac 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -432,11 +432,6 @@ pub(crate) fn blob(&self) -> &'a MetadataBlob { self.blob } - #[inline] - fn read_raw_bytes(&mut self, len: usize) -> &[u8] { - self.opaque.read_raw_bytes(len) - } - fn decode_symbol_or_byte_symbol( &mut self, new_from_index: impl Fn(u32) -> S, From fa5f075d1c4721eda13a4ae65ba5d3376cc164f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 28 Nov 2025 00:14:34 +0100 Subject: [PATCH 387/585] add TyCtxt everywhere replacing nothing or passed sessions --- compiler/rustc_metadata/src/creader.rs | 8 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 498 ++++++++---------- .../src/rmeta/decoder/cstore_impl.rs | 106 ++-- compiler/rustc_metadata/src/rmeta/table.rs | 8 +- .../rustc_resolve/src/build_reduced_graph.rs | 8 +- compiler/rustc_resolve/src/ident.rs | 2 +- .../rustc_resolve/src/late/diagnostics.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_resolve/src/macros.rs | 2 +- src/librustdoc/clean/inline.rs | 4 +- 10 files changed, 288 insertions(+), 352 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 95862ce01687..e0aae4c4b3a0 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -276,8 +276,9 @@ pub(crate) fn iter_crate_data(&self) -> impl Iterator impl Iterator { - self.iter_crate_data().flat_map(|(krate, data)| data.proc_macros_for_crate(krate, self)) + pub fn all_proc_macro_def_ids(&self, tcx: TyCtxt<'_>) -> impl Iterator { + self.iter_crate_data() + .flat_map(move |(krate, data)| data.proc_macros_for_crate(tcx, krate, self)) } fn push_dependencies_in_postorder(&self, deps: &mut IndexSet, cnum: CrateNum) { @@ -683,6 +684,7 @@ fn register_crate<'tcx>( }; let crate_metadata = CrateMetadata::new( + tcx, self, metadata, crate_root, @@ -778,7 +780,7 @@ fn resolve_crate<'tcx>( self.used_extern_options.insert(name); match self.maybe_resolve_crate(tcx, name, dep_kind, origin) { Ok(cnum) => { - self.set_used_recursively(cnum); + self.set_used_recursively(tcx, cnum); Some(cnum) } Err(err) => { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index ba19be36efac..df0d1b7d085f 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -29,7 +29,6 @@ use rustc_proc_macro::bridge::client::ProcMacro; use rustc_serialize::opaque::MemDecoder; use rustc_serialize::{Decodable, Decoder}; -use rustc_session::Session; use rustc_session::config::TargetModifier; use rustc_session::cstore::{CrateSource, ExternCrate}; use rustc_span::hygiene::HygieneDecodeContext; @@ -165,7 +164,6 @@ pub(super) struct BlobDecodeContext<'a> { } /// trait for anything containing `LazyState` and is a decoder. -// TODO: might need to live in rustc_middle pub(super) trait LazyDecoder: BlobDecoder { fn set_lazy_state(&mut self, state: LazyState); fn get_lazy_state(&self) -> LazyState; @@ -215,8 +213,7 @@ fn get_lazy_state(&self) -> LazyState { pub(super) struct MetadataDecodeContext<'a, 'tcx> { blob_decoder: BlobDecodeContext<'a>, cdata: CrateMetadataRef<'a>, - sess: Option<&'tcx Session>, - tcx: Option>, + tcx: TyCtxt<'tcx>, // Used for decoding interpret::AllocIds in a cached & thread-safe manner. alloc_decoding_session: AllocDecodingSession<'a>, @@ -246,50 +243,14 @@ fn deref(&self) -> &Self::Target { } } -pub(super) trait BlobMetadata<'a, 'tcx>: Copy { +pub(super) trait Metadata<'a>: Copy { type Context: BlobDecoder + LazyDecoder; fn blob(self) -> &'a MetadataBlob; fn decoder(self, pos: usize) -> Self::Context; } -/// Abstract over the various ways one can create metadata decoders. -pub(super) trait Metadata<'a, 'tcx>: Copy { - fn _blob(self) -> &'a MetadataBlob; - - fn cdata(self) -> CrateMetadataRef<'a>; - fn sess(self) -> Option<&'tcx Session> { - None - } - fn tcx(self) -> Option> { - None - } -} - -impl<'a, 'tcx, T> BlobMetadata<'a, 'tcx> for T -where - T: Metadata<'a, 'tcx>, -{ - type Context = MetadataDecodeContext<'a, 'tcx>; - - fn blob(self) -> &'a MetadataBlob { - self._blob() - } - - fn decoder(self, pos: usize) -> MetadataDecodeContext<'a, 'tcx> { - let tcx = self.tcx(); - let cdata = self.cdata(); - MetadataDecodeContext { - blob_decoder: self.blob().decoder(pos), - cdata, - sess: self.sess().or(tcx.map(|tcx| tcx.sess)), - tcx, - alloc_decoding_session: cdata.cdata.alloc_decoding_state.new_decoding_session(), - } - } -} - -impl<'a, 'tcx> BlobMetadata<'a, 'tcx> for &'a MetadataBlob { +impl<'a> Metadata<'a> for &'a MetadataBlob { type Context = BlobDecodeContext<'a>; fn blob(self) -> &'a MetadataBlob { @@ -312,50 +273,26 @@ fn decoder(self, pos: usize) -> Self::Context { } } -impl<'a, 'tcx> Metadata<'a, 'tcx> for CrateMetadataRef<'a> { - #[inline] - fn _blob(self) -> &'a MetadataBlob { - &self.cdata.blob - } - #[inline] - fn cdata(self) -> CrateMetadataRef<'a> { - self - } -} +impl<'a, 'tcx> Metadata<'a> for (CrateMetadataRef<'a>, TyCtxt<'tcx>) { + type Context = MetadataDecodeContext<'a, 'tcx>; -impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, &'tcx Session) { - #[inline] - fn _blob(self) -> &'a MetadataBlob { + fn blob(self) -> &'a MetadataBlob { &self.0.cdata.blob } - #[inline] - fn cdata(self) -> CrateMetadataRef<'a> { - self.0 - } - #[inline] - fn sess(self) -> Option<&'tcx Session> { - Some(self.1) - } -} -impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, TyCtxt<'tcx>) { - #[inline] - fn _blob(self) -> &'a MetadataBlob { - &self.0.cdata.blob - } - #[inline] - fn cdata(self) -> CrateMetadataRef<'a> { - self.0 - } - #[inline] - fn tcx(self) -> Option> { - Some(self.1) + fn decoder(self, pos: usize) -> MetadataDecodeContext<'a, 'tcx> { + MetadataDecodeContext { + blob_decoder: self.blob().decoder(pos), + cdata: self.0, + tcx: self.1, + alloc_decoding_session: self.0.cdata.alloc_decoding_state.new_decoding_session(), + } } } impl LazyValue { #[inline] - fn decode<'a, 'tcx, M: BlobMetadata<'a, 'tcx>>(self, metadata: M) -> T::Value<'tcx> + fn decode<'a, 'tcx, M: Metadata<'a>>(self, metadata: M) -> T::Value<'tcx> where T::Value<'tcx>: Decodable, { @@ -395,7 +332,7 @@ unsafe impl> TrustedLen for DecodeIterator {} impl LazyArray { #[inline] - fn decode<'a, 'tcx, M: BlobMetadata<'a, 'tcx>>( + fn decode<'a, 'tcx, M: Metadata<'a>>( self, metadata: M, ) -> DecodeIterator, M::Context> @@ -409,17 +346,6 @@ fn decode<'a, 'tcx, M: BlobMetadata<'a, 'tcx>>( } impl<'a, 'tcx> MetadataDecodeContext<'a, 'tcx> { - #[inline] - fn tcx(&self) -> TyCtxt<'tcx> { - let Some(tcx) = self.tcx else { - bug!( - "No TyCtxt found for decoding. \ - You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`." - ); - }; - tcx - } - #[inline] fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum { self.cdata.map_encoded_cnum_to_current(cnum) @@ -460,14 +386,14 @@ impl<'a, 'tcx> TyDecoder<'tcx> for MetadataDecodeContext<'a, 'tcx> { #[inline] fn interner(&self) -> TyCtxt<'tcx> { - self.tcx() + self.tcx } fn cached_ty_for_shorthand(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx> where F: FnOnce(&mut Self) -> Ty<'tcx>, { - let tcx = self.tcx(); + let tcx = self.tcx; let key = ty::CReaderCacheKey { cnum: Some(self.cdata.cnum), pos: shorthand }; @@ -508,8 +434,7 @@ fn decode(d: &mut MetadataDecodeContext<'a, 'tcx>) -> ExpnIndex { impl<'a, 'tcx> SpanDecoder for MetadataDecodeContext<'a, 'tcx> { fn decode_attr_id(&mut self) -> rustc_span::AttrId { - let sess = self.sess.expect("can't decode AttrId without Session"); - sess.psess.attr_id_generator.mk_attr_id() + self.tcx.sess.psess.attr_id_generator.mk_attr_id() } fn decode_crate_num(&mut self) -> CrateNum { @@ -523,12 +448,7 @@ fn decode_def_id(&mut self) -> DefId { fn decode_syntax_context(&mut self) -> SyntaxContext { let cdata = self.cdata; - let Some(sess) = self.sess else { - bug!( - "Cannot decode SyntaxContext without Session.\ - You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`." - ); - }; + let tcx = self.tcx; let cname = cdata.root.name(); rustc_span::hygiene::decode_syntax_context(self, &cdata.hygiene_context, |_, id| { @@ -536,22 +456,16 @@ fn decode_syntax_context(&mut self) -> SyntaxContext { cdata .root .syntax_contexts - .get(cdata, id) + .get((cdata, tcx), id) .unwrap_or_else(|| panic!("Missing SyntaxContext {id:?} for crate {cname:?}")) - .decode((cdata, sess)) + .decode((cdata, tcx)) }) } fn decode_expn_id(&mut self) -> ExpnId { let local_cdata = self.cdata; - let Some(sess) = self.sess else { - bug!( - "Cannot decode ExpnId without Session. \ - You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`." - ); - }; - + let tcx = self.tcx; let cnum = CrateNum::decode(self); let index = u32::decode(self); @@ -568,15 +482,15 @@ fn decode_expn_id(&mut self) -> ExpnId { let expn_data = crate_data .root .expn_data - .get(crate_data, index) + .get((crate_data, tcx), index) .unwrap() - .decode((crate_data, sess)); + .decode((crate_data, tcx)); let expn_hash = crate_data .root .expn_hashes - .get(crate_data, index) + .get((crate_data, tcx), index) .unwrap() - .decode((crate_data, sess)); + .decode((crate_data, tcx)); (expn_data, expn_hash) }); expn_id @@ -655,12 +569,7 @@ fn decode(decoder: &mut MetadataDecodeContext<'a, 'tcx>) -> SpanData { let len = tag.length().unwrap_or_else(|| BytePos::decode(decoder)); let hi = lo + len; - let Some(sess) = decoder.sess else { - bug!( - "Cannot decode Span without Session. \ - You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`." - ) - }; + let tcx = decoder.tcx; // Index of the file in the corresponding crate's list of encoded files. let metadata_index = u32::decode(decoder); @@ -694,7 +603,7 @@ fn decode(decoder: &mut MetadataDecodeContext<'a, 'tcx>) -> SpanData { // we can call `imported_source_file` for the proper crate, and binary search // through the returned slice using our span. let source_file = if tag.kind() == SpanKind::Local { - decoder.cdata.imported_source_file(metadata_index, sess) + decoder.cdata.imported_source_file(tcx, metadata_index) } else { // When we encode a proc-macro crate, all `Span`s should be encoded // with `TAG_VALID_SPAN_LOCAL` @@ -715,7 +624,7 @@ fn decode(decoder: &mut MetadataDecodeContext<'a, 'tcx>) -> SpanData { ); let foreign_data = decoder.cdata.cstore.get_crate_data(cnum); - foreign_data.imported_source_file(metadata_index, sess) + foreign_data.imported_source_file(tcx, metadata_index) }; // Make sure our span is well-formed. @@ -1052,7 +961,7 @@ fn missing(self, descr: &str, id: DefIndex) -> ! { bug!("missing `{descr}` for {:?}", self.local_def_id(id)) } - fn raw_proc_macro(self, id: DefIndex) -> &'a ProcMacro { + fn raw_proc_macro(self, tcx: TyCtxt<'_>, id: DefIndex) -> &'a ProcMacro { // DefIndex's in root.proc_macro_data have a one-to-one correspondence // with items in 'raw_proc_macros'. let pos = self @@ -1061,7 +970,7 @@ fn raw_proc_macro(self, id: DefIndex) -> &'a ProcMacro { .as_ref() .unwrap() .macros - .decode(self) + .decode((self, tcx)) .position(|i| i == id) .unwrap(); &self.raw_proc_macros.unwrap()[pos] @@ -1083,20 +992,20 @@ fn item_name(self, item_index: DefIndex) -> Symbol { self.opt_item_name(item_index).expect("no encoded ident for item") } - fn opt_item_ident(self, item_index: DefIndex, sess: &Session) -> Option { + fn opt_item_ident(self, tcx: TyCtxt<'_>, item_index: DefIndex) -> Option { let name = self.opt_item_name(item_index)?; let span = self .root .tables .def_ident_span - .get(self, item_index) + .get((self, tcx), item_index) .unwrap_or_else(|| self.missing("def_ident_span", item_index)) - .decode((self, sess)); + .decode((self, tcx)); Some(Ident::new(name, span)) } - fn item_ident(self, item_index: DefIndex, sess: &Session) -> Ident { - self.opt_item_ident(item_index, sess).expect("no encoded ident for item") + fn item_ident(self, tcx: TyCtxt<'_>, item_index: DefIndex) -> Ident { + self.opt_item_ident(tcx, item_index).expect("no encoded ident for item") } #[inline] @@ -1104,25 +1013,25 @@ pub(super) fn map_encoded_cnum_to_current(self, cnum: CrateNum) -> CrateNum { if cnum == LOCAL_CRATE { self.cnum } else { self.cnum_map[cnum] } } - fn def_kind(self, item_id: DefIndex) -> DefKind { + fn def_kind(self, tcx: TyCtxt<'_>, item_id: DefIndex) -> DefKind { self.root .tables .def_kind - .get(self, item_id) + .get((self, tcx), item_id) .unwrap_or_else(|| self.missing("def_kind", item_id)) } - fn get_span(self, index: DefIndex, sess: &Session) -> Span { + fn get_span(self, tcx: TyCtxt<'_>, index: DefIndex) -> Span { self.root .tables .def_span - .get(self, index) + .get((self, tcx), index) .unwrap_or_else(|| self.missing("def_span", index)) - .decode((self, sess)) + .decode((self, tcx)) } - fn load_proc_macro<'tcx>(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> SyntaxExtension { - let (name, kind, helper_attrs) = match *self.raw_proc_macro(id) { + fn load_proc_macro<'tcx>(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> SyntaxExtension { + let (name, kind, helper_attrs) = match *self.raw_proc_macro(tcx, id) { ProcMacro::CustomDerive { trait_name, attributes, client } => { let helper_attrs = attributes.iter().cloned().map(Symbol::intern).collect::>(); @@ -1141,11 +1050,11 @@ fn load_proc_macro<'tcx>(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> SyntaxExtensi }; let sess = tcx.sess; - let attrs: Vec<_> = self.get_item_attrs(id, sess).collect(); + let attrs: Vec<_> = self.get_item_attrs(tcx, id).collect(); SyntaxExtension::new( sess, kind, - self.get_span(id, sess), + self.get_span(tcx, id), helper_attrs, self.root.edition, Symbol::intern(name), @@ -1156,6 +1065,7 @@ fn load_proc_macro<'tcx>(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> SyntaxExtensi fn get_variant( self, + tcx: TyCtxt<'_>, kind: DefKind, index: DefIndex, parent_did: DefId, @@ -1167,7 +1077,8 @@ fn get_variant( _ => bug!(), }; - let data = self.root.tables.variant_data.get(self, index).unwrap().decode(self); + let data = + self.root.tables.variant_data.get((self, tcx), index).unwrap().decode((self, tcx)); let variant_did = if adt_kind == ty::AdtKind::Enum { Some(self.local_def_id(index)) } else { None }; @@ -1180,13 +1091,13 @@ fn get_variant( variant_did, ctor, data.discr, - self.get_associated_item_or_field_def_ids(index) + self.get_associated_item_or_field_def_ids(tcx, index) .map(|did| ty::FieldDef { did, name: self.item_name(did.index), - vis: self.get_visibility(did.index), - safety: self.get_safety(did.index), - value: self.get_default_field(did.index), + vis: self.get_visibility(tcx, did.index), + safety: self.get_safety(tcx, did.index), + value: self.get_default_field(tcx, did.index), }) .collect(), parent_did, @@ -1196,8 +1107,8 @@ fn get_variant( ) } - fn get_adt_def<'tcx>(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<'tcx> { - let kind = self.def_kind(item_id); + fn get_adt_def<'tcx>(self, tcx: TyCtxt<'tcx>, item_id: DefIndex) -> ty::AdtDef<'tcx> { + let kind = self.def_kind(tcx, item_id); let did = self.local_def_id(item_id); let adt_kind = match kind { @@ -1206,25 +1117,26 @@ fn get_adt_def<'tcx>(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<' DefKind::Union => ty::AdtKind::Union, _ => bug!("get_adt_def called on a non-ADT {:?}", did), }; - let repr = self.root.tables.repr_options.get(self, item_id).unwrap().decode(self); + let repr = + self.root.tables.repr_options.get((self, tcx), item_id).unwrap().decode((self, tcx)); let mut variants: Vec<_> = if let ty::AdtKind::Enum = adt_kind { self.root .tables .module_children_non_reexports - .get(self, item_id) + .get((self, tcx), item_id) .expect("variants are not encoded for an enum") - .decode(self) + .decode((self, tcx)) .filter_map(|index| { - let kind = self.def_kind(index); + let kind = self.def_kind(tcx, index); match kind { DefKind::Ctor(..) => None, - _ => Some(self.get_variant(kind, index, did)), + _ => Some(self.get_variant(tcx, kind, index, did)), } }) .collect() } else { - std::iter::once(self.get_variant(kind, item_id, did)).collect() + std::iter::once(self.get_variant(tcx, kind, item_id, did)).collect() }; variants.sort_by_key(|(idx, _)| *idx); @@ -1237,44 +1149,44 @@ fn get_adt_def<'tcx>(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<' ) } - fn get_visibility(self, id: DefIndex) -> Visibility { + fn get_visibility(self, tcx: TyCtxt<'_>, id: DefIndex) -> Visibility { self.root .tables .visibility - .get(self, id) + .get((self, tcx), id) .unwrap_or_else(|| self.missing("visibility", id)) - .decode(self) + .decode((self, tcx)) .map_id(|index| self.local_def_id(index)) } - fn get_safety(self, id: DefIndex) -> Safety { - self.root.tables.safety.get(self, id) + fn get_safety(self, tcx: TyCtxt<'_>, id: DefIndex) -> Safety { + self.root.tables.safety.get((self, tcx), id) } - fn get_default_field(self, id: DefIndex) -> Option { - self.root.tables.default_fields.get(self, id).map(|d| d.decode(self)) + fn get_default_field(self, tcx: TyCtxt<'_>, id: DefIndex) -> Option { + self.root.tables.default_fields.get((self, tcx), id).map(|d| d.decode((self, tcx))) } - fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId { + fn get_expn_that_defined(self, tcx: TyCtxt<'_>, id: DefIndex) -> ExpnId { self.root .tables .expn_that_defined - .get(self, id) + .get((self, tcx), id) .unwrap_or_else(|| self.missing("expn_that_defined", id)) - .decode((self, sess)) + .decode((self, tcx)) } - fn get_debugger_visualizers(self) -> Vec { - self.root.debugger_visualizers.decode(self).collect::>() + fn get_debugger_visualizers(self, tcx: TyCtxt<'_>) -> Vec { + self.root.debugger_visualizers.decode((self, tcx)).collect::>() } /// Iterates over all the stability attributes in the given crate. - fn get_lib_features(self) -> LibFeatures { + fn get_lib_features(self, tcx: TyCtxt<'_>) -> LibFeatures { LibFeatures { stability: self .root .lib_features - .decode(self) + .decode((self, tcx)) .map(|(sym, stab)| (sym, (stab, DUMMY_SP))) .collect(), } @@ -1284,7 +1196,7 @@ fn get_lib_features(self) -> LibFeatures { /// has an `implied_by` meta item, then the mapping from the implied feature to the actual /// feature is a stability implication). fn get_stability_implications<'tcx>(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Symbol)] { - tcx.arena.alloc_from_iter(self.root.stability_implications.decode(self)) + tcx.arena.alloc_from_iter(self.root.stability_implications.decode((self, tcx))) } /// Iterates over the lang items in the given crate. @@ -1292,15 +1204,15 @@ fn get_lang_items<'tcx>(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, LangItem)] { tcx.arena.alloc_from_iter( self.root .lang_items - .decode(self) + .decode((self, tcx)) .map(move |(def_index, index)| (self.local_def_id(def_index), index)), ) } fn get_stripped_cfg_items<'tcx>( self, - cnum: CrateNum, tcx: TyCtxt<'tcx>, + cnum: CrateNum, ) -> &'tcx [StrippedCfgItem] { let item_names = self .root @@ -1311,12 +1223,12 @@ fn get_stripped_cfg_items<'tcx>( } /// Iterates over the diagnostic items in the given crate. - fn get_diagnostic_items(self) -> DiagnosticItems { + fn get_diagnostic_items(self, tcx: TyCtxt<'_>) -> DiagnosticItems { let mut id_to_name = DefIdMap::default(); let name_to_id = self .root .diagnostic_items - .decode(self) + .decode((self, tcx)) .map(|(name, def_index)| { let id = self.local_def_id(def_index); id_to_name.insert(id, name); @@ -1326,10 +1238,10 @@ fn get_diagnostic_items(self) -> DiagnosticItems { DiagnosticItems { id_to_name, name_to_id } } - fn get_mod_child(self, id: DefIndex, sess: &Session) -> ModChild { - let ident = self.item_ident(id, sess); - let res = Res::Def(self.def_kind(id), self.local_def_id(id)); - let vis = self.get_visibility(id); + fn get_mod_child(self, tcx: TyCtxt<'_>, id: DefIndex) -> ModChild { + let ident = self.item_ident(tcx, id); + let res = Res::Def(self.def_kind(tcx, id), self.local_def_id(id)); + let vis = self.get_visibility(tcx, id); ModChild { ident, res, vis, reexport_chain: Default::default() } } @@ -1338,30 +1250,27 @@ fn get_mod_child(self, id: DefIndex, sess: &Session) -> ModChild { /// including both proper items and reexports. /// Module here is understood in name resolution sense - it can be a `mod` item, /// or a crate root, or an enum, or a trait. - fn get_module_children( - self, - id: DefIndex, - sess: &'a Session, - ) -> impl Iterator { + fn get_module_children(self, tcx: TyCtxt<'_>, id: DefIndex) -> impl Iterator { gen move { if let Some(data) = &self.root.proc_macro_data { // If we are loading as a proc macro, we want to return // the view of this crate as a proc macro crate. if id == CRATE_DEF_INDEX { - for child_index in data.macros.decode(self) { - yield self.get_mod_child(child_index, sess); + for child_index in data.macros.decode((self, tcx)) { + yield self.get_mod_child(tcx, child_index); } } } else { // Iterate over all children. - let non_reexports = self.root.tables.module_children_non_reexports.get(self, id); - for child_index in non_reexports.unwrap().decode(self) { - yield self.get_mod_child(child_index, sess); + let non_reexports = + self.root.tables.module_children_non_reexports.get((self, tcx), id); + for child_index in non_reexports.unwrap().decode((self, tcx)) { + yield self.get_mod_child(tcx, child_index); } - let reexports = self.root.tables.module_children_reexports.get(self, id); + let reexports = self.root.tables.module_children_reexports.get((self, tcx), id); if !reexports.is_default() { - for reexport in reexports.decode((self, sess)) { + for reexport in reexports.decode((self, tcx)) { yield reexport; } } @@ -1369,46 +1278,51 @@ fn get_module_children( } } - fn is_ctfe_mir_available(self, id: DefIndex) -> bool { - self.root.tables.mir_for_ctfe.get(self, id).is_some() + fn is_ctfe_mir_available(self, tcx: TyCtxt<'_>, id: DefIndex) -> bool { + self.root.tables.mir_for_ctfe.get((self, tcx), id).is_some() } - fn is_item_mir_available(self, id: DefIndex) -> bool { - self.root.tables.optimized_mir.get(self, id).is_some() + fn is_item_mir_available(self, tcx: TyCtxt<'_>, id: DefIndex) -> bool { + self.root.tables.optimized_mir.get((self, tcx), id).is_some() } - fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool { + fn get_fn_has_self_parameter(self, tcx: TyCtxt<'_>, id: DefIndex) -> bool { self.root .tables .fn_arg_idents - .get(self, id) + .get((self, tcx), id) .expect("argument names not encoded for a function") - .decode((self, sess)) + .decode((self, tcx)) .nth(0) .is_some_and(|ident| matches!(ident, Some(Ident { name: kw::SelfLower, .. }))) } - fn get_associated_item_or_field_def_ids(self, id: DefIndex) -> impl Iterator { + fn get_associated_item_or_field_def_ids( + self, + tcx: TyCtxt<'_>, + id: DefIndex, + ) -> impl Iterator { self.root .tables .associated_item_or_field_def_ids - .get(self, id) + .get((self, tcx), id) .unwrap_or_else(|| self.missing("associated_item_or_field_def_ids", id)) - .decode(self) + .decode((self, tcx)) .map(move |child_index| self.local_def_id(child_index)) } - fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem { - let kind = match self.def_kind(id) { + fn get_associated_item(self, tcx: TyCtxt<'_>, id: DefIndex) -> ty::AssocItem { + let kind = match self.def_kind(tcx, id) { DefKind::AssocConst => ty::AssocKind::Const { name: self.item_name(id) }, DefKind::AssocFn => ty::AssocKind::Fn { name: self.item_name(id), - has_self: self.get_fn_has_self_parameter(id, sess), + has_self: self.get_fn_has_self_parameter(tcx, id), }, DefKind::AssocTy => { - let data = if let Some(rpitit_info) = self.root.tables.opt_rpitit_info.get(self, id) + let data = if let Some(rpitit_info) = + self.root.tables.opt_rpitit_info.get((self, tcx), id) { - ty::AssocTypeData::Rpitit(rpitit_info.decode(self)) + ty::AssocTypeData::Rpitit(rpitit_info.decode((self, tcx))) } else { ty::AssocTypeData::Normal(self.item_name(id)) }; @@ -1416,30 +1330,33 @@ fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem { } _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), }; - let container = self.root.tables.assoc_container.get(self, id).unwrap().decode(self); + let container = + self.root.tables.assoc_container.get((self, tcx), id).unwrap().decode((self, tcx)); ty::AssocItem { kind, def_id: self.local_def_id(id), container } } - fn get_ctor(self, node_id: DefIndex) -> Option<(CtorKind, DefId)> { - match self.def_kind(node_id) { + fn get_ctor(self, tcx: TyCtxt<'_>, node_id: DefIndex) -> Option<(CtorKind, DefId)> { + match self.def_kind(tcx, node_id) { DefKind::Struct | DefKind::Variant => { - let vdata = self.root.tables.variant_data.get(self, node_id).unwrap().decode(self); + let vdata = self + .root + .tables + .variant_data + .get((self, tcx), node_id) + .unwrap() + .decode((self, tcx)); vdata.ctor.map(|(kind, index)| (kind, self.local_def_id(index))) } _ => None, } } - fn get_item_attrs( - self, - id: DefIndex, - sess: &'a Session, - ) -> impl Iterator { + fn get_item_attrs(self, tcx: TyCtxt<'_>, id: DefIndex) -> impl Iterator { self.root .tables .attributes - .get(self, id) + .get((self, tcx), id) .unwrap_or_else(|| { // Structure and variant constructors don't have any attributes encoded for them, // but we assume that someone passing a constructor ID actually wants to look at @@ -1450,10 +1367,10 @@ fn get_item_attrs( self.root .tables .attributes - .get(self, parent_id) + .get((self, tcx), parent_id) .expect("no encoded attributes for a structure or variant") }) - .decode((self, sess)) + .decode((self, tcx)) } fn get_inherent_implementations_for_type<'tcx>( @@ -1465,27 +1382,27 @@ fn get_inherent_implementations_for_type<'tcx>( self.root .tables .inherent_impls - .get(self, id) - .decode(self) + .get((self, tcx), id) + .decode((self, tcx)) .map(|index| self.local_def_id(index)), ) } /// Decodes all traits in the crate (for rustdoc and rustc diagnostics). - fn get_traits(self) -> impl Iterator { - self.root.traits.decode(self).map(move |index| self.local_def_id(index)) + fn get_traits(self, tcx: TyCtxt<'_>) -> impl Iterator { + self.root.traits.decode((self, tcx)).map(move |index| self.local_def_id(index)) } /// Decodes all trait impls in the crate (for rustdoc). - fn get_trait_impls(self) -> impl Iterator { + fn get_trait_impls(self, tcx: TyCtxt<'_>) -> impl Iterator { self.cdata.trait_impls.values().flat_map(move |impls| { - impls.decode(self).map(move |(impl_index, _)| self.local_def_id(impl_index)) + impls.decode((self, tcx)).map(move |(impl_index, _)| self.local_def_id(impl_index)) }) } fn get_incoherent_impls<'tcx>(self, tcx: TyCtxt<'tcx>, simp: SimplifiedType) -> &'tcx [DefId] { if let Some(impls) = self.cdata.incoherent_impls.get(&simp) { - tcx.arena.alloc_from_iter(impls.decode(self).map(|idx| self.local_def_id(idx))) + tcx.arena.alloc_from_iter(impls.decode((self, tcx)).map(|idx| self.local_def_id(idx))) } else { &[] } @@ -1510,7 +1427,7 @@ fn get_implementations_of_trait<'tcx>( if let Some(impls) = self.trait_impls.get(&key) { tcx.arena.alloc_from_iter( impls - .decode(self) + .decode((self, tcx)) .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)), ) } else { @@ -1518,21 +1435,21 @@ fn get_implementations_of_trait<'tcx>( } } - fn get_native_libraries(self, sess: &'a Session) -> impl Iterator { - self.root.native_libraries.decode((self, sess)) + fn get_native_libraries(self, tcx: TyCtxt<'_>) -> impl Iterator { + self.root.native_libraries.decode((self, tcx)) } - fn get_proc_macro_quoted_span(self, index: usize, sess: &Session) -> Span { + fn get_proc_macro_quoted_span(self, tcx: TyCtxt<'_>, index: usize) -> Span { self.root .tables .proc_macro_quoted_spans - .get(self, index) + .get((self, tcx), index) .unwrap_or_else(|| panic!("Missing proc macro quoted span: {index:?}")) - .decode((self, sess)) + .decode((self, tcx)) } - fn get_foreign_modules(self, sess: &'a Session) -> impl Iterator { - self.root.foreign_modules.decode((self, sess)) + fn get_foreign_modules(self, tcx: TyCtxt<'_>) -> impl Iterator { + self.root.foreign_modules.decode((self, tcx)) } fn get_dylib_dependency_formats<'tcx>( @@ -1540,25 +1457,30 @@ fn get_dylib_dependency_formats<'tcx>( tcx: TyCtxt<'tcx>, ) -> &'tcx [(CrateNum, LinkagePreference)] { tcx.arena.alloc_from_iter( - self.root.dylib_dependency_formats.decode(self).enumerate().flat_map(|(i, link)| { - let cnum = CrateNum::new(i + 1); // We skipped LOCAL_CRATE when encoding - link.map(|link| (self.cnum_map[cnum], link)) - }), + self.root.dylib_dependency_formats.decode((self, tcx)).enumerate().flat_map( + |(i, link)| { + let cnum = CrateNum::new(i + 1); // We skipped LOCAL_CRATE when encoding + link.map(|link| (self.cnum_map[cnum], link)) + }, + ), ) } fn get_missing_lang_items<'tcx>(self, tcx: TyCtxt<'tcx>) -> &'tcx [LangItem] { - tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode(self)) + tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode((self, tcx))) } - fn get_exportable_items(self) -> impl Iterator { - self.root.exportable_items.decode(self).map(move |index| self.local_def_id(index)) + fn get_exportable_items(self, tcx: TyCtxt<'_>) -> impl Iterator { + self.root.exportable_items.decode((self, tcx)).map(move |index| self.local_def_id(index)) } - fn get_stable_order_of_exportable_impls(self) -> impl Iterator { + fn get_stable_order_of_exportable_impls( + self, + tcx: TyCtxt<'_>, + ) -> impl Iterator { self.root .stable_order_of_exportable_impls - .decode(self) + .decode((self, tcx)) .map(move |v| (self.local_def_id(v.0), v.1)) } @@ -1576,12 +1498,17 @@ fn exported_generic_symbols<'tcx>( tcx.arena.alloc_from_iter(self.root.exported_generic_symbols.decode((self, tcx))) } - fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef { - match self.def_kind(id) { + fn get_macro(self, tcx: TyCtxt<'_>, id: DefIndex) -> ast::MacroDef { + match self.def_kind(tcx, id) { DefKind::Macro(_) => { - let macro_rules = self.root.tables.is_macro_rules.get(self, id); - let body = - self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess)); + let macro_rules = self.root.tables.is_macro_rules.get((self, tcx), id); + let body = self + .root + .tables + .macro_definition + .get((self, tcx), id) + .unwrap() + .decode((self, tcx)); ast::MacroDef { macro_rules, body: Box::new(body) } } _ => bug!(), @@ -1590,11 +1517,9 @@ fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef { #[inline] fn def_key(self, index: DefIndex) -> DefKey { - *self - .def_key_cache - .lock() - .entry(index) - .or_insert_with(|| self.root.tables.def_keys.get(self, index).unwrap().decode(self)) + *self.def_key_cache.lock().entry(index).or_insert_with(|| { + self.root.tables.def_keys.get(&self.blob, index).unwrap().decode(&self.blob) + }) } // Returns the path leading to the thing with this `id`. @@ -1610,7 +1535,7 @@ fn def_path_hash(self, index: DefIndex) -> DefPathHash { // relax the Default restriction will likely fix this. let fingerprint = Fingerprint::new( self.root.stable_crate_id.as_u64(), - self.root.tables.def_path_hashes.get(self, index), + self.root.tables.def_path_hashes.get(&self.blob, index), ); DefPathHash::new(self.root.stable_crate_id, fingerprint.split().1) } @@ -1620,9 +1545,13 @@ fn def_path_hash_to_def_index(self, hash: DefPathHash) -> Option { self.def_path_hash_map.def_path_hash_to_def_index(&hash) } - fn expn_hash_to_expn_id(self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId { + fn expn_hash_to_expn_id(self, tcx: TyCtxt<'_>, index_guess: u32, hash: ExpnHash) -> ExpnId { let index_guess = ExpnIndex::from_u32(index_guess); - let old_hash = self.root.expn_hashes.get(self, index_guess).map(|lazy| lazy.decode(self)); + let old_hash = self + .root + .expn_hashes + .get((self, tcx), index_guess) + .map(|lazy| lazy.decode((self, tcx))); let index = if old_hash == Some(hash) { // Fast path: the expn and its index is unchanged from the @@ -1639,8 +1568,8 @@ fn expn_hash_to_expn_id(self, sess: &Session, index_guess: u32, hash: ExpnHash) UnhashMap::with_capacity_and_hasher(end_id as usize, Default::default()); for i in 0..end_id { let i = ExpnIndex::from_u32(i); - if let Some(hash) = self.root.expn_hashes.get(self, i) { - map.insert(hash.decode(self), i); + if let Some(hash) = self.root.expn_hashes.get((self, tcx), i) { + map.insert(hash.decode((self, tcx)), i); } } map @@ -1648,7 +1577,7 @@ fn expn_hash_to_expn_id(self, sess: &Session, index_guess: u32, hash: ExpnHash) map[&hash] }; - let data = self.root.expn_data.get(self, index).unwrap().decode((self, sess)); + let data = self.root.expn_data.get((self, tcx), index).unwrap().decode((self, tcx)); rustc_span::hygiene::register_expn_id(self.cnum, index, data, hash) } @@ -1677,9 +1606,9 @@ fn expn_hash_to_expn_id(self, sess: &Session, index_guess: u32, hash: ExpnHash) /// /// Proc macro crates don't currently export spans, so this function does not have /// to work for them. - fn imported_source_file(self, source_file_index: u32, sess: &Session) -> ImportedSourceFile { + fn imported_source_file(self, tcx: TyCtxt<'_>, source_file_index: u32) -> ImportedSourceFile { fn filter<'a>( - sess: &Session, + tcx: TyCtxt<'_>, real_source_base_dir: &Option, path: Option<&'a Path>, ) -> Option<&'a Path> { @@ -1687,13 +1616,13 @@ fn filter<'a>( // Only spend time on further checks if we have what to translate *to*. real_source_base_dir.is_some() // Some tests need the translation to be always skipped. - && sess.opts.unstable_opts.translate_remapped_path_to_local_path + && tcx.sess.opts.unstable_opts.translate_remapped_path_to_local_path }) .filter(|virtual_dir| { // Don't translate away `/rustc/$hash` if we're still remapping to it, // since that means we're still building `std`/`rustc` that need it, // and we don't want the real path to leak into codegen/debuginfo. - !sess.opts.remap_path_prefix.iter().any(|(_from, to)| to == virtual_dir) + !tcx.sess.opts.remap_path_prefix.iter().any(|(_from, to)| to == virtual_dir) }) } @@ -1702,11 +1631,11 @@ fn filter<'a>( real_source_base_dir: &Option, name: &mut rustc_span::FileName| { let virtual_source_base_dir = [ - filter(sess, real_source_base_dir, virtual_source_base_dir.map(Path::new)), + filter(tcx, real_source_base_dir, virtual_source_base_dir.map(Path::new)), filter( - sess, + tcx, real_source_base_dir, - sess.opts.unstable_opts.simulate_remapped_rust_src_base.as_deref(), + tcx.sess.opts.unstable_opts.simulate_remapped_rust_src_base.as_deref(), ), ]; @@ -1737,7 +1666,7 @@ fn filter<'a>( // https://rust-lang.github.io/rfcs/3127-trim-paths.html#handling-sysroot-paths. // Other imported paths are not currently remapped (see #66251). let (user_remapped, applied) = - sess.source_map().path_mapping().map_prefix(&new_path); + tcx.sess.source_map().path_mapping().map_prefix(&new_path); let new_name = if applied { rustc_span::RealFileName::Remapped { local_path: Some(new_path.clone()), @@ -1756,7 +1685,8 @@ fn filter<'a>( real_source_base_dir: &Option, subdir: &str, name: &mut rustc_span::FileName| { - if let Some(virtual_dir) = &sess.opts.unstable_opts.simulate_remapped_rust_src_base + if let Some(virtual_dir) = + &tcx.sess.opts.unstable_opts.simulate_remapped_rust_src_base && let Some(real_dir) = real_source_base_dir && let rustc_span::FileName::Real(old_name) = name { @@ -1793,9 +1723,9 @@ fn filter<'a>( let source_file_to_import = self .root .source_map - .get(self, source_file_index) + .get((self, tcx), source_file_index) .expect("missing source file") - .decode(self); + .decode((self, tcx)); // We can't reuse an existing SourceFile, so allocate a new one // containing the information we need. @@ -1823,7 +1753,7 @@ fn filter<'a>( // compiler is bootstrapped. try_to_translate_real_to_virtual( option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR"), - &sess.opts.real_rust_source_base_dir, + &tcx.sess.opts.real_rust_source_base_dir, "library", &mut name, ); @@ -1834,7 +1764,7 @@ fn filter<'a>( // with `remap-debuginfo = true`. try_to_translate_real_to_virtual( option_env!("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR"), - &sess.opts.real_rustc_dev_source_base_dir, + &tcx.sess.opts.real_rustc_dev_source_base_dir, "compiler", &mut name, ); @@ -1846,7 +1776,7 @@ fn filter<'a>( // the `rust-src` component in `Src::run` in `src/bootstrap/dist.rs`. try_to_translate_virtual_to_real( option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR"), - &sess.opts.real_rust_source_base_dir, + &tcx.sess.opts.real_rust_source_base_dir, &mut name, ); @@ -1857,11 +1787,11 @@ fn filter<'a>( // the `rustc-dev` component in `Src::run` in `src/bootstrap/dist.rs`. try_to_translate_virtual_to_real( option_env!("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR"), - &sess.opts.real_rustc_dev_source_base_dir, + &tcx.sess.opts.real_rustc_dev_source_base_dir, &mut name, ); - let local_version = sess.source_map().new_imported_source_file( + let local_version = tcx.sess.source_map().new_imported_source_file( name, src_hash, checksum_hash, @@ -1894,35 +1824,40 @@ fn filter<'a>( .clone() } - fn get_attr_flags(self, index: DefIndex) -> AttrFlags { - self.root.tables.attr_flags.get(self, index) + fn get_attr_flags(self, tcx: TyCtxt<'_>, index: DefIndex) -> AttrFlags { + self.root.tables.attr_flags.get((self, tcx), index) } - fn get_intrinsic(self, index: DefIndex) -> Option { - self.root.tables.intrinsic.get(self, index).map(|d| d.decode(self)) + fn get_intrinsic(self, tcx: TyCtxt<'_>, index: DefIndex) -> Option { + self.root.tables.intrinsic.get((self, tcx), index).map(|d| d.decode((self, tcx))) } - fn get_doc_link_resolutions(self, index: DefIndex) -> DocLinkResMap { + fn get_doc_link_resolutions(self, tcx: TyCtxt<'_>, index: DefIndex) -> DocLinkResMap { self.root .tables .doc_link_resolutions - .get(self, index) + .get((self, tcx), index) .expect("no resolutions for a doc link") - .decode(self) + .decode((self, tcx)) } - fn get_doc_link_traits_in_scope(self, index: DefIndex) -> impl Iterator { + fn get_doc_link_traits_in_scope( + self, + tcx: TyCtxt<'_>, + index: DefIndex, + ) -> impl Iterator { self.root .tables .doc_link_traits_in_scope - .get(self, index) + .get((self, tcx), index) .expect("no traits in scope for a doc link") - .decode(self) + .decode((self, tcx)) } } impl CrateMetadata { pub(crate) fn new( + tcx: TyCtxt<'_>, cstore: &CStore, blob: MetadataBlob, root: CrateRoot, @@ -1975,8 +1910,10 @@ pub(crate) fn new( cdata.incoherent_impls = cdata .root .incoherent_impls - .decode(cref) - .map(|incoherent_impls| (incoherent_impls.self_ty.decode(cref), incoherent_impls.impls)) + .decode((cref, tcx)) + .map(|incoherent_impls| { + (incoherent_impls.self_ty.decode((cref, tcx)), incoherent_impls.impls) + }) .collect(); cdata @@ -2069,13 +2006,14 @@ pub(crate) fn is_proc_macro_crate(&self) -> bool { pub(crate) fn proc_macros_for_crate( &self, + tcx: TyCtxt<'_>, krate: CrateNum, cstore: &CStore, ) -> impl Iterator { gen move { for def_id in self.root.proc_macro_data.as_ref().into_iter().flat_map(move |data| { data.macros - .decode(CrateMetadataRef { cdata: self, cstore }) + .decode((CrateMetadataRef { cdata: self, cstore }, tcx)) .map(move |index| DefId { index, krate }) }) { yield def_id; diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 24cfdc05e5cb..ac4faae5a87a 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -16,8 +16,8 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::util::Providers; use rustc_serialize::Decoder; +use rustc_session::StableCrateId; use rustc_session::cstore::{CrateStore, ExternCrate}; -use rustc_session::{Session, StableCrateId}; use rustc_span::hygiene::ExpnId; use rustc_span::{Span, Symbol, kw}; @@ -99,7 +99,7 @@ macro_rules! provide_one { .root .tables .$name - .get($cdata, $def_id.index) + .get(($cdata, $tcx), $def_id.index) .map(|lazy| lazy.decode(($cdata, $tcx))) .process_decoded($tcx, || panic!("{:?} does not have a {:?}", $def_id, stringify!($name))) } @@ -108,7 +108,7 @@ macro_rules! provide_one { ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_defaulted_array }) => { provide_one! { $tcx, $def_id, $other, $cdata, $name => { - let lazy = $cdata.root.tables.$name.get($cdata, $def_id.index); + let lazy = $cdata.root.tables.$name.get(($cdata, $tcx), $def_id.index); let value = if lazy.is_default() { &[] as &[_] } else { @@ -126,7 +126,7 @@ macro_rules! provide_one { .root .tables .$name - .get($cdata, $def_id.index) + .get(($cdata, $tcx), $def_id.index) .process_decoded($tcx, || panic!("{:?} does not have a {:?}", $def_id, stringify!($name))) } } @@ -252,7 +252,7 @@ fn into_args(self) -> (DefId, SimplifiedType) { lookup_default_body_stability => { table } lookup_deprecation_entry => { table } params_in_repr => { table } - def_kind => { cdata.def_kind(def_id.index) } + def_kind => { cdata.def_kind(tcx, def_id.index) } impl_parent => { table } defaultness => { table_direct } constness => { table_direct } @@ -263,7 +263,7 @@ fn into_args(self) -> (DefId, SimplifiedType) { .root .tables .coerce_unsized_info - .get(cdata, def_id.index) + .get((cdata, tcx), def_id.index) .map(|lazy| lazy.decode((cdata, tcx))) .process_decoded(tcx, || panic!("{def_id:?} does not have coerce_unsized_info"))) } mir_const_qualif => { table } @@ -279,7 +279,7 @@ fn into_args(self) -> (DefId, SimplifiedType) { .root .tables .eval_static_initializer - .get(cdata, def_id.index) + .get((cdata, tcx), def_id.index) .map(|lazy| lazy.decode((cdata, tcx))) .unwrap_or_else(|| panic!("{def_id:?} does not have eval_static_initializer"))) } @@ -292,7 +292,7 @@ fn into_args(self) -> (DefId, SimplifiedType) { .root .tables .deduced_param_attrs - .get(cdata, def_id.index) + .get((cdata, tcx), def_id.index) .map(|lazy| { &*tcx.arena.alloc_from_iter(lazy.decode((cdata, tcx))) }) @@ -305,25 +305,25 @@ fn into_args(self) -> (DefId, SimplifiedType) { .root .tables .trait_impl_trait_tys - .get(cdata, def_id.index) + .get((cdata, tcx), def_id.index) .map(|lazy| lazy.decode((cdata, tcx))) .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys"))) } associated_types_for_impl_traits_in_trait_or_impl => { table } - visibility => { cdata.get_visibility(def_id.index) } - adt_def => { cdata.get_adt_def(def_id.index, tcx) } + visibility => { cdata.get_visibility(tcx, def_id.index) } + adt_def => { cdata.get_adt_def(tcx, def_id.index) } adt_destructor => { table } adt_async_destructor => { table } associated_item_def_ids => { - tcx.arena.alloc_from_iter(cdata.get_associated_item_or_field_def_ids(def_id.index)) + tcx.arena.alloc_from_iter(cdata.get_associated_item_or_field_def_ids(tcx, def_id.index)) } - associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) } + associated_item => { cdata.get_associated_item(tcx, def_id.index) } inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } - attrs_for_def => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) } - is_mir_available => { cdata.is_item_mir_available(def_id.index) } - is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) } + attrs_for_def => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(tcx, def_id.index)) } + is_mir_available => { cdata.is_item_mir_available(tcx, def_id.index) } + is_ctfe_mir_available => { cdata.is_ctfe_mir_available(tcx, def_id.index) } cross_crate_inlinable => { table_direct } dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) } @@ -355,8 +355,8 @@ fn into_args(self) -> (DefId, SimplifiedType) { reachable_non_generics } - native_libraries => { cdata.get_native_libraries(tcx.sess).collect() } - foreign_modules => { cdata.get_foreign_modules(tcx.sess).map(|m| (m.def_id, m)).collect() } + native_libraries => { cdata.get_native_libraries(tcx).collect() } + foreign_modules => { cdata.get_foreign_modules(tcx).map(|m| (m.def_id, m)).collect() } crate_hash => { cdata.root.header.hash } crate_host_hash => { cdata.host_hash } crate_name => { cdata.root.header.name } @@ -364,23 +364,23 @@ fn into_args(self) -> (DefId, SimplifiedType) { extra_filename => { cdata.root.extra_filename.clone() } - traits => { tcx.arena.alloc_from_iter(cdata.get_traits()) } - trait_impls_in_crate => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) } + traits => { tcx.arena.alloc_from_iter(cdata.get_traits(tcx)) } + trait_impls_in_crate => { tcx.arena.alloc_from_iter(cdata.get_trait_impls(tcx)) } implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) } crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) } dep_kind => { cdata.dep_kind } module_children => { - tcx.arena.alloc_from_iter(cdata.get_module_children(def_id.index, tcx.sess)) + tcx.arena.alloc_from_iter(cdata.get_module_children(tcx, def_id.index)) } - lib_features => { cdata.get_lib_features() } + lib_features => { cdata.get_lib_features(tcx) } stability_implications => { cdata.get_stability_implications(tcx).iter().copied().collect() } - stripped_cfg_items => { cdata.get_stripped_cfg_items(cdata.cnum, tcx) } - intrinsic_raw => { cdata.get_intrinsic(def_id.index) } + stripped_cfg_items => { cdata.get_stripped_cfg_items(tcx, cdata.cnum) } + intrinsic_raw => { cdata.get_intrinsic(tcx, def_id.index) } defined_lang_items => { cdata.get_lang_items(tcx) } - diagnostic_items => { cdata.get_diagnostic_items() } + diagnostic_items => { cdata.get_diagnostic_items(tcx) } missing_lang_items => { cdata.get_missing_lang_items(tcx) } missing_extern_crate_item => { @@ -388,20 +388,20 @@ fn into_args(self) -> (DefId, SimplifiedType) { } used_crate_source => { Arc::clone(&cdata.source) } - debugger_visualizers => { cdata.get_debugger_visualizers() } + debugger_visualizers => { cdata.get_debugger_visualizers(tcx) } - exportable_items => { tcx.arena.alloc_from_iter(cdata.get_exportable_items()) } - stable_order_of_exportable_impls => { tcx.arena.alloc(cdata.get_stable_order_of_exportable_impls().collect()) } + exportable_items => { tcx.arena.alloc_from_iter(cdata.get_exportable_items(tcx)) } + stable_order_of_exportable_impls => { tcx.arena.alloc(cdata.get_stable_order_of_exportable_impls(tcx).collect()) } exported_non_generic_symbols => { cdata.exported_non_generic_symbols(tcx) } exported_generic_symbols => { cdata.exported_generic_symbols(tcx) } crate_extern_paths => { cdata.source().paths().cloned().collect() } - expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) } - default_field => { cdata.get_default_field(def_id.index) } - is_doc_hidden => { cdata.get_attr_flags(def_id.index).contains(AttrFlags::IS_DOC_HIDDEN) } - doc_link_resolutions => { tcx.arena.alloc(cdata.get_doc_link_resolutions(def_id.index)) } + expn_that_defined => { cdata.get_expn_that_defined(tcx, def_id.index) } + default_field => { cdata.get_default_field(tcx, def_id.index) } + is_doc_hidden => { cdata.get_attr_flags(tcx,def_id.index).contains(AttrFlags::IS_DOC_HIDDEN) } + doc_link_resolutions => { tcx.arena.alloc(cdata.get_doc_link_resolutions(tcx, def_id.index)) } doc_link_traits_in_scope => { - tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index)) + tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(tcx, def_id.index)) } anon_const_kind => { table } const_of_item => { table } @@ -551,38 +551,38 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { } impl CStore { - pub fn ctor_untracked(&self, def: DefId) -> Option<(CtorKind, DefId)> { - self.get_crate_data(def.krate).get_ctor(def.index) + pub fn ctor_untracked(&self, tcx: TyCtxt<'_>, def: DefId) -> Option<(CtorKind, DefId)> { + self.get_crate_data(def.krate).get_ctor(tcx, def.index) } - pub fn load_macro_untracked(&self, id: DefId, tcx: TyCtxt<'_>) -> LoadedMacro { + pub fn load_macro_untracked(&self, tcx: TyCtxt<'_>, id: DefId) -> LoadedMacro { let sess = tcx.sess; let _prof_timer = sess.prof.generic_activity("metadata_load_macro"); let data = self.get_crate_data(id.krate); if data.root.is_proc_macro_crate() { - LoadedMacro::ProcMacro(data.load_proc_macro(id.index, tcx)) + LoadedMacro::ProcMacro(data.load_proc_macro(tcx, id.index)) } else { LoadedMacro::MacroDef { - def: data.get_macro(id.index, sess), - ident: data.item_ident(id.index, sess), - attrs: data.get_item_attrs(id.index, sess).collect(), - span: data.get_span(id.index, sess), + def: data.get_macro(tcx, id.index), + ident: data.item_ident(tcx, id.index), + attrs: data.get_item_attrs(tcx, id.index).collect(), + span: data.get_span(tcx, id.index), edition: data.root.edition, } } } - pub fn def_span_untracked(&self, def_id: DefId, sess: &Session) -> Span { - self.get_crate_data(def_id.krate).get_span(def_id.index, sess) + pub fn def_span_untracked(&self, tcx: TyCtxt<'_>, def_id: DefId) -> Span { + self.get_crate_data(def_id.krate).get_span(tcx, def_id.index) } - pub fn def_kind_untracked(&self, def: DefId) -> DefKind { - self.get_crate_data(def.krate).def_kind(def.index) + pub fn def_kind_untracked(&self, tcx: TyCtxt<'_>, def: DefId) -> DefKind { + self.get_crate_data(def.krate).def_kind(tcx, def.index) } - pub fn expn_that_defined_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId { - self.get_crate_data(def_id.krate).get_expn_that_defined(def_id.index, sess) + pub fn expn_that_defined_untracked(&self, tcx: TyCtxt<'_>, def_id: DefId) -> ExpnId { + self.get_crate_data(def_id.krate).get_expn_that_defined(tcx, def_id.index) } /// Only public-facing way to traverse all the definitions in a non-local crate. @@ -594,20 +594,20 @@ pub fn num_def_ids_untracked(&self, cnum: CrateNum) -> usize { pub fn get_proc_macro_quoted_span_untracked( &self, + tcx: TyCtxt<'_>, cnum: CrateNum, id: usize, - sess: &Session, ) -> Span { - self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess) + self.get_crate_data(cnum).get_proc_macro_quoted_span(tcx, id) } - pub fn set_used_recursively(&mut self, cnum: CrateNum) { + pub fn set_used_recursively(&mut self, tcx: TyCtxt<'_>, cnum: CrateNum) { let cmeta = self.get_crate_data_mut(cnum); if !cmeta.used { cmeta.used = true; let dependencies = mem::take(&mut cmeta.dependencies); for &dep_cnum in &dependencies { - self.set_used_recursively(dep_cnum); + self.set_used_recursively(tcx, dep_cnum); } self.get_crate_data_mut(cnum).dependencies = dependencies; } @@ -700,13 +700,13 @@ fn provide_cstore_hooks(providers: &mut Providers) { providers.hooks.expn_hash_to_expn_id = |tcx, cnum, index_guess, hash| { let cstore = CStore::from_tcx(tcx); - cstore.get_crate_data(cnum).expn_hash_to_expn_id(tcx.sess, index_guess, hash) + cstore.get_crate_data(cnum).expn_hash_to_expn_id(tcx, index_guess, hash) }; providers.hooks.import_source_files = |tcx, cnum| { let cstore = CStore::from_tcx(tcx); let cdata = cstore.get_crate_data(cnum); for file_index in 0..cdata.root.source_map.size() { - cdata.imported_source_file(file_index as u32, tcx.sess); + cdata.imported_source_file(tcx, file_index as u32); } }; } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index aaaed76bda9d..3b5a38181d58 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -1,7 +1,7 @@ use rustc_hir::def::CtorOf; use rustc_index::Idx; -use crate::rmeta::decoder::BlobMetadata; +use crate::rmeta::decoder::Metadata; use crate::rmeta::*; pub(super) trait IsDefault: Default { @@ -523,11 +523,7 @@ fn trailing_zeros(x: &[u8]) -> usize { for<'tcx> T::Value<'tcx>: FixedSizeEncoding, { /// Given the metadata, extract out the value at a particular index (if any). - pub(super) fn get<'a, 'tcx, M: BlobMetadata<'a, 'tcx>>( - &self, - metadata: M, - i: I, - ) -> T::Value<'tcx> { + pub(super) fn get<'a, 'tcx, M: Metadata<'a>>(&self, metadata: M, i: I) -> T::Value<'tcx> { // Access past the end of the table returns a Default if i.index() >= self.len { return Default::default(); diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index cd12d5ad10cf..26658aef3359 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -141,7 +141,7 @@ pub(crate) fn get_module(&self, def_id: DefId) -> Option> { } // Query `def_kind` is not used because query system overhead is too expensive here. - let def_kind = self.cstore().def_kind_untracked(def_id); + let def_kind = self.cstore().def_kind_untracked(self.tcx, def_id); if def_kind.is_module_like() { let parent = self .tcx @@ -149,7 +149,7 @@ pub(crate) fn get_module(&self, def_id: DefId) -> Option> { .map(|parent_id| self.get_nearest_non_block_module(parent_id)); // Query `expn_that_defined` is not used because // hashing spans in its result is expensive. - let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess); + let expn_id = self.cstore().expn_that_defined_untracked(self.tcx, def_id); return Some(self.new_extern_module( parent, ModuleKind::Def(def_kind, def_id, Some(self.tcx.item_name(def_id))), @@ -196,7 +196,7 @@ pub(crate) fn get_macro_by_def_id(&self, def_id: DefId) -> &'ra MacroData { match def_id.as_local() { Some(local_def_id) => self.local_macro_map[&local_def_id], None => *self.extern_macro_map.borrow_mut().entry(def_id).or_insert_with(|| { - let loaded_macro = self.cstore().load_macro_untracked(def_id, self.tcx); + let loaded_macro = self.cstore().load_macro_untracked(self.tcx, def_id); let macro_data = match loaded_macro { LoadedMacro::MacroDef { def, ident, attrs, span, edition } => { self.compile_macro(&def, ident, &attrs, span, ast::DUMMY_NODE_ID, edition) @@ -213,7 +213,7 @@ pub(crate) fn get_macro_by_def_id(&self, def_id: DefId) -> &'ra MacroData { /// find them for suggestions. pub(crate) fn register_macros_for_all_crates(&mut self) { if !self.all_crate_macros_already_registered { - for def_id in self.cstore().all_proc_macro_def_ids() { + for def_id in self.cstore().all_proc_macro_def_ids(self.tcx) { self.get_macro_by_def_id(def_id); } self.all_crate_macros_already_registered = true; diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index f59b5a0aad9a..e38d4370d5d2 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1235,7 +1235,7 @@ fn finalize_module_binding( let struct_ctor = match def_id.as_local() { Some(def_id) => self.struct_constructors.get(&def_id).cloned(), None => { - let ctor = self.cstore().ctor_untracked(def_id); + let ctor = self.cstore().ctor_untracked(self.tcx(), def_id); ctor.map(|(ctor_kind, ctor_def_id)| { let ctor_res = Res::Def( DefKind::Ctor(rustc_hir::def::CtorOf::Struct, ctor_kind), diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 3ab6c7dcc006..71baef458bbf 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2024,7 +2024,7 @@ fn smart_resolve_context_dependent_help( let struct_ctor = match def_id.as_local() { Some(def_id) => self.r.struct_constructors.get(&def_id).cloned(), None => { - let ctor = self.r.cstore().ctor_untracked(def_id); + let ctor = self.r.cstore().ctor_untracked(self.r.tcx(), def_id); ctor.map(|(ctor_kind, ctor_def_id)| { let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ed47f3124f93..35d54615772b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2316,7 +2316,7 @@ fn def_span(&self, def_id: DefId) -> Span { match def_id.as_local() { Some(def_id) => self.tcx.source_span(def_id), // Query `def_span` is not used because hashing its result span is expensive. - None => self.cstore().def_span_untracked(def_id, self.tcx.sess), + None => self.cstore().def_span_untracked(self.tcx(), def_id), } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 10a0078547ad..6bba985d87dd 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -477,7 +477,7 @@ fn macro_accessible( } fn get_proc_macro_quoted_span(&self, krate: CrateNum, id: usize) -> Span { - self.cstore().get_proc_macro_quoted_span_untracked(krate, id, self.tcx.sess) + self.cstore().get_proc_macro_quoted_span_untracked(self.tcx, krate, id) } fn declare_proc_macro(&mut self, id: NodeId) { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 189d3a70ad62..849df566b4bd 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -239,7 +239,7 @@ pub(crate) fn get_item_path(tcx: TyCtxt<'_>, def_id: DefId, kind: ItemType) -> V // Check to see if it is a macro 2.0 or built-in macro // More information in . if matches!( - CStore::from_tcx(tcx).load_macro_untracked(def_id, tcx), + CStore::from_tcx(tcx).load_macro_untracked(tcx, def_id), LoadedMacro::MacroDef { def, .. } if !def.macro_rules ) { once(crate_name).chain(relative).collect() @@ -772,7 +772,7 @@ fn build_macro( name: Symbol, macro_kinds: MacroKinds, ) -> clean::ItemKind { - match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) { + match CStore::from_tcx(cx.tcx).load_macro_untracked(cx.tcx, def_id) { // FIXME: handle attributes and derives that aren't proc macros, and macros with multiple // kinds LoadedMacro::MacroDef { def, .. } => match macro_kinds { From 8c7889bd18a93a7c82db0dcdf6c661594a5a8093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 1 Dec 2025 11:48:22 +0100 Subject: [PATCH 388/585] document various traits --- compiler/rustc_macros/src/lib.rs | 79 +++++++++++++++++--- compiler/rustc_macros/src/serialize.rs | 2 +- compiler/rustc_metadata/src/locator.rs | 1 - compiler/rustc_metadata/src/rmeta/decoder.rs | 12 ++- compiler/rustc_metadata/src/rmeta/mod.rs | 13 ++-- compiler/rustc_span/src/lib.rs | 14 ++++ 6 files changed, 97 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 9f55143ecf53..8cd6c0264448 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -72,25 +72,80 @@ pub fn extension(attr: TokenStream, input: TokenStream) -> TokenStream { hash_stable::hash_stable_no_context_derive ); -decl_derive!([Decodable_NoContext] => serialize::decodable_nocontext_derive); +// Encoding and Decoding derives +decl_derive!([Decodable_NoContext] => + /// See docs on derive [`Decodable`]. + /// + /// Derives `Decodable for T where D: Decoder`. + serialize::decodable_nocontext_derive +); decl_derive!([Encodable_NoContext] => serialize::encodable_nocontext_derive); -decl_derive!([Decodable] => serialize::decodable_derive); +decl_derive!([Decodable] => + /// Derives `Decodable for T where D: SpanDecoder` + /// + /// # Deriving decoding traits + /// + /// > Some shared docs about decoding traits, since this is likely the first trait you find + /// + /// The difference between these derives can be subtle! + /// At a high level, there's the `T: Decodable` trait that says some type `T` + /// can be decoded using a decoder `D`. There are various decoders! + /// The different derives place different *trait* bounds on this type `D`. + /// + /// Even though this derive, based on its name, seems like the most vanilla one, + /// it actually places a pretty strict bound on `D`: `SpanDecoder`. + /// It means that types that derive this can contain spans, among other things, + /// and still be decoded. The reason this is hard is that at least in metadata, + /// spans can only be decoded later, once some information from the header + /// is already decoded to properly deal with spans. + /// + /// The hierarchy is roughly: + /// + /// - derive [`Decodable_NoContext`] is the most relaxed bounds that could be placed on `D`, + /// and is only really suited for structs and enums containing primitive types. + /// - derive [`BlobDecodable`] may be a better default, than deriving `Decodable`: + /// it places fewer requirements on `D`, while still allowing some complex types to be decoded. + /// - derive [`LazyDecodable`]: Only for types containing `Lazy{Array,Table,Value}`. + /// - derive [`Decodable`] for structures containing spans. Requires `D: SpanDecoder` + /// - derive [`TyDecodable`] for types that require access to the `TyCtxt` while decoding. + /// For example: arena allocated types. + serialize::decodable_derive +); decl_derive!([Encodable] => serialize::encodable_derive); -decl_derive!([TyDecodable] => serialize::type_decodable_derive); +decl_derive!([TyDecodable] => + /// See docs on derive [`Decodable`]. + /// + /// Derives `Decodable for T where D: TyDecoder`. + serialize::type_decodable_derive +); decl_derive!([TyEncodable] => serialize::type_encodable_derive); -decl_derive!([MetadataDecodable] => - /// This constrains the decoder to be specifically the decoder that can decode LazyArrays in metadata. - /// Therefore, we only use this on things containing LazyArray really. - /// Anything else should either be `NoContext`, if possible `BlobDecodable`, or otherwise just `Decodable`. - serialize::meta_decodable_derive +decl_derive!([LazyDecodable] => + /// See docs on derive [`Decodable`]. + /// + /// Derives `Decodable for T where D: LazyDecoder`. + /// This constrains the decoder to be specifically the decoder that can decode + /// `LazyArray`s, `LazyValue`s amd `LazyTable`s in metadata. + /// Therefore, we only need this on things containing LazyArray really. + /// + /// Most decodable derives mirror an encodable derive. + /// [`LazyDecodable`] and [`BlobDecodable`] together roughly mirror [`MetadataEncodable`] + serialize::lazy_decodable_derive ); decl_derive!([BlobDecodable] => - /// For anything that is "simple" to decode, without needing anything but the original data, - /// but for which the Decoder can customize some things - /// (unlike Decodable_NoContext which individual decoders can't customize). + /// See docs on derive [`Decodable`]. + /// + /// Derives `Decodable for T where D: BlobDecoder`. + /// + /// Most decodable derives mirror an encodable derive. + /// [`LazyDecodable`] and [`BlobDecodable`] together roughly mirror [`MetadataEncodable`] serialize::blob_decodable_derive ); -decl_derive!([MetadataEncodable] => serialize::meta_encodable_derive); +decl_derive!([MetadataEncodable] => + /// Most encodable derives mirror a decodable derive. + /// [`MetadataEncodable`] is roughly mirrored by the combination of [`LazyDecodable`] and [`BlobDecodable`] + serialize::meta_encodable_derive +); + decl_derive!( [TypeFoldable, attributes(type_foldable)] => /// Derives `TypeFoldable` for the annotated `struct` or `enum` (`union` is not supported). diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index abf566288df4..5ae6fb241c98 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -26,7 +26,7 @@ pub(super) fn blob_decodable_derive( decodable_body(s, decoder_ty) } -pub(super) fn meta_decodable_derive( +pub(super) fn lazy_decodable_derive( mut s: synstructure::Structure<'_>, ) -> proc_macro2::TokenStream { let decoder_ty = quote! { __D }; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 6a441706a22b..9fef22f9558d 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -224,7 +224,6 @@ use rustc_data_structures::svh::Svh; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_fs_util::try_canonicalize; -use rustc_middle::ty::TyCtxt; use rustc_session::cstore::CrateSource; use rustc_session::filesearch::FileSearch; use rustc_session::search_paths::PathKind; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index df0d1b7d085f..bf7818b49933 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -155,15 +155,20 @@ struct ImportedSourceFile { translated_source_file: Arc, } -/// Decode context used when we just have a blob, -/// and we still have to read the header etc. +/// Decode context used when we just have a blob of metadata from which we have to decode a header +/// and [`CrateRoot`]. After that, [`MetadataDecodeContext`] can be used. +/// Most notably, [`BlobDecodeContext]` doesn't implement [`SpanDecoder`] pub(super) struct BlobDecodeContext<'a> { opaque: MemDecoder<'a>, blob: &'a MetadataBlob, lazy_state: LazyState, } -/// trait for anything containing `LazyState` and is a decoder. +/// This trait abstracts over decoders that can decode lazy values using [`LazyState`]: +/// +/// - [`LazyValue`] +/// - [`LazyArray`] +/// - [`LazyTable`] pub(super) trait LazyDecoder: BlobDecoder { fn set_lazy_state(&mut self, state: LazyState); fn get_lazy_state(&self) -> LazyState; @@ -210,6 +215,7 @@ fn get_lazy_state(&self) -> LazyState { /// This is the decode context used when crate metadata was already read. /// Decoding of some types, like `Span` require some information to already been read. +/// Can be constructed from a [`TyCtxt`] and [`CrateMetadataRef`] (see the [`Metadata`] trait) pub(super) struct MetadataDecodeContext<'a, 'tcx> { blob_decoder: BlobDecodeContext<'a>, cdata: CrateMetadataRef<'a>, diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index b1b9bcfcc506..8ac1dd83ee5d 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -19,8 +19,7 @@ use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; use rustc_macros::{ - BlobDecodable, Decodable, Encodable, MetadataDecodable, MetadataEncodable, TyDecodable, - TyEncodable, + BlobDecodable, Decodable, Encodable, LazyDecodable, MetadataEncodable, TyDecodable, TyEncodable, }; use rustc_middle::metadata::ModChild; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -188,7 +187,7 @@ enum LazyState { type ExpnDataTable = LazyTable>>; type ExpnHashTable = LazyTable>>; -#[derive(MetadataEncodable, MetadataDecodable)] +#[derive(MetadataEncodable, LazyDecodable)] pub(crate) struct ProcMacroData { proc_macro_decls_static: DefIndex, stability: Option, @@ -237,7 +236,7 @@ pub(crate) struct CrateHeader { /// compilation session. If we were to serialize a proc-macro crate like /// a normal crate, much of what we serialized would be unusable in addition /// to being unused. -#[derive(MetadataEncodable, MetadataDecodable)] +#[derive(MetadataEncodable, LazyDecodable)] pub(crate) struct CrateRoot { /// A header used to detect if this is the right crate to load. header: CrateHeader, @@ -334,13 +333,13 @@ pub(crate) struct CrateDep { pub is_private: bool, } -#[derive(MetadataEncodable, MetadataDecodable)] +#[derive(MetadataEncodable, LazyDecodable)] pub(crate) struct TraitImpls { trait_id: (u32, DefIndex), impls: LazyArray<(DefIndex, Option)>, } -#[derive(MetadataEncodable, MetadataDecodable)] +#[derive(MetadataEncodable, LazyDecodable)] pub(crate) struct IncoherentImpls { self_ty: LazyValue, impls: LazyArray, @@ -352,7 +351,7 @@ macro_rules! define_tables { - defaulted: $($name1:ident: Table<$IDX1:ty, $T1:ty>,)+ - optional: $($name2:ident: Table<$IDX2:ty, $T2:ty>,)+ ) => { - #[derive(MetadataEncodable, MetadataDecodable)] + #[derive(MetadataEncodable, LazyDecodable)] pub(crate) struct LazyTables { $($name1: LazyTable<$IDX1, $T1>,)+ $($name2: LazyTable<$IDX2, Option<$T2>>,)+ diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index c6490b358ef8..6a359c5f4656 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1304,6 +1304,20 @@ pub trait BlobDecoder: Decoder { /// This trait is used to allow decoder specific encodings of certain types. /// It is similar to rustc_type_ir's TyDecoder. +/// +/// Specifically for metadata, an important note is that spans can only be decoded once +/// some other metadata is already read. +/// Spans have to be properly mapped into the decoding crate's sourcemap, +/// and crate numbers have to be converted sometimes. +/// This can only be done once the `CrateRoot` is available. +/// +/// As such, some methods that used to be in the `SpanDecoder` trait +/// are now in the `BlobDecoder` trait. This hierarchy is not mirrored for `Encoder`s. +/// `BlobDecoder` has methods for deserializing types that are more complex than just those +/// that can be decoded with `Decoder`, but which can be decoded on their own, *before* any other metadata is. +/// Importantly, that means that types that can be decoded with `BlobDecoder` can show up in the crate root. +/// The place where this distinction is relevant is in `rustc_metadata` where metadata is decoded using either the +/// `MetadataDecodeContext` or the `BlobDecodeContext`. pub trait SpanDecoder: BlobDecoder { fn decode_span(&mut self) -> Span; fn decode_expn_id(&mut self) -> ExpnId; From 260b1ffc2cc6e2b83c68e6357417022db262f511 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 8 Dec 2025 09:37:11 +0800 Subject: [PATCH 389/585] compiletest: require `host`/`target` flags specified Instead of allowing them to be missing and using some placeholder "(none)" value instead. --- src/tools/compiletest/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index f3bd467db3e4..625d839dece1 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -255,7 +255,9 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { } } - let target = opt_str2(matches.opt_str("target")); + let host = matches.opt_str("host").expect("`--host` must be unconditionally specified"); + let target = matches.opt_str("target").expect("`--target` must be unconditionally specified"); + let android_cross_path = matches.opt_str("android-cross-path").map(Utf8PathBuf::from); // FIXME: `cdb_version` is *derived* from cdb, but it's *not* technically a config! let cdb = debuggers::discover_cdb(matches.opt_str("cdb"), &target); @@ -433,7 +435,7 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { optimize_tests: matches.opt_present("optimize-tests"), rust_randomized_layout: matches.opt_present("rust-randomized-layout"), target, - host: opt_str2(matches.opt_str("host")), + host, cdb, cdb_version, gdb, From a7ad2142e35a1aa7e51b052b9ffad83e653e6340 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 8 Dec 2025 09:38:31 +0800 Subject: [PATCH 390/585] compiletest: make presence/absence of adb-related options clear Instead of possibly falling back to "(none)" when they are not specified. --- src/tools/compiletest/src/lib.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 625d839dece1..cd875d78f231 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -259,6 +259,13 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { let target = matches.opt_str("target").expect("`--target` must be unconditionally specified"); let android_cross_path = matches.opt_str("android-cross-path").map(Utf8PathBuf::from); + + // FIXME: `adb_path` should be an `Option`... + let adb_path = matches.opt_str("adb-path").map(Utf8PathBuf::from).unwrap_or_default(); + // FIXME: `adb_test_dir` should be an `Option`... + let adb_test_dir = matches.opt_str("adb-test-dir").map(Utf8PathBuf::from).unwrap_or_default(); + let adb_device_status = target.contains("android") && !adb_test_dir.as_str().is_empty(); + // FIXME: `cdb_version` is *derived* from cdb, but it's *not* technically a config! let cdb = debuggers::discover_cdb(matches.opt_str("cdb"), &target); let cdb_version = cdb.as_deref().and_then(debuggers::query_cdb_version); @@ -445,11 +452,9 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { llvm_version, system_llvm: matches.opt_present("system-llvm"), android_cross_path, - adb_path: Utf8PathBuf::from(opt_str2(matches.opt_str("adb-path"))), - adb_test_dir: Utf8PathBuf::from(opt_str2(matches.opt_str("adb-test-dir"))), - adb_device_status: opt_str2(matches.opt_str("target")).contains("android") - && "(none)" != opt_str2(matches.opt_str("adb-test-dir")) - && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(), + adb_path, + adb_test_dir, + adb_device_status, verbose: matches.opt_present("verbose"), only_modified: matches.opt_present("only-modified"), color, From 72541e9a511f4844000ca42a60516eddb2bfa892 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 8 Dec 2025 09:41:46 +0800 Subject: [PATCH 391/585] compiletest: retire `opt_str2` We either have the value of a flag specified, or we don't. Use `Option<...>` to represent that -- don't invent a new "(none)" sentinel value... --- src/tools/compiletest/src/lib.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index cd875d78f231..ff4cd81d33ff 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -500,13 +500,6 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { } } -fn opt_str2(maybestr: Option) -> String { - match maybestr { - None => "(none)".to_owned(), - Some(s) => s, - } -} - /// Called by `main` after the config has been parsed. fn run_tests(config: Arc) { debug!(?config, "run_tests"); From 29d4cbafa418c9546546d8867bdd07afa8fbcda3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 8 Dec 2025 09:46:16 +0000 Subject: [PATCH 392/585] Rustup to rustc 1.94.0-nightly (ba2142a19 2025-12-07) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 4bbbc12cdd0b..461dbcdb0fb5 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-11-28" +channel = "nightly-2025-12-08" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 942a08b559714576ee97bb2f4001f20547de427d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 8 Dec 2025 10:48:42 +0100 Subject: [PATCH 393/585] Revert "early return on duplicate span lowerings" This reverts commit 0087253015d1191b97b5e312c2409e008db87ed6. --- compiler/rustc_ast_lowering/src/lib.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ab5caff86204..dff46ece6543 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -225,13 +225,6 @@ struct SpanLowerer { impl SpanLowerer { fn lower(&self, span: Span) -> Span { if self.is_incremental { - // early return: span lowering takes some time since it accesses the query dependency graph - // to make sure we rerun the right code paths when spans change. When we've already lowered a span, - // or don't have to, bail out ASAP. - if span.is_dummy() || span.parent().is_some_and(|i| i == self.def_id) { - return span; - } - span.with_parent(Some(self.def_id)) } else { // Do not make spans relative when not using incremental compilation. From 5139ab431ff1d9a21f9ce0505e33642e79107d93 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 8 Dec 2025 09:55:17 +0000 Subject: [PATCH 394/585] Fix rustc testsuite --- src/lib.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 5fdecd014ac0..b47b9afa4f07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,7 +47,7 @@ use rustc_log::tracing::info; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; -use rustc_session::config::OutputFilenames; +use rustc_session::config::{OutputFilenames, PrintKind, PrintRequest}; use rustc_span::{Symbol, sym}; use rustc_target::spec::{Abi, Arch, Env, Os}; @@ -160,6 +160,16 @@ fn init(&self, sess: &Session) { } } + fn print(&self, req: &PrintRequest, out: &mut String, _sess: &Session) { + match req.kind { + // FIXME have a default impl that returns false + PrintKind::BackendHasZstd => { + out.push_str("false\n"); + } + _ => {} + } + } + fn target_config(&self, sess: &Session) -> TargetConfig { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] let target_features = match sess.target.arch { From fd6e372a97fd63907ac87826ea1567e5d2c01c20 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:13:25 +0000 Subject: [PATCH 395/585] Fix Cirrus CI --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 3ed89beceb7f..9be095dbf2d8 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,7 +1,7 @@ task: name: freebsd freebsd_instance: - image_family: freebsd-14-2 + image_family: freebsd-15-0-amd64-ufs setup_rust_script: - pkg install -y git-tiny binutils - curl https://sh.rustup.rs -sSf --output rustup.sh From ba27d3d8a68534ee2f418cce3cfaa0f5b0d79d90 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:09:16 +0000 Subject: [PATCH 396/585] Fix gimli assertion for anonymous sources --- src/debuginfo/line_info.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/debuginfo/line_info.rs b/src/debuginfo/line_info.rs index 6fe22f5c6dd9..a6ffe6c2bf39 100644 --- a/src/debuginfo/line_info.rs +++ b/src/debuginfo/line_info.rs @@ -117,8 +117,7 @@ pub(crate) fn add_source_file(&mut self, source_file: &SourceFile) -> FileId { } filename => { // For anonymous sources, create an empty directory instead of using the default - let empty_dir = LineString::new(b"", line_program.encoding(), line_strings); - let dir_id = line_program.add_directory(empty_dir); + let dir_id = line_program.default_directory(); let dummy_file_name = LineString::new( filename.prefer_remapped_unconditionally().to_string().into_bytes(), From 8b0e6756e0c40e5f64cf356344e593c02a982d4a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:09:50 +0000 Subject: [PATCH 397/585] Only generate line tables with -Cdebuginfo=line-table-only --- src/debuginfo/line_info.rs | 6 +--- src/debuginfo/mod.rs | 59 +++++++++++++++++++++++++------------- src/debuginfo/types.rs | 3 +- 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/debuginfo/line_info.rs b/src/debuginfo/line_info.rs index a6ffe6c2bf39..db58ee890911 100644 --- a/src/debuginfo/line_info.rs +++ b/src/debuginfo/line_info.rs @@ -5,7 +5,7 @@ use cranelift_codegen::MachSrcLoc; use cranelift_codegen::binemit::CodeOffset; -use gimli::write::{AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable}; +use gimli::write::{FileId, FileInfo, LineProgram, LineString, LineStringTable}; use rustc_span::{FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHashAlgorithm, hygiene}; use crate::debuginfo::FunctionDebugContext; @@ -175,10 +175,6 @@ pub(super) fn create_debug_lines( assert_ne!(func_end, 0); - let entry = debug_context.dwarf.unit.get_mut(self.entry_id); - entry.set(gimli::DW_AT_low_pc, AttributeValue::Address(address_for_func(func_id))); - entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(func_end))); - func_end } } diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 494002f525c8..8c43db92fe05 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -42,14 +42,14 @@ pub(crate) struct DebugContext { created_files: FxHashMap<(StableSourceFileId, SourceFileHash), FileId>, stack_pointer_register: Register, namespace_map: DefIdMap, - array_size_type: UnitEntryId, + array_size_type: Option, filename_display_preference: FileNameDisplayPreference, embed_source: bool, } pub(crate) struct FunctionDebugContext { - entry_id: UnitEntryId, + entry_id: Option, function_source_loc: (FileId, u64, u64), source_loc_set: IndexSet<(FileId, u64, u64)>, } @@ -154,18 +154,23 @@ pub(crate) fn new( root.set(gimli::DW_AT_low_pc, AttributeValue::Address(Address::Constant(0))); } - let array_size_type = dwarf.unit.add(dwarf.unit.root(), gimli::DW_TAG_base_type); - let array_size_type_entry = dwarf.unit.get_mut(array_size_type); - array_size_type_entry.set( - gimli::DW_AT_name, - AttributeValue::StringRef(dwarf.strings.add("__ARRAY_SIZE_TYPE__")), - ); - array_size_type_entry - .set(gimli::DW_AT_encoding, AttributeValue::Encoding(gimli::DW_ATE_unsigned)); - array_size_type_entry.set( - gimli::DW_AT_byte_size, - AttributeValue::Udata(isa.frontend_config().pointer_bytes().into()), - ); + let array_size_type = if tcx.sess.opts.debuginfo == DebugInfo::LineTablesOnly { + None + } else { + let array_size_type = dwarf.unit.add(dwarf.unit.root(), gimli::DW_TAG_base_type); + let array_size_type_entry = dwarf.unit.get_mut(array_size_type); + array_size_type_entry.set( + gimli::DW_AT_name, + AttributeValue::StringRef(dwarf.strings.add("__ARRAY_SIZE_TYPE__")), + ); + array_size_type_entry + .set(gimli::DW_AT_encoding, AttributeValue::Encoding(gimli::DW_ATE_unsigned)); + array_size_type_entry.set( + gimli::DW_AT_byte_size, + AttributeValue::Udata(isa.frontend_config().pointer_bytes().into()), + ); + Some(array_size_type) + }; Some(DebugContext { endian, @@ -217,6 +222,14 @@ pub(crate) fn define_function<'tcx>( ) -> FunctionDebugContext { let (file_id, line, column) = self.get_span_loc(tcx, function_span, function_span); + if tcx.sess.opts.debuginfo == DebugInfo::LineTablesOnly { + return FunctionDebugContext { + entry_id: None, + function_source_loc: (file_id, line, column), + source_loc_set: IndexSet::new(), + }; + } + let scope = self.item_namespace(tcx, tcx.parent(instance.def_id())); let mut name = String::new(); @@ -274,7 +287,7 @@ pub(crate) fn define_function<'tcx>( } FunctionDebugContext { - entry_id, + entry_id: Some(entry_id), function_source_loc: (file_id, line, column), source_loc_set: IndexSet::new(), } @@ -288,6 +301,10 @@ pub(crate) fn define_static<'tcx>( def_id: DefId, data_id: DataId, ) { + if tcx.sess.opts.debuginfo == DebugInfo::LineTablesOnly { + return; + } + let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() }; if nested { return; @@ -353,10 +370,12 @@ pub(crate) fn finalize( .0 .push(Range::StartLength { begin: address_for_func(func_id), length: u64::from(end) }); - let func_entry = debug_context.dwarf.unit.get_mut(self.entry_id); - // Gdb requires both DW_AT_low_pc and DW_AT_high_pc. Otherwise the DW_TAG_subprogram is skipped. - func_entry.set(gimli::DW_AT_low_pc, AttributeValue::Address(address_for_func(func_id))); - // Using Udata for DW_AT_high_pc requires at least DWARF4 - func_entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(end))); + if let Some(entry_id) = self.entry_id { + let entry = debug_context.dwarf.unit.get_mut(entry_id); + // Gdb requires both DW_AT_low_pc and DW_AT_high_pc. Otherwise the DW_TAG_subprogram is skipped. + entry.set(gimli::DW_AT_low_pc, AttributeValue::Address(address_for_func(func_id))); + // Using Udata for DW_AT_high_pc requires at least DWARF4 + entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(end))); + } } } diff --git a/src/debuginfo/types.rs b/src/debuginfo/types.rs index a292429cdfad..18a0632a0939 100644 --- a/src/debuginfo/types.rs +++ b/src/debuginfo/types.rs @@ -109,7 +109,8 @@ fn array_type<'tcx>( let subrange_id = self.dwarf.unit.add(array_type_id, gimli::DW_TAG_subrange_type); let subrange_entry = self.dwarf.unit.get_mut(subrange_id); - subrange_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(self.array_size_type)); + subrange_entry + .set(gimli::DW_AT_type, AttributeValue::UnitRef(self.array_size_type.unwrap())); subrange_entry.set(gimli::DW_AT_lower_bound, AttributeValue::Udata(0)); subrange_entry.set(gimli::DW_AT_count, AttributeValue::Udata(len)); From 8c582e1f530b967dcbf2a549f70fce08819da3a1 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 7 Dec 2025 15:27:50 +1100 Subject: [PATCH 398/585] Don't require `test::Coverage` to implement Ord This derive was an artifact of test-only method `Cache::all` wanting to automatically sort its output to hide HashMap iteration order. We can achieve an equivalent result by requiring the caller to provide a projection function that returns results that _are_ sortable. --- src/bootstrap/src/core/build_steps/test.rs | 2 +- src/bootstrap/src/core/builder/tests.rs | 3 +-- src/bootstrap/src/utils/cache.rs | 20 +++++++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 09c98bd7c88b..67cd5b8d67c3 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1582,7 +1582,7 @@ fn run(self, builder: &Builder<'_>) { /// Runs the coverage test suite at `tests/coverage` in some or all of the /// coverage test modes. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Coverage { pub compiler: Compiler, pub target: TargetSelection, diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index b8ba1b4c2c34..965b75f24c20 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -345,8 +345,7 @@ struct Case { let config = configure_with_args(cmd, &[], &[TEST_TRIPLE_1]); let mut cache = run_build(&config.paths.clone(), config); - let modes = - cache.all::().iter().map(|(step, ())| step.mode).collect::>(); + let modes = cache.inspect_all_steps_of_type::(|step, ()| step.mode); assert_eq!(modes, expected); } } diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs index 5098e2f03c43..8c5b3529979d 100644 --- a/src/bootstrap/src/utils/cache.rs +++ b/src/bootstrap/src/utils/cache.rs @@ -270,16 +270,18 @@ pub fn get(&self, step: &S) -> Option { #[cfg(test)] impl Cache { - pub fn all(&mut self) -> Vec<(S, S::Output)> { - let cache = self.cache.get_mut(); - let type_id = TypeId::of::(); - let mut v = cache - .remove(&type_id) - .map(|b| b.downcast::>().expect("correct type")) - .map(|m| m.into_iter().collect::>()) + pub(crate) fn inspect_all_steps_of_type( + &self, + map_fn: impl Fn(&S, &S::Output) -> T, + ) -> Vec { + let cache = self.cache.borrow(); + let mut values = cache + .get(&TypeId::of::()) + .map(|any| any.downcast_ref::>().expect("correct type")) + .map(|m| m.iter().map(|(step, output)| map_fn(step, output)).collect::>()) .unwrap_or_default(); - v.sort_by_key(|(s, _)| s.clone()); - v + values.sort(); + values } pub fn contains(&self) -> bool { From dc8cdb1c00da2649fb7ff56b56af11b4e9592802 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 7 Dec 2025 15:14:26 +1100 Subject: [PATCH 399/585] Use a `CompiletestMode` enum in bootstrap --- src/bootstrap/src/core/build_steps/test.rs | 116 +++++++++++------- .../src/core/build_steps/test/compiletest.rs | 71 +++++++++++ src/bootstrap/src/core/builder/tests.rs | 3 +- 3 files changed, 142 insertions(+), 48 deletions(-) create mode 100644 src/bootstrap/src/core/build_steps/test/compiletest.rs diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 67cd5b8d67c3..a699cd23fb60 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3,6 +3,9 @@ //! `./x.py test` (aka [`Kind::Test`]) is currently allowed to reach build steps in other modules. //! However, this contains ~all test parts we expect people to be able to build and run locally. +// (This file should be split up, but having tidy block all changes is not helpful.) +// ignore-tidy-filelength + use std::collections::HashSet; use std::env::split_paths; use std::ffi::{OsStr, OsString}; @@ -17,6 +20,7 @@ use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::run::{get_completion_paths, get_help_path}; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; +use crate::core::build_steps::test::compiletest::CompiletestMode; use crate::core::build_steps::tool::{ self, RustcPrivateCompilers, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool, ToolTargetBuildMode, get_tool_target_compiler, @@ -39,6 +43,8 @@ use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests}; use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, envify}; +mod compiletest; + /// Runs `cargo test` on various internal tools used by bootstrap. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateBootstrap { @@ -1085,7 +1091,7 @@ fn run(self, builder: &Builder<'_>) { builder.ensure(Compiletest { test_compiler: self.compiler, target: self.target, - mode: "rustdoc-js", + mode: CompiletestMode::RustdocJs, suite: "rustdoc-js", path: "tests/rustdoc-js", compare_mode: None, @@ -1478,7 +1484,7 @@ fn run(self, builder: &Builder<'_>) { builder.ensure(Compiletest { test_compiler: self.test_compiler, target: self.target, - mode: $mode, + mode: const { $mode }, suite: $suite, path: $path, compare_mode: (const { @@ -1493,34 +1499,39 @@ fn run(self, builder: &Builder<'_>) { }; } -test!(Ui { path: "tests/ui", mode: "ui", suite: "ui", default: true }); +test!(Ui { path: "tests/ui", mode: CompiletestMode::Ui, suite: "ui", default: true }); -test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes", default: true }); +test!(Crashes { + path: "tests/crashes", + mode: CompiletestMode::Crashes, + suite: "crashes", + default: true, +}); test!(CodegenLlvm { path: "tests/codegen-llvm", - mode: "codegen", + mode: CompiletestMode::Codegen, suite: "codegen-llvm", default: true }); test!(CodegenUnits { path: "tests/codegen-units", - mode: "codegen-units", + mode: CompiletestMode::CodegenUnits, suite: "codegen-units", default: true, }); test!(Incremental { path: "tests/incremental", - mode: "incremental", + mode: CompiletestMode::Incremental, suite: "incremental", default: true, }); test!(Debuginfo { path: "tests/debuginfo", - mode: "debuginfo", + mode: CompiletestMode::Debuginfo, suite: "debuginfo", default: true, compare_mode: Some("split-dwarf"), @@ -1528,7 +1539,7 @@ fn run(self, builder: &Builder<'_>) { test!(UiFullDeps { path: "tests/ui-fulldeps", - mode: "ui", + mode: CompiletestMode::Ui, suite: "ui-fulldeps", default: true, IS_HOST: true, @@ -1536,14 +1547,14 @@ fn run(self, builder: &Builder<'_>) { test!(Rustdoc { path: "tests/rustdoc", - mode: "rustdoc", + mode: CompiletestMode::Rustdoc, suite: "rustdoc", default: true, IS_HOST: true, }); test!(RustdocUi { path: "tests/rustdoc-ui", - mode: "ui", + mode: CompiletestMode::Ui, suite: "rustdoc-ui", default: true, IS_HOST: true, @@ -1551,7 +1562,7 @@ fn run(self, builder: &Builder<'_>) { test!(RustdocJson { path: "tests/rustdoc-json", - mode: "rustdoc-json", + mode: CompiletestMode::RustdocJson, suite: "rustdoc-json", default: true, IS_HOST: true, @@ -1559,23 +1570,28 @@ fn run(self, builder: &Builder<'_>) { test!(Pretty { path: "tests/pretty", - mode: "pretty", + mode: CompiletestMode::Pretty, suite: "pretty", default: true, IS_HOST: true, }); -test!(RunMake { path: "tests/run-make", mode: "run-make", suite: "run-make", default: true }); +test!(RunMake { + path: "tests/run-make", + mode: CompiletestMode::RunMake, + suite: "run-make", + default: true, +}); test!(RunMakeCargo { path: "tests/run-make-cargo", - mode: "run-make", + mode: CompiletestMode::RunMake, suite: "run-make-cargo", default: true }); test!(AssemblyLlvm { path: "tests/assembly-llvm", - mode: "assembly", + mode: CompiletestMode::Assembly, suite: "assembly-llvm", default: true }); @@ -1586,13 +1602,14 @@ fn run(self, builder: &Builder<'_>) { pub struct Coverage { pub compiler: Compiler, pub target: TargetSelection, - pub mode: &'static str, + pub(crate) mode: CompiletestMode, } impl Coverage { const PATH: &'static str = "tests/coverage"; const SUITE: &'static str = "coverage"; - const ALL_MODES: &[&str] = &["coverage-map", "coverage-run"]; + const ALL_MODES: &[CompiletestMode] = + &[CompiletestMode::CoverageMap, CompiletestMode::CoverageRun]; } impl Step for Coverage { @@ -1608,7 +1625,7 @@ fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> { // - `./x test coverage-run -- tests/coverage/trivial.rs` run = run.suite_path(Self::PATH); for mode in Self::ALL_MODES { - run = run.alias(mode); + run = run.alias(mode.as_str()); } run } @@ -1631,15 +1648,15 @@ fn make_run(run: RunConfig<'_>) { for path in &run.paths { match path { PathSet::Set(_) => { - for mode in Self::ALL_MODES { - if path.assert_single_path().path == Path::new(mode) { + for &mode in Self::ALL_MODES { + if path.assert_single_path().path == Path::new(mode.as_str()) { modes.push(mode); break; } } } PathSet::Suite(_) => { - modes.extend(Self::ALL_MODES); + modes.extend_from_slice(Self::ALL_MODES); break; } } @@ -1647,7 +1664,9 @@ fn make_run(run: RunConfig<'_>) { // Skip any modes that were explicitly skipped/excluded on the command-line. // FIXME(Zalathar): Integrate this into central skip handling somehow? - modes.retain(|mode| !run.builder.config.skip.iter().any(|skip| skip == Path::new(mode))); + modes.retain(|mode| { + !run.builder.config.skip.iter().any(|skip| skip == Path::new(mode.as_str())) + }); // FIXME(Zalathar): Make these commands skip all coverage tests, as expected: // - `./x test --skip=tests` @@ -1678,7 +1697,7 @@ fn run(self, builder: &Builder<'_>) { test!(CoverageRunRustdoc { path: "tests/coverage-run-rustdoc", - mode: "coverage-run", + mode: CompiletestMode::CoverageRun, suite: "coverage-run-rustdoc", default: true, IS_HOST: true, @@ -1712,7 +1731,7 @@ fn run(self, builder: &Builder<'_>) { builder.ensure(Compiletest { test_compiler: self.compiler, target, - mode: "mir-opt", + mode: CompiletestMode::MirOpt, suite: "mir-opt", path: "tests/mir-opt", compare_mode: None, @@ -1755,7 +1774,7 @@ struct Compiletest { /// The compiler that we're testing. test_compiler: Compiler, target: TargetSelection, - mode: &'static str, + mode: CompiletestMode, suite: &'static str, path: &'static str, compare_mode: Option<&'static str>, @@ -1791,7 +1810,7 @@ fn run(self, builder: &Builder<'_>) { let suite_path = self.path; // Skip codegen tests if they aren't enabled in configuration. - if !builder.config.codegen_tests && mode == "codegen" { + if !builder.config.codegen_tests && mode == CompiletestMode::Codegen { return; } @@ -1829,7 +1848,7 @@ fn run(self, builder: &Builder<'_>) { target, }); } - if mode == "run-make" { + if mode == CompiletestMode::RunMake { builder.tool_exe(Tool::RunMakeSupport); } @@ -1886,7 +1905,7 @@ fn run(self, builder: &Builder<'_>) { // suites, `run-make` and `run-make-cargo`. That way, contributors who do not need to run // the `run-make` tests that need in-tree cargo do not need to spend time building in-tree // cargo. - if mode == "run-make" { + if mode == CompiletestMode::RunMake { // We need to pass the compiler that was used to compile run-make-support, // because we have to use the same compiler to compile rmake.rs recipes. let stage0_rustc_path = builder.compiler(0, test_compiler.host); @@ -1910,17 +1929,18 @@ fn run(self, builder: &Builder<'_>) { } // Avoid depending on rustdoc when we don't need it. - if mode == "rustdoc" - || mode == "run-make" - || (mode == "ui" && is_rustdoc) - || mode == "rustdoc-js" - || mode == "rustdoc-json" - || suite == "coverage-run-rustdoc" + if matches!( + mode, + CompiletestMode::RunMake + | CompiletestMode::Rustdoc + | CompiletestMode::RustdocJs + | CompiletestMode::RustdocJson + ) || matches!(suite, "rustdoc-ui" | "coverage-run-rustdoc") { cmd.arg("--rustdoc-path").arg(builder.rustdoc_for_compiler(test_compiler)); } - if mode == "rustdoc-json" { + if mode == CompiletestMode::RustdocJson { // Use the stage0 compiler for jsondocck let json_compiler = builder.compiler(0, builder.host_target); cmd.arg("--jsondocck-path") @@ -1930,7 +1950,7 @@ fn run(self, builder: &Builder<'_>) { ); } - if matches!(mode, "coverage-map" | "coverage-run") { + if matches!(mode, CompiletestMode::CoverageMap | CompiletestMode::CoverageRun) { let coverage_dump = builder.tool_exe(Tool::CoverageDump); cmd.arg("--coverage-dump-path").arg(coverage_dump); } @@ -1957,7 +1977,7 @@ fn run(self, builder: &Builder<'_>) { cmd.arg("--sysroot-base").arg(sysroot); cmd.arg("--suite").arg(suite); - cmd.arg("--mode").arg(mode); + cmd.arg("--mode").arg(mode.as_str()); cmd.arg("--target").arg(target.rustc_target_arg()); cmd.arg("--host").arg(&*test_compiler.host.triple); cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.host_target)); @@ -2036,7 +2056,7 @@ fn run(self, builder: &Builder<'_>) { if let Some(ref nodejs) = builder.config.nodejs { cmd.arg("--nodejs").arg(nodejs); - } else if mode == "rustdoc-js" { + } else if mode == CompiletestMode::RustdocJs { panic!("need nodejs to run rustdoc-js suite"); } if builder.config.rust_optimize_tests { @@ -2055,7 +2075,7 @@ fn run(self, builder: &Builder<'_>) { let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] }; flags.push(format!( "-Cdebuginfo={}", - if mode == "codegen" { + if mode == CompiletestMode::Codegen { // codegen tests typically check LLVM IR and are sensitive to additional debuginfo. // So do not apply `rust.debuginfo-level-tests` for codegen tests. if builder.config.rust_debuginfo_level_tests @@ -2122,7 +2142,7 @@ fn run(self, builder: &Builder<'_>) { cmd.arg("--android-cross-path").arg(android_cross_path); } - if mode == "debuginfo" { + if mode == CompiletestMode::Debuginfo { if let Some(debuggers::Gdb { gdb }) = debuggers::discover_gdb(builder, android.as_ref()) { cmd.arg("--gdb").arg(gdb.as_ref()); @@ -2155,7 +2175,7 @@ fn run(self, builder: &Builder<'_>) { // in rustdoc-js mode, allow filters to be rs files or js files. // use a late-initialized Vec to avoid cloning for other modes. let mut paths_v; - if mode == "rustdoc-js" { + if mode == CompiletestMode::RustdocJs { paths_v = paths.to_vec(); for p in &mut paths_v { if let Some(ext) = p.extension() @@ -2237,7 +2257,9 @@ fn run(self, builder: &Builder<'_>) { cmd.arg("--host-rustcflags").arg(link_llvm); } - if !builder.config.dry_run() && matches!(mode, "run-make" | "coverage-run") { + if !builder.config.dry_run() + && matches!(mode, CompiletestMode::RunMake | CompiletestMode::CoverageRun) + { // The llvm/bin directory contains many useful cross-platform // tools. Pass the path to run-make tests so they can use them. // (The coverage-run tests also need these tools to process @@ -2249,7 +2271,7 @@ fn run(self, builder: &Builder<'_>) { cmd.arg("--llvm-bin-dir").arg(llvm_bin_path); } - if !builder.config.dry_run() && mode == "run-make" { + if !builder.config.dry_run() && mode == CompiletestMode::RunMake { // If LLD is available, add it to the PATH if builder.config.lld_enabled { let lld_install_root = @@ -2269,7 +2291,7 @@ fn run(self, builder: &Builder<'_>) { // Only pass correct values for these flags for the `run-make` suite as it // requires that a C++ compiler was configured which isn't always the case. - if !builder.config.dry_run() && mode == "run-make" { + if !builder.config.dry_run() && mode == CompiletestMode::RunMake { let mut cflags = builder.cc_handled_clags(target, CLang::C); cflags.extend(builder.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::C)); let mut cxxflags = builder.cc_handled_clags(target, CLang::Cxx); @@ -2385,7 +2407,7 @@ fn run(self, builder: &Builder<'_>) { builder.metrics.begin_test_suite( build_helper::metrics::TestSuiteMetadata::Compiletest { suite: suite.into(), - mode: mode.into(), + mode: mode.to_string(), compare_mode: None, target: self.target.triple.to_string(), host: self.test_compiler.host.triple.to_string(), @@ -2408,7 +2430,7 @@ fn run(self, builder: &Builder<'_>) { builder.metrics.begin_test_suite( build_helper::metrics::TestSuiteMetadata::Compiletest { suite: suite.into(), - mode: mode.into(), + mode: mode.to_string(), compare_mode: Some(compare_mode.into()), target: self.target.triple.to_string(), host: self.test_compiler.host.triple.to_string(), diff --git a/src/bootstrap/src/core/build_steps/test/compiletest.rs b/src/bootstrap/src/core/build_steps/test/compiletest.rs new file mode 100644 index 000000000000..359f6bb1a6ef --- /dev/null +++ b/src/bootstrap/src/core/build_steps/test/compiletest.rs @@ -0,0 +1,71 @@ +use std::fmt; + +/// Enum of all the "test modes" understood by compiletest. +/// +/// Some of these mode names happen to overlap with the names of test suite +/// directories, but the relationship between modes and suites is not 1:1. +/// For example: +/// - Mode `ui` is used by suites `tests/ui` and `tests/rustdoc-ui` +/// - Suite `tests/coverage` uses modes `coverage-map` and `coverage-run` +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) enum CompiletestMode { + // tidy-alphabetical-start + Assembly, + Codegen, + CodegenUnits, + CoverageMap, + CoverageRun, + Crashes, + Debuginfo, + Incremental, + MirOpt, + Pretty, + RunMake, + Rustdoc, + RustdocJs, + RustdocJson, + Ui, + // tidy-alphabetical-end +} + +impl CompiletestMode { + /// Returns a string representing this mode, which can be passed to + /// compiletest via a command-line argument. + /// + /// These mode names must be kept in sync with the ones understood by + /// compiletest's `TestMode`, but they change so rarely that doing so + /// manually should not be burdensome. + pub(crate) const fn as_str(self) -> &'static str { + match self { + // tidy-alphabetical-start + Self::Assembly => "assembly", + Self::Codegen => "codegen", + Self::CodegenUnits => "codegen-units", + Self::CoverageMap => "coverage-map", + Self::CoverageRun => "coverage-run", + Self::Crashes => "crashes", + Self::Debuginfo => "debuginfo", + Self::Incremental => "incremental", + Self::MirOpt => "mir-opt", + Self::Pretty => "pretty", + Self::RunMake => "run-make", + Self::Rustdoc => "rustdoc", + Self::RustdocJs => "rustdoc-js", + Self::RustdocJson => "rustdoc-json", + Self::Ui => "ui", + // tidy-alphabetical-end + } + } +} + +impl fmt::Display for CompiletestMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +impl fmt::Debug for CompiletestMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ::fmt(self, f) + } +} diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 965b75f24c20..709d646bb359 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -345,7 +345,8 @@ struct Case { let config = configure_with_args(cmd, &[], &[TEST_TRIPLE_1]); let mut cache = run_build(&config.paths.clone(), config); - let modes = cache.inspect_all_steps_of_type::(|step, ()| step.mode); + let modes = + cache.inspect_all_steps_of_type::(|step, ()| step.mode.as_str()); assert_eq!(modes, expected); } } From e24f0fa3c54951d1a5843b54ebe052faaa3a3cd2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 8 Dec 2025 11:07:33 +0000 Subject: [PATCH 400/585] Update dependencies --- Cargo.lock | 58 ++++++++++++++++++++++++++++++------------------------ Cargo.toml | 2 +- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc27d9c6b542..617c7f0e34cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,9 +37,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cranelift-assembler-x64" @@ -282,18 +282,18 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.177" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libloading" -version = "0.8.8" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" dependencies = [ "cfg-if", - "windows-targets 0.53.3", + "windows-link 0.2.1", ] [[package]] @@ -304,9 +304,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "mach2" @@ -319,9 +319,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "object" @@ -337,27 +337,27 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] [[package]] name = "regalloc2" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd8138ce7c3d7c13be4f61893154b5d711bd798d2d7be3ecb8dcc7e7a06ca98" +checksum = "4e249c660440317032a71ddac302f25f1d5dff387667bcc3978d1f77aa31ac34" dependencies = [ "allocator-api2", "bumpalo", @@ -440,15 +440,15 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -457,15 +457,15 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" +checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "wasmtime-internal-jit-icache-coherence" @@ -494,6 +494,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" version = "0.52.0" @@ -534,7 +540,7 @@ version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", diff --git a/Cargo.toml b/Cargo.toml index 02d0d2ab3c58..58e61cd0b9d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ gimli = { version = "0.32", default-features = false, features = ["write"] } object = { version = "0.37.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" -libloading = { version = "0.8.0", optional = true } +libloading = { version = "0.9.0", optional = true } smallvec = "1.8.1" [patch.crates-io] From 0f4ec281558a40645b125fda43f36d7006180e54 Mon Sep 17 00:00:00 2001 From: SATVIKsynopsis Date: Sun, 7 Dec 2025 16:58:31 +0530 Subject: [PATCH 401/585] lint: treat unsafe binders in improper_ctypes instead of ICE Replaced _binder with _ --- compiler/rustc_lint/messages.ftl | 2 ++ compiler/rustc_lint/src/types/improper_ctypes.rs | 4 +++- .../lint/improper-ctypes/unsafe-binder-basic.rs | 10 ++++++++++ .../improper-ctypes/unsafe-binder-basic.stderr | 15 +++++++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/improper-ctypes/unsafe-binder-basic.rs create mode 100644 tests/ui/lint/improper-ctypes/unsafe-binder-basic.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 1bcdda96e13a..a90a9c91ef13 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -416,6 +416,8 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re lint_improper_ctypes_union_layout_reason = this union has unspecified layout lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive +lint_improper_ctypes_unsafe_binder = unsafe binders are incompatible with foreign function interfaces + lint_int_to_ptr_transmutes = transmuting an integer to a pointer creates a pointer without provenance .note = this is dangerous because dereferencing the resulting pointer is undefined behavior .note_exposed_provenance = exposed provenance semantics can be used to create a pointer based on some previously exposed provenance diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index 9e38ea6b685b..38094c67c34a 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -669,7 +669,9 @@ fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> { FfiSafe } - ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"), + ty::UnsafeBinder(_) => { + FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_unsafe_binder, help: None } + } ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..) diff --git a/tests/ui/lint/improper-ctypes/unsafe-binder-basic.rs b/tests/ui/lint/improper-ctypes/unsafe-binder-basic.rs new file mode 100644 index 000000000000..5d4279fc834d --- /dev/null +++ b/tests/ui/lint/improper-ctypes/unsafe-binder-basic.rs @@ -0,0 +1,10 @@ +#![feature(unsafe_binders)] +#![expect(incomplete_features)] +#![deny(improper_ctypes)] + +extern "C" { + fn exit_2(x: unsafe<'a> &'a ()); + //~^ ERROR `extern` block uses type `unsafe<'a> &'a ()`, which is not FFI-safe +} + +fn main() {} diff --git a/tests/ui/lint/improper-ctypes/unsafe-binder-basic.stderr b/tests/ui/lint/improper-ctypes/unsafe-binder-basic.stderr new file mode 100644 index 000000000000..4b8d51690f1a --- /dev/null +++ b/tests/ui/lint/improper-ctypes/unsafe-binder-basic.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `unsafe<'a> &'a ()`, which is not FFI-safe + --> $DIR/unsafe-binder-basic.rs:6:18 + | +LL | fn exit_2(x: unsafe<'a> &'a ()); + | ^^^^^^^^^^^^^^^^^ not FFI-safe + | + = note: unsafe binders are incompatible with foreign function interfaces +note: the lint level is defined here + --> $DIR/unsafe-binder-basic.rs:3:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From 611c956c78fc9f95bd8af1f9b0567669959d1efe Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 8 Dec 2025 21:57:05 +0800 Subject: [PATCH 402/585] test: Add test for 146133 Even if a crate is marked as #![no_builtins], we can still generate bitcode for rlib, but we cannot emit bitcode to the linker in rustc's LTO. --- .../no-builtins-linker-plugin-lto/main.rs | 3 ++ .../no_builtins.rs | 4 ++ .../no-builtins-linker-plugin-lto/rmake.rs | 53 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 tests/run-make/no-builtins-linker-plugin-lto/main.rs create mode 100644 tests/run-make/no-builtins-linker-plugin-lto/no_builtins.rs create mode 100644 tests/run-make/no-builtins-linker-plugin-lto/rmake.rs diff --git a/tests/run-make/no-builtins-linker-plugin-lto/main.rs b/tests/run-make/no-builtins-linker-plugin-lto/main.rs new file mode 100644 index 000000000000..f96605be8949 --- /dev/null +++ b/tests/run-make/no-builtins-linker-plugin-lto/main.rs @@ -0,0 +1,3 @@ +fn main() { + no_builtins::foo(); +} diff --git a/tests/run-make/no-builtins-linker-plugin-lto/no_builtins.rs b/tests/run-make/no-builtins-linker-plugin-lto/no_builtins.rs new file mode 100644 index 000000000000..a56c1d6b4133 --- /dev/null +++ b/tests/run-make/no-builtins-linker-plugin-lto/no_builtins.rs @@ -0,0 +1,4 @@ +#![no_builtins] + +#[inline(never)] +pub fn foo() {} diff --git a/tests/run-make/no-builtins-linker-plugin-lto/rmake.rs b/tests/run-make/no-builtins-linker-plugin-lto/rmake.rs new file mode 100644 index 000000000000..713308567737 --- /dev/null +++ b/tests/run-make/no-builtins-linker-plugin-lto/rmake.rs @@ -0,0 +1,53 @@ +//@ only-x86_64-unknown-linux-gnu + +use std::fs; +use std::path::Path; + +use run_make_support::{cwd, has_extension, llvm_ar, llvm_bcanalyzer, rust_lib_name, rustc}; + +// A regression test for #146133. + +fn main() { + // Compile a `#![no_builtins]` rlib crate with `-Clinker-plugin-lto`. + // It is acceptable to generate bitcode for rlib, so there is no need to check something. + rustc().input("no_builtins.rs").crate_type("rlib").linker_plugin_lto("on").run(); + + // Checks that rustc's LTO doesn't emit any bitcode to the linker. + let stdout = rustc() + .input("main.rs") + .extern_("no_builtins", rust_lib_name("no_builtins")) + .lto("thin") + .print("link-args") + .arg("-Csave-temps") + .arg("-Clinker-features=-lld") + .run() + .stdout_utf8(); + for object in stdout + .split_whitespace() + .map(|s| s.trim_matches('"')) + .filter(|path| has_extension(path, "rlib") || has_extension(path, "o")) + { + let object_path = if !fs::exists(object).unwrap() { + cwd().join(object) + } else { + Path::new(object).to_path_buf() + }; + if has_extension(object, "rlib") { + let ar_stdout = llvm_ar().arg("t").arg(&object_path).run().stdout_utf8(); + llvm_ar().extract().arg(&object_path).run(); + for object in ar_stdout.split_whitespace().filter(|o| has_extension(o, "o")) { + let object_path = cwd().join(object); + not_bitcode(&object_path); + } + } else { + not_bitcode(&object_path); + } + } +} + +fn not_bitcode(object: &Path) { + llvm_bcanalyzer() + .input(object) + .run_fail() + .assert_stderr_contains("llvm-bcanalyzer: Invalid record at top-level"); +} From ba462864f1175690d1925cb5b1c6bf0a0c3cb579 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 10 Oct 2025 12:59:41 -0700 Subject: [PATCH 403/585] std: Use more `unix.rs` code on WASI targets This commit is a large change to the implementation of filesystem and other system-related operations on WASI targets. Previously the standard library explicitly used the `wasi` crate at the 0.11.x version track which means that it used WASIp1 APIs directly. This meant that `std` was hard-coded to use WASIp1 syscalls and there was no separate implementation for the WASIp{2,3} targets, for example. The high-level goal of this commit is to decouple this interaction and avoid the use of the `wasi` crate on the WASIp2 target. Historically when WASIp1 was originally added to Rust the wasi-libc library was in a much different position than it is today. Nowadays Rust already depends on wasi-libc on WASI targets for things like memory allocation and environment variable management. As a libc library it also has all the functions necessary to implement all filesystem operations Rust wants. Recently wasi-libc additionally was updated to use WASIp2 APIs directly on the `wasm32-wasip2` target instead of using `wasm32-wasip1` APIs. This commit is leveraging this work by enabling Rust to completely sever the dependence on WASIp1 APIs when compiling for `wasm32-wasip2`. This is also intended to make it easier to migrate to `wasm32-wasip3` internally in the future where now only libc need be updated and Rust doesn't need to explicitly change as well. The overall premise of this commit is that there's no need for WASI-specific implementation modules throughout the standard library. Instead the libc-style bindings already implemented for Unix-like targets are sufficient. This means that Rust will now be using libc-style interfaces to interact with the filesystem, for example, and wasi-libc is the one responsible for translating these POSIX-ish functions into WASIp{1,2} calls. Concrete changes here are: * `std` for `wasm32-wasip2` no longer depends on `wasi 0.11.x` * The implementation of `std::os::wasi::fs`, which was previously unstable and still is, now has portions gated to only work on the WASIp1 target which use the `wasi` crate directly. Traits have been trimmed down in some cases, updated in others, or now present a different API on WASIp1 and WASIp2. It's expected this'll get further cleanup in the future. * The `std::sys::fd::wasi` module is deleted and `unix` is used instead. * The `std::sys::fs::wasi` module is deleted and `unix` is used instead. * The `std::sys::io::io_slice::wasi` module is deleted and `unix` is used instead. * The `std::sys::pal::{wasip1,wasip2}` modules are now merged together as their difference is much smaller than before. * The `std::sys::pal::wasi::time` is deleted and the `unix` variant is used directly instead. * The `std::sys::stdio::wasip{1,2}` modules are deleted and the `unix` variant is used instead. * The `std::sys::thread::wasip{1,2}` modules are deleted and the `unix` variant is used instead. Overall Rust's libstd is effectively more tightly bound to libc when compiled to WASI targets. This is intended to mirror how it's expected all other languages will also bind to WASI. This additionally has the nice goal of drastically reducing the WASI-specific maintenance burden in libstd (in theory) and the only real changes required here are extra definitions being added to `libc` (done in separate PRs). This might be required for more symbols in the future but for now everything should be mostly complete. --- library/Cargo.lock | 4 +- library/std/Cargo.toml | 4 +- library/std/src/os/wasi/fs.rs | 310 ++---- library/std/src/os/wasi/net/mod.rs | 5 +- library/std/src/sys/fd/mod.rs | 6 +- library/std/src/sys/fd/unix.rs | 10 +- library/std/src/sys/fd/wasi.rs | 331 ------- library/std/src/sys/fs/mod.rs | 12 +- library/std/src/sys/fs/unix.rs | 55 +- library/std/src/sys/fs/wasi.rs | 913 ------------------ library/std/src/sys/io/io_slice/iovec.rs | 2 +- library/std/src/sys/io/io_slice/wasi.rs | 76 -- library/std/src/sys/io/mod.rs | 6 +- .../std/src/sys/net/connection/socket/mod.rs | 6 +- .../std/src/sys/net/connection/socket/unix.rs | 6 +- .../src/sys/net/connection/socket/wasip2.rs | 408 -------- library/std/src/sys/net/connection/wasip1.rs | 20 +- library/std/src/sys/pal/mod.rs | 10 +- library/std/src/sys/pal/unix/time.rs | 7 + .../sys/pal/{wasip2 => wasi}/cabi_realloc.rs | 0 library/std/src/sys/pal/wasi/helpers.rs | 63 ++ library/std/src/sys/pal/wasi/mod.rs | 39 + .../std/src/sys/pal/{wasip1 => wasi}/os.rs | 32 +- .../std/src/sys/pal/wasi/stack_overflow.rs | 7 + library/std/src/sys/pal/wasip1/helpers.rs | 114 --- library/std/src/sys/pal/wasip1/mod.rs | 38 - library/std/src/sys/pal/wasip1/time.rs | 65 -- library/std/src/sys/pal/wasip2/mod.rs | 35 - library/std/src/sys/pal/wasip2/time.rs | 58 -- library/std/src/sys/stdio/mod.rs | 10 +- library/std/src/sys/stdio/unix.rs | 7 +- library/std/src/sys/stdio/wasip1.rs | 117 --- library/std/src/sys/stdio/wasip2.rs | 120 --- library/std/src/sys/thread/mod.rs | 28 +- library/std/src/sys/thread/unix.rs | 3 + library/std/src/sys/thread/wasip1.rs | 183 ---- library/std/src/sys/thread/wasip2.rs | 32 - tests/rustdoc-js-std/unbox-type-result.js | 1 - triagebot.toml | 3 +- 39 files changed, 343 insertions(+), 2803 deletions(-) delete mode 100644 library/std/src/sys/fd/wasi.rs delete mode 100644 library/std/src/sys/fs/wasi.rs delete mode 100644 library/std/src/sys/io/io_slice/wasi.rs delete mode 100644 library/std/src/sys/net/connection/socket/wasip2.rs rename library/std/src/sys/pal/{wasip2 => wasi}/cabi_realloc.rs (100%) create mode 100644 library/std/src/sys/pal/wasi/helpers.rs create mode 100644 library/std/src/sys/pal/wasi/mod.rs rename library/std/src/sys/pal/{wasip1 => wasi}/os.rs (88%) create mode 100644 library/std/src/sys/pal/wasi/stack_overflow.rs delete mode 100644 library/std/src/sys/pal/wasip1/helpers.rs delete mode 100644 library/std/src/sys/pal/wasip1/mod.rs delete mode 100644 library/std/src/sys/pal/wasip1/time.rs delete mode 100644 library/std/src/sys/pal/wasip2/mod.rs delete mode 100644 library/std/src/sys/pal/wasip2/time.rs delete mode 100644 library/std/src/sys/stdio/wasip1.rs delete mode 100644 library/std/src/sys/stdio/wasip2.rs delete mode 100644 library/std/src/sys/thread/wasip1.rs delete mode 100644 library/std/src/sys/thread/wasip2.rs diff --git a/library/Cargo.lock b/library/Cargo.lock index accbbe9d236f..513d3f136698 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -146,9 +146,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.177" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" dependencies = [ "rustc-std-workspace-core", ] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 3a673cf23b83..83a0826ac425 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -33,7 +33,7 @@ miniz_oxide = { version = "0.8.0", optional = true, default-features = false } addr2line = { version = "0.25.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] -libc = { version = "0.2.177", default-features = false, features = [ +libc = { version = "0.2.178", default-features = false, features = [ 'rustc-dep-of-std', ], public = true } @@ -78,7 +78,7 @@ hermit-abi = { version = "0.5.0", features = [ 'rustc-dep-of-std', ], public = true } -[target.'cfg(target_os = "wasi")'.dependencies] +[target.'cfg(all(target_os = "wasi", target_env = "p1"))'.dependencies] wasi = { version = "0.11.0", features = [ 'rustc-dep-of-std', ], default-features = false } diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index 5ea91dd6521a..9145283dae6e 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -1,4 +1,4 @@ -//! WASI-specific extensions to primitives in the [`std::fs`] module. +//! WASIp1-specific extensions to primitives in the [`std::fs`] module. //! //! [`std::fs`]: crate::fs @@ -8,11 +8,16 @@ #[allow(unused_imports)] use io::{Read, Write}; +#[cfg(target_env = "p1")] use crate::ffi::OsStr; -use crate::fs::{self, File, Metadata, OpenOptions}; -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::path::{Path, PathBuf}; -use crate::sys_common::{AsInner, AsInnerMut, FromInner}; +use crate::fs::{self, File, OpenOptions}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; +#[cfg(target_env = "p1")] +use crate::os::fd::AsRawFd; +use crate::path::Path; +#[cfg(target_env = "p1")] +use crate::sys::err2io; +use crate::sys_common::{AsInner, AsInnerMut}; /// WASI-specific extensions to [`File`]. pub trait FileExt { @@ -27,10 +32,7 @@ pub trait FileExt { /// /// Note that similar to [`File::read`], it is not an error to return with a /// short read. - fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { - let bufs = &mut [IoSliceMut::new(buf)]; - self.read_vectored_at(bufs, offset) - } + fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result; /// Reads a number of bytes starting from a given offset. /// @@ -45,6 +47,13 @@ fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { /// return with a short read. fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result; + /// Reads some bytes starting from a given offset into the buffer. + /// + /// This equivalent to the [`read_at`](FileExt::read_at) method, except that it is passed a + /// [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized buffers. The new + /// data will be appended to any existing contents of `buf`. + fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()>; + /// Reads the exact number of byte required to fill `buf` from the given offset. /// /// The offset is relative to the start of the file and thus independent @@ -102,10 +111,7 @@ fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { /// /// Note that similar to [`File::write`], it is not an error to return a /// short write. - fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { - let bufs = &[IoSlice::new(buf)]; - self.write_vectored_at(bufs, offset) - } + fn write_at(&self, buf: &[u8], offset: u64) -> io::Result; /// Writes a number of bytes starting from a given offset. /// @@ -164,54 +170,49 @@ fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { /// /// This corresponds to the `fd_fdstat_set_flags` syscall. #[doc(alias = "fd_fdstat_set_flags")] + #[cfg(target_env = "p1")] fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>; /// Adjusts the rights associated with this file. /// /// This corresponds to the `fd_fdstat_set_rights` syscall. #[doc(alias = "fd_fdstat_set_rights")] + #[cfg(target_env = "p1")] fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>; /// Provides file advisory information on a file descriptor. /// /// This corresponds to the `fd_advise` syscall. #[doc(alias = "fd_advise")] + #[cfg(target_env = "p1")] fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>; /// Forces the allocation of space in a file. /// /// This corresponds to the `fd_allocate` syscall. #[doc(alias = "fd_allocate")] + #[cfg(target_env = "p1")] fn allocate(&self, offset: u64, len: u64) -> io::Result<()>; /// Creates a directory. /// /// This corresponds to the `path_create_directory` syscall. #[doc(alias = "path_create_directory")] + #[cfg(target_env = "p1")] fn create_directory>(&self, dir: P) -> io::Result<()>; - /// Reads the contents of a symbolic link. - /// - /// This corresponds to the `path_readlink` syscall. - #[doc(alias = "path_readlink")] - fn read_link>(&self, path: P) -> io::Result; - - /// Returns the attributes of a file or directory. - /// - /// This corresponds to the `path_filestat_get` syscall. - #[doc(alias = "path_filestat_get")] - fn metadata_at>(&self, lookup_flags: u32, path: P) -> io::Result; - /// Unlinks a file. /// /// This corresponds to the `path_unlink_file` syscall. #[doc(alias = "path_unlink_file")] + #[cfg(target_env = "p1")] fn remove_file>(&self, path: P) -> io::Result<()>; /// Removes a directory. /// /// This corresponds to the `path_remove_directory` syscall. #[doc(alias = "path_remove_directory")] + #[cfg(target_env = "p1")] fn remove_directory>(&self, path: P) -> io::Result<()>; } @@ -222,23 +223,41 @@ fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { // FIXME: bind poll_oneoff maybe? - probably should wait for I/O to settle // FIXME: bind random_get maybe? - on crates.io for unix -impl FileExt for fs::File { +impl FileExt for File { + fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { + self.as_inner().read_at(buf, offset) + } + + fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + self.as_inner().read_buf_at(buf, offset) + } + fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - self.as_inner().as_inner().pread(bufs, offset) + self.as_inner().read_vectored_at(bufs, offset) + } + + fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { + self.as_inner().write_at(buf, offset) } fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - self.as_inner().as_inner().pwrite(bufs, offset) + self.as_inner().write_vectored_at(bufs, offset) } + #[cfg(target_env = "p1")] fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> { - self.as_inner().as_inner().set_flags(flags) + unsafe { wasi::fd_fdstat_set_flags(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) } } + #[cfg(target_env = "p1")] fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()> { - self.as_inner().as_inner().set_rights(rights, inheriting) + unsafe { + wasi::fd_fdstat_set_rights(self.as_raw_fd() as wasi::Fd, rights, inheriting) + .map_err(err2io) + } } + #[cfg(target_env = "p1")] fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> { let advice = match advice { a if a == wasi::ADVICE_NORMAL.raw() => wasi::ADVICE_NORMAL, @@ -255,149 +274,46 @@ fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> { } }; - self.as_inner().as_inner().advise(offset, len, advice) + unsafe { + wasi::fd_advise(self.as_raw_fd() as wasi::Fd, offset, len, advice).map_err(err2io) + } } + #[cfg(target_env = "p1")] fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { - self.as_inner().as_inner().allocate(offset, len) + unsafe { wasi::fd_allocate(self.as_raw_fd() as wasi::Fd, offset, len).map_err(err2io) } } + #[cfg(target_env = "p1")] fn create_directory>(&self, dir: P) -> io::Result<()> { - self.as_inner().as_inner().create_directory(osstr2str(dir.as_ref().as_ref())?) - } - - fn read_link>(&self, path: P) -> io::Result { - self.as_inner().read_link(path.as_ref()) - } - - fn metadata_at>(&self, lookup_flags: u32, path: P) -> io::Result { - let m = self.as_inner().metadata_at(lookup_flags, path.as_ref())?; - Ok(FromInner::from_inner(m)) + let path = osstr2str(dir.as_ref().as_ref())?; + unsafe { wasi::path_create_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) } } + #[cfg(target_env = "p1")] fn remove_file>(&self, path: P) -> io::Result<()> { - self.as_inner().as_inner().unlink_file(osstr2str(path.as_ref().as_ref())?) + let path = osstr2str(path.as_ref().as_ref())?; + unsafe { wasi::path_unlink_file(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) } } + #[cfg(target_env = "p1")] fn remove_directory>(&self, path: P) -> io::Result<()> { - self.as_inner().as_inner().remove_directory(osstr2str(path.as_ref().as_ref())?) + let path = osstr2str(path.as_ref().as_ref())?; + unsafe { wasi::path_remove_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) } } } -/// WASI-specific extensions to [`fs::OpenOptions`]. +/// WASI-specific extensions to [`OpenOptions`]. pub trait OpenOptionsExt { - /// Pass custom `dirflags` argument to `path_open`. - /// - /// This option configures the `dirflags` argument to the - /// `path_open` syscall which `OpenOptions` will eventually call. The - /// `dirflags` argument configures how the file is looked up, currently - /// primarily affecting whether symlinks are followed or not. - /// - /// By default this value is `__WASI_LOOKUP_SYMLINK_FOLLOW`, or symlinks are - /// followed. You can call this method with 0 to disable following symlinks - fn lookup_flags(&mut self, flags: u32) -> &mut Self; - - /// Indicates whether `OpenOptions` must open a directory or not. - /// - /// This method will configure whether the `__WASI_O_DIRECTORY` flag is - /// passed when opening a file. When passed it will require that the opened - /// path is a directory. - /// - /// This option is by default `false` - fn directory(&mut self, dir: bool) -> &mut Self; - - /// Indicates whether `__WASI_FDFLAG_DSYNC` is passed in the `fs_flags` - /// field of `path_open`. - /// - /// This option is by default `false` - fn dsync(&mut self, dsync: bool) -> &mut Self; - - /// Indicates whether `__WASI_FDFLAG_NONBLOCK` is passed in the `fs_flags` - /// field of `path_open`. - /// - /// This option is by default `false` - fn nonblock(&mut self, nonblock: bool) -> &mut Self; - - /// Indicates whether `__WASI_FDFLAG_RSYNC` is passed in the `fs_flags` - /// field of `path_open`. - /// - /// This option is by default `false` - fn rsync(&mut self, rsync: bool) -> &mut Self; - - /// Indicates whether `__WASI_FDFLAG_SYNC` is passed in the `fs_flags` - /// field of `path_open`. - /// - /// This option is by default `false` - fn sync(&mut self, sync: bool) -> &mut Self; - - /// Indicates the value that should be passed in for the `fs_rights_base` - /// parameter of `path_open`. - /// - /// This option defaults based on the `read` and `write` configuration of - /// this `OpenOptions` builder. If this method is called, however, the - /// exact mask passed in will be used instead. - fn fs_rights_base(&mut self, rights: u64) -> &mut Self; - - /// Indicates the value that should be passed in for the - /// `fs_rights_inheriting` parameter of `path_open`. - /// - /// The default for this option is the same value as what will be passed - /// for the `fs_rights_base` parameter but if this method is called then - /// the specified value will be used instead. - fn fs_rights_inheriting(&mut self, rights: u64) -> &mut Self; - - /// Open a file or directory. - /// - /// This corresponds to the `path_open` syscall. - #[doc(alias = "path_open")] - fn open_at>(&self, file: &File, path: P) -> io::Result; + /// Pass custom flags to the `flags` argument of `open`. + fn custom_flags(&mut self, flags: i32) -> &mut Self; } impl OpenOptionsExt for OpenOptions { - fn lookup_flags(&mut self, flags: u32) -> &mut OpenOptions { - self.as_inner_mut().lookup_flags(flags); + fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { + self.as_inner_mut().custom_flags(flags); self } - - fn directory(&mut self, dir: bool) -> &mut OpenOptions { - self.as_inner_mut().directory(dir); - self - } - - fn dsync(&mut self, enabled: bool) -> &mut OpenOptions { - self.as_inner_mut().dsync(enabled); - self - } - - fn nonblock(&mut self, enabled: bool) -> &mut OpenOptions { - self.as_inner_mut().nonblock(enabled); - self - } - - fn rsync(&mut self, enabled: bool) -> &mut OpenOptions { - self.as_inner_mut().rsync(enabled); - self - } - - fn sync(&mut self, enabled: bool) -> &mut OpenOptions { - self.as_inner_mut().sync(enabled); - self - } - - fn fs_rights_base(&mut self, rights: u64) -> &mut OpenOptions { - self.as_inner_mut().fs_rights_base(rights); - self - } - - fn fs_rights_inheriting(&mut self, rights: u64) -> &mut OpenOptions { - self.as_inner_mut().fs_rights_inheriting(rights); - self - } - - fn open_at>(&self, file: &File, path: P) -> io::Result { - let inner = file.as_inner().open_at(path.as_ref(), self.as_inner())?; - Ok(File::from_inner(inner)) - } } /// WASI-specific extensions to [`fs::Metadata`]. @@ -408,37 +324,17 @@ pub trait MetadataExt { fn ino(&self) -> u64; /// Returns the `st_nlink` field of the internal `filestat_t` fn nlink(&self) -> u64; - /// Returns the `st_size` field of the internal `filestat_t` - fn size(&self) -> u64; - /// Returns the `st_atim` field of the internal `filestat_t` - fn atim(&self) -> u64; - /// Returns the `st_mtim` field of the internal `filestat_t` - fn mtim(&self) -> u64; - /// Returns the `st_ctim` field of the internal `filestat_t` - fn ctim(&self) -> u64; } impl MetadataExt for fs::Metadata { fn dev(&self) -> u64 { - self.as_inner().as_wasi().dev + self.as_inner().as_inner().st_dev } fn ino(&self) -> u64 { - self.as_inner().as_wasi().ino + self.as_inner().as_inner().st_ino } fn nlink(&self) -> u64 { - self.as_inner().as_wasi().nlink - } - fn size(&self) -> u64 { - self.as_inner().as_wasi().size - } - fn atim(&self) -> u64 { - self.as_inner().as_wasi().atim - } - fn mtim(&self) -> u64 { - self.as_inner().as_wasi().mtim - } - fn ctim(&self) -> u64 { - self.as_inner().as_wasi().ctim + self.as_inner().as_inner().st_nlink } } @@ -451,28 +347,19 @@ pub trait FileTypeExt { fn is_block_device(&self) -> bool; /// Returns `true` if this file type is a character device. fn is_char_device(&self) -> bool; - /// Returns `true` if this file type is a socket datagram. - fn is_socket_dgram(&self) -> bool; - /// Returns `true` if this file type is a socket stream. - fn is_socket_stream(&self) -> bool; /// Returns `true` if this file type is any type of socket. - fn is_socket(&self) -> bool { - self.is_socket_stream() || self.is_socket_dgram() - } + fn is_socket(&self) -> bool; } impl FileTypeExt for fs::FileType { fn is_block_device(&self) -> bool { - self.as_inner().bits() == wasi::FILETYPE_BLOCK_DEVICE + self.as_inner().is(libc::S_IFBLK) } fn is_char_device(&self) -> bool { - self.as_inner().bits() == wasi::FILETYPE_CHARACTER_DEVICE + self.as_inner().is(libc::S_IFCHR) } - fn is_socket_dgram(&self) -> bool { - self.as_inner().bits() == wasi::FILETYPE_SOCKET_DGRAM - } - fn is_socket_stream(&self) -> bool { - self.as_inner().bits() == wasi::FILETYPE_SOCKET_STREAM + fn is_socket(&self) -> bool { + self.as_inner().is(libc::S_IFSOCK) } } @@ -492,6 +379,7 @@ fn ino(&self) -> u64 { /// /// This corresponds to the `path_link` syscall. #[doc(alias = "path_link")] +#[cfg(target_env = "p1")] pub fn link, U: AsRef>( old_fd: &File, old_flags: u32, @@ -499,43 +387,58 @@ pub fn link, U: AsRef>( new_fd: &File, new_path: U, ) -> io::Result<()> { - old_fd.as_inner().as_inner().link( - old_flags, - osstr2str(old_path.as_ref().as_ref())?, - new_fd.as_inner().as_inner(), - osstr2str(new_path.as_ref().as_ref())?, - ) + unsafe { + wasi::path_link( + old_fd.as_raw_fd() as wasi::Fd, + old_flags, + osstr2str(old_path.as_ref().as_ref())?, + new_fd.as_raw_fd() as wasi::Fd, + osstr2str(new_path.as_ref().as_ref())?, + ) + .map_err(err2io) + } } /// Renames a file or directory. /// /// This corresponds to the `path_rename` syscall. #[doc(alias = "path_rename")] +#[cfg(target_env = "p1")] pub fn rename, U: AsRef>( old_fd: &File, old_path: P, new_fd: &File, new_path: U, ) -> io::Result<()> { - old_fd.as_inner().as_inner().rename( - osstr2str(old_path.as_ref().as_ref())?, - new_fd.as_inner().as_inner(), - osstr2str(new_path.as_ref().as_ref())?, - ) + unsafe { + wasi::path_rename( + old_fd.as_raw_fd() as wasi::Fd, + osstr2str(old_path.as_ref().as_ref())?, + new_fd.as_raw_fd() as wasi::Fd, + osstr2str(new_path.as_ref().as_ref())?, + ) + .map_err(err2io) + } } /// Creates a symbolic link. /// /// This corresponds to the `path_symlink` syscall. #[doc(alias = "path_symlink")] +#[cfg(target_env = "p1")] pub fn symlink, U: AsRef>( old_path: P, fd: &File, new_path: U, ) -> io::Result<()> { - fd.as_inner() - .as_inner() - .symlink(osstr2str(old_path.as_ref().as_ref())?, osstr2str(new_path.as_ref().as_ref())?) + unsafe { + wasi::path_symlink( + osstr2str(old_path.as_ref().as_ref())?, + fd.as_raw_fd() as wasi::Fd, + osstr2str(new_path.as_ref().as_ref())?, + ) + .map_err(err2io) + } } /// Creates a symbolic link. @@ -546,6 +449,7 @@ pub fn symlink_path, U: AsRef>(old_path: P, new_path: U) -> crate::sys::fs::symlink(old_path.as_ref(), new_path.as_ref()) } +#[cfg(target_env = "p1")] fn osstr2str(f: &OsStr) -> io::Result<&str> { f.to_str().ok_or_else(|| io::const_error!(io::ErrorKind::Uncategorized, "input must be utf-8")) } diff --git a/library/std/src/os/wasi/net/mod.rs b/library/std/src/os/wasi/net/mod.rs index 4704dd574517..9430cd3b05ee 100644 --- a/library/std/src/os/wasi/net/mod.rs +++ b/library/std/src/os/wasi/net/mod.rs @@ -2,7 +2,8 @@ #![unstable(feature = "wasi_ext", issue = "71213")] -use crate::sys_common::AsInner; +use crate::os::fd::AsRawFd; +use crate::sys::err2io; use crate::{io, net}; /// WASI-specific extensions to [`std::net::TcpListener`]. @@ -17,6 +18,6 @@ pub trait TcpListenerExt { impl TcpListenerExt for net::TcpListener { fn sock_accept(&self, flags: u16) -> io::Result { - self.as_inner().as_inner().as_inner().sock_accept(flags) + unsafe { wasi::sock_accept(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) } } } diff --git a/library/std/src/sys/fd/mod.rs b/library/std/src/sys/fd/mod.rs index 330499ecc18f..02d61a62f4e6 100644 --- a/library/std/src/sys/fd/mod.rs +++ b/library/std/src/sys/fd/mod.rs @@ -3,7 +3,7 @@ #![forbid(unsafe_op_in_unsafe_fn)] cfg_select! { - target_family = "unix" => { + any(target_family = "unix", target_os = "wasi") => { mod unix; pub use unix::*; } @@ -19,9 +19,5 @@ mod sgx; pub use sgx::*; } - target_os = "wasi" => { - mod wasi; - pub use wasi::*; - } _ => {} } diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index a631e1d91393..33fff36b35b0 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -35,7 +35,7 @@ use crate::cmp; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; -use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::sys::cvt; #[cfg(all(target_os = "android", target_pointer_width = "64"))] use crate::sys::pal::weak::syscall; @@ -152,7 +152,8 @@ pub fn is_read_vectored(&self) -> bool { target_os = "espidf", target_os = "horizon", target_os = "vita", - target_os = "nuttx" + target_os = "nuttx", + target_os = "wasi", ))) } @@ -385,7 +386,8 @@ pub fn is_write_vectored(&self) -> bool { target_os = "espidf", target_os = "horizon", target_os = "vita", - target_os = "nuttx" + target_os = "nuttx", + target_os = "wasi", ))) } @@ -560,6 +562,7 @@ fn pwritev( target_os = "redox", target_os = "vxworks", target_os = "nto", + target_os = "wasi", )))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { @@ -583,6 +586,7 @@ pub fn set_cloexec(&self) -> io::Result<()> { target_os = "redox", target_os = "vxworks", target_os = "nto", + target_os = "wasi", ))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { diff --git a/library/std/src/sys/fd/wasi.rs b/library/std/src/sys/fd/wasi.rs deleted file mode 100644 index a468b31168af..000000000000 --- a/library/std/src/sys/fd/wasi.rs +++ /dev/null @@ -1,331 +0,0 @@ -#![expect(dead_code)] - -use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; -use crate::mem; -use crate::net::Shutdown; -use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; -use crate::sys::pal::err2io; -use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; - -#[derive(Debug)] -pub struct WasiFd { - fd: OwnedFd, -} - -fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] { - assert_eq!(size_of::>(), size_of::()); - assert_eq!(align_of::>(), align_of::()); - // SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout. - // We decorate our `IoSliceMut` with `repr(transparent)` (see `io.rs`), and - // `crate::io::IoSliceMut` is a `repr(transparent)` wrapper around our type, so this is - // guaranteed. - unsafe { mem::transmute(a) } -} - -fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] { - assert_eq!(size_of::>(), size_of::()); - assert_eq!(align_of::>(), align_of::()); - // SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout. - // We decorate our `IoSlice` with `repr(transparent)` (see `io.rs`), and - // `crate::io::IoSlice` is a `repr(transparent)` wrapper around our type, so this is - // guaranteed. - unsafe { mem::transmute(a) } -} - -impl WasiFd { - pub fn datasync(&self) -> io::Result<()> { - unsafe { wasi::fd_datasync(self.as_raw_fd() as wasi::Fd).map_err(err2io) } - } - - pub fn pread(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - unsafe { wasi::fd_pread(self.as_raw_fd() as wasi::Fd, iovec(bufs), offset).map_err(err2io) } - } - - pub fn pwrite(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - unsafe { - wasi::fd_pwrite(self.as_raw_fd() as wasi::Fd, ciovec(bufs), offset).map_err(err2io) - } - } - - pub fn read(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - unsafe { wasi::fd_read(self.as_raw_fd() as wasi::Fd, iovec(bufs)).map_err(err2io) } - } - - pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { - unsafe { - let bufs = [wasi::Iovec { - buf: buf.as_mut().as_mut_ptr() as *mut u8, - buf_len: buf.capacity(), - }]; - match wasi::fd_read(self.as_raw_fd() as wasi::Fd, &bufs) { - Ok(n) => { - buf.advance(n); - Ok(()) - } - Err(e) => Err(err2io(e)), - } - } - } - - pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result { - unsafe { wasi::fd_write(self.as_raw_fd() as wasi::Fd, ciovec(bufs)).map_err(err2io) } - } - - pub fn seek(&self, pos: SeekFrom) -> io::Result { - let (whence, offset) = match pos { - SeekFrom::Start(pos) => (wasi::WHENCE_SET, pos as i64), - SeekFrom::End(pos) => (wasi::WHENCE_END, pos), - SeekFrom::Current(pos) => (wasi::WHENCE_CUR, pos), - }; - unsafe { wasi::fd_seek(self.as_raw_fd() as wasi::Fd, offset, whence).map_err(err2io) } - } - - pub fn tell(&self) -> io::Result { - unsafe { wasi::fd_tell(self.as_raw_fd() as wasi::Fd).map_err(err2io) } - } - - // FIXME: __wasi_fd_fdstat_get - - pub fn set_flags(&self, flags: wasi::Fdflags) -> io::Result<()> { - unsafe { wasi::fd_fdstat_set_flags(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) } - } - - pub fn set_rights(&self, base: wasi::Rights, inheriting: wasi::Rights) -> io::Result<()> { - unsafe { - wasi::fd_fdstat_set_rights(self.as_raw_fd() as wasi::Fd, base, inheriting) - .map_err(err2io) - } - } - - pub fn sync(&self) -> io::Result<()> { - unsafe { wasi::fd_sync(self.as_raw_fd() as wasi::Fd).map_err(err2io) } - } - - pub(crate) fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> { - unsafe { - wasi::fd_advise(self.as_raw_fd() as wasi::Fd, offset, len, advice).map_err(err2io) - } - } - - pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { - unsafe { wasi::fd_allocate(self.as_raw_fd() as wasi::Fd, offset, len).map_err(err2io) } - } - - pub fn create_directory(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_create_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) } - } - - pub fn link( - &self, - old_flags: wasi::Lookupflags, - old_path: &str, - new_fd: &WasiFd, - new_path: &str, - ) -> io::Result<()> { - unsafe { - wasi::path_link( - self.as_raw_fd() as wasi::Fd, - old_flags, - old_path, - new_fd.as_raw_fd() as wasi::Fd, - new_path, - ) - .map_err(err2io) - } - } - - pub fn open( - &self, - dirflags: wasi::Lookupflags, - path: &str, - oflags: wasi::Oflags, - fs_rights_base: wasi::Rights, - fs_rights_inheriting: wasi::Rights, - fs_flags: wasi::Fdflags, - ) -> io::Result { - unsafe { - wasi::path_open( - self.as_raw_fd() as wasi::Fd, - dirflags, - path, - oflags, - fs_rights_base, - fs_rights_inheriting, - fs_flags, - ) - .map(|fd| WasiFd::from_raw_fd(fd as RawFd)) - .map_err(err2io) - } - } - - pub fn readdir(&self, buf: &mut [u8], cookie: wasi::Dircookie) -> io::Result { - unsafe { - wasi::fd_readdir(self.as_raw_fd() as wasi::Fd, buf.as_mut_ptr(), buf.len(), cookie) - .map_err(err2io) - } - } - - pub fn readlink(&self, path: &str, buf: &mut [u8]) -> io::Result { - unsafe { - wasi::path_readlink(self.as_raw_fd() as wasi::Fd, path, buf.as_mut_ptr(), buf.len()) - .map_err(err2io) - } - } - - pub fn rename(&self, old_path: &str, new_fd: &WasiFd, new_path: &str) -> io::Result<()> { - unsafe { - wasi::path_rename( - self.as_raw_fd() as wasi::Fd, - old_path, - new_fd.as_raw_fd() as wasi::Fd, - new_path, - ) - .map_err(err2io) - } - } - - pub(crate) fn filestat_get(&self) -> io::Result { - unsafe { wasi::fd_filestat_get(self.as_raw_fd() as wasi::Fd).map_err(err2io) } - } - - pub fn filestat_set_times( - &self, - atim: wasi::Timestamp, - mtim: wasi::Timestamp, - fstflags: wasi::Fstflags, - ) -> io::Result<()> { - unsafe { - wasi::fd_filestat_set_times(self.as_raw_fd() as wasi::Fd, atim, mtim, fstflags) - .map_err(err2io) - } - } - - pub fn filestat_set_size(&self, size: u64) -> io::Result<()> { - unsafe { wasi::fd_filestat_set_size(self.as_raw_fd() as wasi::Fd, size).map_err(err2io) } - } - - pub(crate) fn path_filestat_get( - &self, - flags: wasi::Lookupflags, - path: &str, - ) -> io::Result { - unsafe { - wasi::path_filestat_get(self.as_raw_fd() as wasi::Fd, flags, path).map_err(err2io) - } - } - - pub fn path_filestat_set_times( - &self, - flags: wasi::Lookupflags, - path: &str, - atim: wasi::Timestamp, - mtim: wasi::Timestamp, - fstflags: wasi::Fstflags, - ) -> io::Result<()> { - unsafe { - wasi::path_filestat_set_times( - self.as_raw_fd() as wasi::Fd, - flags, - path, - atim, - mtim, - fstflags, - ) - .map_err(err2io) - } - } - - pub fn symlink(&self, old_path: &str, new_path: &str) -> io::Result<()> { - unsafe { - wasi::path_symlink(old_path, self.as_raw_fd() as wasi::Fd, new_path).map_err(err2io) - } - } - - pub fn unlink_file(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_unlink_file(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) } - } - - pub fn remove_directory(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_remove_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) } - } - - pub fn sock_accept(&self, flags: wasi::Fdflags) -> io::Result { - unsafe { wasi::sock_accept(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) } - } - - pub fn sock_recv( - &self, - ri_data: &mut [IoSliceMut<'_>], - ri_flags: wasi::Riflags, - ) -> io::Result<(usize, wasi::Roflags)> { - unsafe { - wasi::sock_recv(self.as_raw_fd() as wasi::Fd, iovec(ri_data), ri_flags).map_err(err2io) - } - } - - pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::Siflags) -> io::Result { - unsafe { - wasi::sock_send(self.as_raw_fd() as wasi::Fd, ciovec(si_data), si_flags).map_err(err2io) - } - } - - pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> { - let how = match how { - Shutdown::Read => wasi::SDFLAGS_RD, - Shutdown::Write => wasi::SDFLAGS_WR, - Shutdown::Both => wasi::SDFLAGS_WR | wasi::SDFLAGS_RD, - }; - unsafe { wasi::sock_shutdown(self.as_raw_fd() as wasi::Fd, how).map_err(err2io) } - } -} - -impl AsInner for WasiFd { - #[inline] - fn as_inner(&self) -> &OwnedFd { - &self.fd - } -} - -impl AsInnerMut for WasiFd { - #[inline] - fn as_inner_mut(&mut self) -> &mut OwnedFd { - &mut self.fd - } -} - -impl IntoInner for WasiFd { - fn into_inner(self) -> OwnedFd { - self.fd - } -} - -impl FromInner for WasiFd { - fn from_inner(owned_fd: OwnedFd) -> Self { - Self { fd: owned_fd } - } -} - -impl AsFd for WasiFd { - fn as_fd(&self) -> BorrowedFd<'_> { - self.fd.as_fd() - } -} - -impl AsRawFd for WasiFd { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.fd.as_raw_fd() - } -} - -impl IntoRawFd for WasiFd { - fn into_raw_fd(self) -> RawFd { - self.fd.into_raw_fd() - } -} - -impl FromRawFd for WasiFd { - unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { - unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } } - } -} diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index eaea28871241..4a66227ce5f4 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -6,12 +6,14 @@ pub mod common; cfg_select! { - target_family = "unix" => { + any(target_family = "unix", target_os = "wasi") => { mod unix; use unix as imp; + #[cfg(not(target_os = "wasi"))] pub use unix::{chown, fchown, lchown, mkfifo}; - #[cfg(not(target_os = "fuchsia"))] + #[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] pub use unix::chroot; + #[cfg(not(target_os = "wasi"))] pub(crate) use unix::debug_assert_fd_is_open; #[cfg(any(target_os = "linux", target_os = "android"))] pub(super) use unix::CachedFileMetadata; @@ -43,10 +45,6 @@ mod vexos; use vexos as imp; } - target_os = "wasi" => { - mod wasi; - use wasi as imp; - } _ => { mod unsupported; use unsupported as imp; @@ -54,7 +52,7 @@ } // FIXME: Replace this with platform-specific path conversion functions. -#[cfg(not(any(target_family = "unix", target_os = "windows")))] +#[cfg(not(any(target_family = "unix", target_os = "windows", target_os = "wasi")))] #[inline] pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> io::Result { f(path) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 47d9ee226653..507d093d2b2f 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -31,6 +31,7 @@ target_os = "redox", target_os = "solaris", target_os = "vita", + target_os = "wasi", all(target_os = "linux", target_env = "musl"), ))] use libc::readdir as readdir64; @@ -47,6 +48,7 @@ target_os = "redox", target_os = "solaris", target_os = "vita", + target_os = "wasi", )))] use libc::readdir_r as readdir64_r; #[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))] @@ -80,8 +82,11 @@ use crate::fmt::{self, Write as _}; use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; -use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; +use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; +#[cfg(target_family = "unix")] use crate::os::unix::prelude::*; +#[cfg(target_os = "wasi")] +use crate::os::wasi::prelude::*; use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::common::small_c_string::run_path_with_cstr; @@ -285,6 +290,7 @@ unsafe impl Sync for Dir {} target_os = "redox", target_os = "solaris", target_os = "vita", + target_os = "wasi", ))] pub struct DirEntry { dir: Arc, @@ -310,6 +316,7 @@ pub struct DirEntry { target_os = "redox", target_os = "solaris", target_os = "vita", + target_os = "wasi", ))] struct dirent64_min { d_ino: u64, @@ -335,6 +342,7 @@ struct dirent64_min { target_os = "redox", target_os = "solaris", target_os = "vita", + target_os = "wasi", )))] pub struct DirEntry { dir: Arc, @@ -480,7 +488,7 @@ pub fn created(&self) -> io::Result { } } -#[cfg(not(any(target_os = "netbsd", target_os = "nto", target_os = "aix")))] +#[cfg(not(any(target_os = "netbsd", target_os = "nto", target_os = "aix", target_os = "wasi")))] impl FileAttr { #[cfg(not(any( target_os = "vxworks", @@ -595,18 +603,18 @@ pub fn created(&self) -> io::Result { } } -#[cfg(target_os = "nto")] +#[cfg(any(target_os = "nto", target_os = "wasi"))] impl FileAttr { pub fn modified(&self) -> io::Result { - SystemTime::new(self.stat.st_mtim.tv_sec, self.stat.st_mtim.tv_nsec) + SystemTime::new(self.stat.st_mtim.tv_sec, self.stat.st_mtim.tv_nsec.into()) } pub fn accessed(&self) -> io::Result { - SystemTime::new(self.stat.st_atim.tv_sec, self.stat.st_atim.tv_nsec) + SystemTime::new(self.stat.st_atim.tv_sec, self.stat.st_atim.tv_nsec.into()) } pub fn created(&self) -> io::Result { - SystemTime::new(self.stat.st_ctim.tv_sec, self.stat.st_ctim.tv_nsec) + SystemTime::new(self.stat.st_ctim.tv_sec, self.stat.st_ctim.tv_nsec.into()) } } @@ -632,6 +640,7 @@ pub fn set_readonly(&mut self, readonly: bool) { self.mode |= 0o222; } } + #[cfg(not(target_os = "wasi"))] pub fn mode(&self) -> u32 { self.mode as u32 } @@ -715,6 +724,7 @@ impl Iterator for ReadDir { target_os = "redox", target_os = "solaris", target_os = "vita", + target_os = "wasi", ))] fn next(&mut self) -> Option> { use crate::sys::os::{errno, set_errno}; @@ -812,6 +822,7 @@ fn next(&mut self) -> Option> { target_os = "redox", target_os = "solaris", target_os = "vita", + target_os = "wasi", )))] fn next(&mut self) -> Option> { if self.end_of_stream { @@ -1002,6 +1013,7 @@ pub fn file_type(&self) -> io::Result { target_os = "solaris", target_os = "vita", target_os = "vxworks", + target_os = "wasi", target_vendor = "apple", ))] pub fn ino(&self) -> u64 { @@ -1057,6 +1069,7 @@ fn name_bytes(&self) -> &[u8] { target_os = "nto", target_os = "vita", target_os = "hurd", + target_os = "wasi", )))] fn name_cstr(&self) -> &CStr { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) } @@ -1073,6 +1086,7 @@ fn name_cstr(&self) -> &CStr { target_os = "nto", target_os = "vita", target_os = "hurd", + target_os = "wasi", ))] fn name_cstr(&self) -> &CStr { &self.name @@ -1121,6 +1135,7 @@ pub fn create_new(&mut self, create_new: bool) { pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; } + #[cfg(not(target_os = "wasi"))] pub fn mode(&mut self, mode: u32) { self.mode = mode as mode_t; } @@ -1769,6 +1784,7 @@ pub fn mkdir(&self, p: &Path) -> io::Result<()> { run_path_with_cstr(p, &|p| cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) }).map(|_| ())) } + #[cfg(not(target_os = "wasi"))] pub fn set_mode(&mut self, mode: u32) { self.mode = mode as mode_t; } @@ -2217,7 +2233,7 @@ pub fn set_times_nofollow(p: &CStr, times: FileTimes) -> io::Result<()> { set_times_impl(p, times, false) } -#[cfg(target_os = "espidf")] +#[cfg(any(target_os = "espidf", target_os = "wasi"))] fn open_to_and_set_permissions( to: &Path, _reader_metadata: &crate::fs::Metadata, @@ -2228,7 +2244,7 @@ fn open_to_and_set_permissions( Ok((writer, writer_metadata)) } -#[cfg(not(target_os = "espidf"))] +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] fn open_to_and_set_permissions( to: &Path, reader_metadata: &crate::fs::Metadata, @@ -2376,6 +2392,7 @@ fn drop(&mut self) { Ok(bytes_copied as u64) } +#[cfg(not(target_os = "wasi"))] pub fn chown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { run_path_with_cstr(path, &|path| { cvt(unsafe { libc::chown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) }) @@ -2383,12 +2400,13 @@ pub fn chown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { }) } +#[cfg(not(target_os = "wasi"))] pub fn fchown(fd: c_int, uid: u32, gid: u32) -> io::Result<()> { cvt(unsafe { libc::fchown(fd, uid as libc::uid_t, gid as libc::gid_t) })?; Ok(()) } -#[cfg(not(target_os = "vxworks"))] +#[cfg(not(any(target_os = "vxworks", target_os = "wasi")))] pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { run_path_with_cstr(path, &|path| { cvt(unsafe { libc::lchown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) }) @@ -2402,7 +2420,7 @@ pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { Err(io::const_error!(io::ErrorKind::Unsupported, "lchown not supported by vxworks")) } -#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))] +#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks", target_os = "wasi")))] pub fn chroot(dir: &Path) -> io::Result<()> { run_path_with_cstr(dir, &|dir| cvt(unsafe { libc::chroot(dir.as_ptr()) }).map(|_| ())) } @@ -2413,6 +2431,7 @@ pub fn chroot(dir: &Path) -> io::Result<()> { Err(io::const_error!(io::ErrorKind::Unsupported, "chroot not supported by vxworks")) } +#[cfg(not(target_os = "wasi"))] pub fn mkfifo(path: &Path, mode: u32) -> io::Result<()> { run_path_with_cstr(path, &|path| { cvt(unsafe { libc::mkfifo(path.as_ptr(), mode.try_into().unwrap()) }).map(|_| ()) @@ -2451,11 +2470,11 @@ mod remove_dir_impl { #[cfg(all(target_os = "linux", target_env = "gnu"))] use libc::{fdopendir, openat64 as openat, unlinkat}; - use super::{Dir, DirEntry, InnerReadDir, ReadDir, lstat}; + use super::{ + AsRawFd, Dir, DirEntry, FromRawFd, InnerReadDir, IntoRawFd, OwnedFd, RawFd, ReadDir, lstat, + }; use crate::ffi::CStr; use crate::io; - use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd}; - use crate::os::unix::prelude::{OwnedFd, RawFd}; use crate::path::{Path, PathBuf}; use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::{cvt, cvt_r}; @@ -2543,6 +2562,16 @@ fn remove_dir_all_recursive(parent_fd: Option, path: &CStr) -> io::Result // open the directory passing ownership of the fd let (dir, fd) = fdreaddir(fd)?; + + // For WASI all directory entries for this directory are read first + // before any removal is done. This works around the fact that the + // WASIp1 API for reading directories is not well-designed for handling + // mutations between invocations of reading a directory. By reading all + // the entries at once this ensures that, at least without concurrent + // modifications, it should be possible to delete everything. + #[cfg(target_os = "wasi")] + let dir = dir.collect::>(); + for child in dir { let child = child?; let child_name = child.name_cstr(); diff --git a/library/std/src/sys/fs/wasi.rs b/library/std/src/sys/fs/wasi.rs deleted file mode 100644 index 92eb35317415..000000000000 --- a/library/std/src/sys/fs/wasi.rs +++ /dev/null @@ -1,913 +0,0 @@ -use crate::ffi::{CStr, OsStr, OsString}; -use crate::fs::TryLockError; -use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; -use crate::mem::{self, ManuallyDrop}; -use crate::os::raw::c_int; -use crate::os::wasi::ffi::{OsStrExt, OsStringExt}; -use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; -use crate::path::{Path, PathBuf}; -use crate::sync::Arc; -use crate::sys::common::small_c_string::run_path_with_cstr; -use crate::sys::fd::WasiFd; -pub use crate::sys::fs::common::exists; -use crate::sys::time::SystemTime; -use crate::sys::{unsupported, unsupported_err}; -use crate::sys_common::{AsInner, FromInner, IntoInner, ignore_notfound}; -use crate::{fmt, iter, ptr}; - -pub struct File { - fd: WasiFd, -} - -#[derive(Clone)] -pub struct FileAttr { - meta: wasi::Filestat, -} - -pub struct ReadDir { - inner: Arc, - state: ReadDirState, -} - -enum ReadDirState { - /// Fill `buf` with `buf.len()` bytes starting from `next_read_offset`. - FillBuffer { - next_read_offset: wasi::Dircookie, - buf: Vec, - }, - ProcessEntry { - buf: Vec, - next_read_offset: Option, - offset: usize, - }, - /// There is no more data to get in [`Self::FillBuffer`]; keep returning - /// entries via ProcessEntry until `buf` is exhausted. - RunUntilExhaustion { - buf: Vec, - offset: usize, - }, - Done, -} - -struct ReadDirInner { - root: PathBuf, - dir: File, -} - -pub struct DirEntry { - meta: wasi::Dirent, - name: Vec, - inner: Arc, -} - -#[derive(Clone, Debug, Default)] -pub struct OpenOptions { - read: bool, - write: bool, - append: bool, - dirflags: wasi::Lookupflags, - fdflags: wasi::Fdflags, - oflags: wasi::Oflags, - rights_base: Option, - rights_inheriting: Option, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct FilePermissions { - readonly: bool, -} - -#[derive(Copy, Clone, Debug, Default)] -pub struct FileTimes { - accessed: Option, - modified: Option, -} - -#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] -pub struct FileType { - bits: wasi::Filetype, -} - -#[derive(Debug)] -pub struct DirBuilder {} - -impl FileAttr { - pub fn size(&self) -> u64 { - self.meta.size - } - - pub fn perm(&self) -> FilePermissions { - // not currently implemented in wasi yet - FilePermissions { readonly: false } - } - - pub fn file_type(&self) -> FileType { - FileType { bits: self.meta.filetype } - } - - pub fn modified(&self) -> io::Result { - Ok(SystemTime::from_wasi_timestamp(self.meta.mtim)) - } - - pub fn accessed(&self) -> io::Result { - Ok(SystemTime::from_wasi_timestamp(self.meta.atim)) - } - - pub fn created(&self) -> io::Result { - Ok(SystemTime::from_wasi_timestamp(self.meta.ctim)) - } - - pub(crate) fn as_wasi(&self) -> &wasi::Filestat { - &self.meta - } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - self.readonly - } - - pub fn set_readonly(&mut self, readonly: bool) { - self.readonly = readonly; - } -} - -impl FileTimes { - pub fn set_accessed(&mut self, t: SystemTime) { - self.accessed = Some(t); - } - - pub fn set_modified(&mut self, t: SystemTime) { - self.modified = Some(t); - } -} - -impl FileType { - pub fn is_dir(&self) -> bool { - self.bits == wasi::FILETYPE_DIRECTORY - } - - pub fn is_file(&self) -> bool { - self.bits == wasi::FILETYPE_REGULAR_FILE - } - - pub fn is_symlink(&self) -> bool { - self.bits == wasi::FILETYPE_SYMBOLIC_LINK - } - - pub(crate) fn bits(&self) -> wasi::Filetype { - self.bits - } -} - -impl ReadDir { - fn new(dir: File, root: PathBuf) -> ReadDir { - ReadDir { - inner: Arc::new(ReadDirInner { dir, root }), - state: ReadDirState::FillBuffer { next_read_offset: 0, buf: vec![0; 128] }, - } - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ReadDir").finish_non_exhaustive() - } -} - -impl core::iter::FusedIterator for ReadDir {} - -impl Iterator for ReadDir { - type Item = io::Result; - - fn next(&mut self) -> Option> { - match &mut self.state { - ReadDirState::FillBuffer { next_read_offset, buf } => { - let result = self.inner.dir.fd.readdir(buf, *next_read_offset); - match result { - Ok(read_bytes) => { - if read_bytes < buf.len() { - buf.truncate(read_bytes); - self.state = - ReadDirState::RunUntilExhaustion { buf: mem::take(buf), offset: 0 }; - } else { - debug_assert_eq!(read_bytes, buf.len()); - self.state = ReadDirState::ProcessEntry { - buf: mem::take(buf), - offset: 0, - next_read_offset: Some(*next_read_offset), - }; - } - self.next() - } - Err(e) => { - self.state = ReadDirState::Done; - return Some(Err(e)); - } - } - } - ReadDirState::ProcessEntry { buf, next_read_offset, offset } => { - let contents = &buf[*offset..]; - const DIRENT_SIZE: usize = size_of::(); - if contents.len() >= DIRENT_SIZE { - let (dirent, data) = contents.split_at(DIRENT_SIZE); - let dirent = - unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) }; - // If the file name was truncated, then we need to reinvoke - // `readdir` so we truncate our buffer to start over and reread this - // descriptor. - if data.len() < dirent.d_namlen as usize { - if buf.len() < dirent.d_namlen as usize + DIRENT_SIZE { - buf.resize(dirent.d_namlen as usize + DIRENT_SIZE, 0); - } - if let Some(next_read_offset) = *next_read_offset { - self.state = - ReadDirState::FillBuffer { next_read_offset, buf: mem::take(buf) }; - } else { - self.state = ReadDirState::Done; - } - - return self.next(); - } - next_read_offset.as_mut().map(|cookie| { - *cookie = dirent.d_next; - }); - *offset = *offset + DIRENT_SIZE + dirent.d_namlen as usize; - - let name = &data[..(dirent.d_namlen as usize)]; - - // These names are skipped on all other platforms, so let's skip - // them here too - if name == b"." || name == b".." { - return self.next(); - } - - return Some(Ok(DirEntry { - meta: dirent, - name: name.to_vec(), - inner: self.inner.clone(), - })); - } else if let Some(next_read_offset) = *next_read_offset { - self.state = ReadDirState::FillBuffer { next_read_offset, buf: mem::take(buf) }; - } else { - self.state = ReadDirState::Done; - } - self.next() - } - ReadDirState::RunUntilExhaustion { buf, offset } => { - if *offset >= buf.len() { - self.state = ReadDirState::Done; - } else { - self.state = ReadDirState::ProcessEntry { - buf: mem::take(buf), - offset: *offset, - next_read_offset: None, - }; - } - - self.next() - } - ReadDirState::Done => None, - } - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - let name = OsStr::from_bytes(&self.name); - self.inner.root.join(name) - } - - pub fn file_name(&self) -> OsString { - OsString::from_vec(self.name.clone()) - } - - pub fn metadata(&self) -> io::Result { - metadata_at(&self.inner.dir.fd, 0, OsStr::from_bytes(&self.name).as_ref()) - } - - pub fn file_type(&self) -> io::Result { - Ok(FileType { bits: self.meta.d_type }) - } - - pub fn ino(&self) -> wasi::Inode { - self.meta.d_ino - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - let mut base = OpenOptions::default(); - base.dirflags = wasi::LOOKUPFLAGS_SYMLINK_FOLLOW; - base - } - - pub fn read(&mut self, read: bool) { - self.read = read; - } - - pub fn write(&mut self, write: bool) { - self.write = write; - } - - pub fn truncate(&mut self, truncate: bool) { - self.oflag(wasi::OFLAGS_TRUNC, truncate); - } - - pub fn create(&mut self, create: bool) { - self.oflag(wasi::OFLAGS_CREAT, create); - } - - pub fn create_new(&mut self, create_new: bool) { - self.oflag(wasi::OFLAGS_EXCL, create_new); - self.oflag(wasi::OFLAGS_CREAT, create_new); - } - - pub fn directory(&mut self, directory: bool) { - self.oflag(wasi::OFLAGS_DIRECTORY, directory); - } - - fn oflag(&mut self, bit: wasi::Oflags, set: bool) { - if set { - self.oflags |= bit; - } else { - self.oflags &= !bit; - } - } - - pub fn append(&mut self, append: bool) { - self.append = append; - self.fdflag(wasi::FDFLAGS_APPEND, append); - } - - pub fn dsync(&mut self, set: bool) { - self.fdflag(wasi::FDFLAGS_DSYNC, set); - } - - pub fn nonblock(&mut self, set: bool) { - self.fdflag(wasi::FDFLAGS_NONBLOCK, set); - } - - pub fn rsync(&mut self, set: bool) { - self.fdflag(wasi::FDFLAGS_RSYNC, set); - } - - pub fn sync(&mut self, set: bool) { - self.fdflag(wasi::FDFLAGS_SYNC, set); - } - - fn fdflag(&mut self, bit: wasi::Fdflags, set: bool) { - if set { - self.fdflags |= bit; - } else { - self.fdflags &= !bit; - } - } - - pub fn fs_rights_base(&mut self, rights: wasi::Rights) { - self.rights_base = Some(rights); - } - - pub fn fs_rights_inheriting(&mut self, rights: wasi::Rights) { - self.rights_inheriting = Some(rights); - } - - fn rights_base(&self) -> wasi::Rights { - if let Some(rights) = self.rights_base { - return rights; - } - - // If rights haven't otherwise been specified try to pick a reasonable - // set. This can always be overridden by users via extension traits, and - // implementations may give us fewer rights silently than we ask for. So - // given that, just look at `read` and `write` and bucket permissions - // based on that. - let mut base = 0; - if self.read { - base |= wasi::RIGHTS_FD_READ; - base |= wasi::RIGHTS_FD_READDIR; - } - if self.write || self.append { - base |= wasi::RIGHTS_FD_WRITE; - base |= wasi::RIGHTS_FD_DATASYNC; - base |= wasi::RIGHTS_FD_ALLOCATE; - base |= wasi::RIGHTS_FD_FILESTAT_SET_SIZE; - } - - // FIXME: some of these should probably be read-only or write-only... - base |= wasi::RIGHTS_FD_ADVISE; - base |= wasi::RIGHTS_FD_FDSTAT_SET_FLAGS; - base |= wasi::RIGHTS_FD_FILESTAT_GET; - base |= wasi::RIGHTS_FD_FILESTAT_SET_TIMES; - base |= wasi::RIGHTS_FD_SEEK; - base |= wasi::RIGHTS_FD_SYNC; - base |= wasi::RIGHTS_FD_TELL; - base |= wasi::RIGHTS_PATH_CREATE_DIRECTORY; - base |= wasi::RIGHTS_PATH_CREATE_FILE; - base |= wasi::RIGHTS_PATH_FILESTAT_GET; - base |= wasi::RIGHTS_PATH_LINK_SOURCE; - base |= wasi::RIGHTS_PATH_LINK_TARGET; - base |= wasi::RIGHTS_PATH_OPEN; - base |= wasi::RIGHTS_PATH_READLINK; - base |= wasi::RIGHTS_PATH_REMOVE_DIRECTORY; - base |= wasi::RIGHTS_PATH_RENAME_SOURCE; - base |= wasi::RIGHTS_PATH_RENAME_TARGET; - base |= wasi::RIGHTS_PATH_SYMLINK; - base |= wasi::RIGHTS_PATH_UNLINK_FILE; - base |= wasi::RIGHTS_POLL_FD_READWRITE; - - base - } - - fn rights_inheriting(&self) -> wasi::Rights { - self.rights_inheriting.unwrap_or_else(|| self.rights_base()) - } - - pub fn lookup_flags(&mut self, flags: wasi::Lookupflags) { - self.dirflags = flags; - } -} - -impl File { - pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { - let (dir, file) = open_parent(path)?; - open_at(&dir, &file, opts) - } - - pub fn open_at(&self, path: &Path, opts: &OpenOptions) -> io::Result { - open_at(&self.fd, path, opts) - } - - pub fn file_attr(&self) -> io::Result { - self.fd.filestat_get().map(|meta| FileAttr { meta }) - } - - pub fn metadata_at(&self, flags: wasi::Lookupflags, path: &Path) -> io::Result { - metadata_at(&self.fd, flags, path) - } - - pub fn fsync(&self) -> io::Result<()> { - self.fd.sync() - } - - pub fn datasync(&self) -> io::Result<()> { - self.fd.datasync() - } - - pub fn lock(&self) -> io::Result<()> { - unsupported() - } - - pub fn lock_shared(&self) -> io::Result<()> { - unsupported() - } - - pub fn try_lock(&self) -> Result<(), TryLockError> { - Err(TryLockError::Error(unsupported_err())) - } - - pub fn try_lock_shared(&self) -> Result<(), TryLockError> { - Err(TryLockError::Error(unsupported_err())) - } - - pub fn unlock(&self) -> io::Result<()> { - unsupported() - } - - pub fn truncate(&self, size: u64) -> io::Result<()> { - self.fd.filestat_set_size(size) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.read_vectored(&mut [IoSliceMut::new(buf)]) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.fd.read(bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - true - } - - pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { - self.fd.read_buf(cursor) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.write_vectored(&[IoSlice::new(buf)]) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - self.fd.write(bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - true - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } - - pub fn seek(&self, pos: SeekFrom) -> io::Result { - self.fd.seek(pos) - } - - pub fn size(&self) -> Option> { - None - } - - pub fn tell(&self) -> io::Result { - self.fd.tell() - } - - pub fn duplicate(&self) -> io::Result { - // https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-rationale.md#why-no-dup - unsupported() - } - - pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - // Permissions haven't been fully figured out in wasi yet, so this is - // likely temporary - unsupported() - } - - pub fn set_times(&self, times: FileTimes) -> io::Result<()> { - self.fd.filestat_set_times( - to_wasi_timestamp_or_now(times.accessed)?, - to_wasi_timestamp_or_now(times.modified)?, - times.accessed.map_or(0, |_| wasi::FSTFLAGS_ATIM) - | times.modified.map_or(0, |_| wasi::FSTFLAGS_MTIM), - ) - } - - pub fn read_link(&self, file: &Path) -> io::Result { - read_link(&self.fd, file) - } -} - -impl AsInner for File { - #[inline] - fn as_inner(&self) -> &WasiFd { - &self.fd - } -} - -impl IntoInner for File { - fn into_inner(self) -> WasiFd { - self.fd - } -} - -impl FromInner for File { - fn from_inner(fd: WasiFd) -> File { - File { fd } - } -} - -impl AsFd for File { - fn as_fd(&self) -> BorrowedFd<'_> { - self.fd.as_fd() - } -} - -impl AsRawFd for File { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.fd.as_raw_fd() - } -} - -impl IntoRawFd for File { - fn into_raw_fd(self) -> RawFd { - self.fd.into_raw_fd() - } -} - -impl FromRawFd for File { - unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { - unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } } - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder {} - } - - pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p)?; - dir.create_directory(osstr2str(file.as_ref())?) - } -} - -impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("File").field("fd", &self.as_raw_fd()).finish() - } -} - -pub fn readdir(p: &Path) -> io::Result { - let mut opts = OpenOptions::new(); - opts.directory(true); - opts.read(true); - let dir = File::open(p, &opts)?; - Ok(ReadDir::new(dir, p.to_path_buf())) -} - -pub fn unlink(p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p)?; - dir.unlink_file(osstr2str(file.as_ref())?) -} - -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let (old, old_file) = open_parent(old)?; - let (new, new_file) = open_parent(new)?; - old.rename(osstr2str(old_file.as_ref())?, &new, osstr2str(new_file.as_ref())?) -} - -pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { - // Permissions haven't been fully figured out in wasi yet, so this is - // likely temporary - unsupported() -} - -#[inline(always)] -pub fn set_times(p: &Path, times: FileTimes) -> io::Result<()> { - let (dir, file) = open_parent(p)?; - set_times_impl(&dir, &file, times, wasi::LOOKUPFLAGS_SYMLINK_FOLLOW) -} - -#[inline(always)] -pub fn set_times_nofollow(p: &Path, times: FileTimes) -> io::Result<()> { - let (dir, file) = open_parent(p)?; - set_times_impl(&dir, &file, times, 0) -} - -fn to_wasi_timestamp_or_now(time: Option) -> io::Result { - match time { - Some(time) if let Some(ts) = time.to_wasi_timestamp() => Ok(ts), - Some(_) => Err(io::const_error!( - io::ErrorKind::InvalidInput, - "timestamp is too large to set as a file time", - )), - None => Ok(0), - } -} - -fn set_times_impl( - fd: &WasiFd, - path: &Path, - times: FileTimes, - flags: wasi::Lookupflags, -) -> io::Result<()> { - fd.path_filestat_set_times( - flags, - osstr2str(path.as_ref())?, - to_wasi_timestamp_or_now(times.accessed)?, - to_wasi_timestamp_or_now(times.modified)?, - times.accessed.map_or(0, |_| wasi::FSTFLAGS_ATIM) - | times.modified.map_or(0, |_| wasi::FSTFLAGS_MTIM), - ) -} - -pub fn rmdir(p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p)?; - dir.remove_directory(osstr2str(file.as_ref())?) -} - -pub fn readlink(p: &Path) -> io::Result { - let (dir, file) = open_parent(p)?; - read_link(&dir, &file) -} - -fn read_link(fd: &WasiFd, file: &Path) -> io::Result { - // Try to get a best effort initial capacity for the vector we're going to - // fill. Note that if it's not a symlink we don't use a file to avoid - // allocating gigabytes if you read_link a huge movie file by accident. - // Additionally we add 1 to the initial size so if it doesn't change until - // when we call `readlink` the returned length will be less than the - // capacity, guaranteeing that we got all the data. - let meta = metadata_at(fd, 0, file)?; - let initial_size = if meta.file_type().is_symlink() { - (meta.size() as usize).saturating_add(1) - } else { - 1 // this'll fail in just a moment - }; - - // Now that we have an initial guess of how big to make our buffer, call - // `readlink` in a loop until it fails or reports it filled fewer bytes than - // we asked for, indicating we got everything. - let file = osstr2str(file.as_ref())?; - let mut destination = vec![0u8; initial_size]; - loop { - let len = fd.readlink(file, &mut destination)?; - if len < destination.len() { - destination.truncate(len); - destination.shrink_to_fit(); - return Ok(PathBuf::from(OsString::from_vec(destination))); - } - let amt_to_add = destination.len(); - destination.extend(iter::repeat(0).take(amt_to_add)); - } -} - -pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { - let (link, link_file) = open_parent(link)?; - link.symlink(osstr2str(original.as_ref())?, osstr2str(link_file.as_ref())?) -} - -pub fn link(original: &Path, link: &Path) -> io::Result<()> { - let (original, original_file) = open_parent(original)?; - let (link, link_file) = open_parent(link)?; - // Pass 0 as the flags argument, meaning don't follow symlinks. - original.link(0, osstr2str(original_file.as_ref())?, &link, osstr2str(link_file.as_ref())?) -} - -pub fn stat(p: &Path) -> io::Result { - let (dir, file) = open_parent(p)?; - metadata_at(&dir, wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, &file) -} - -pub fn lstat(p: &Path) -> io::Result { - let (dir, file) = open_parent(p)?; - metadata_at(&dir, 0, &file) -} - -fn metadata_at(fd: &WasiFd, flags: wasi::Lookupflags, path: &Path) -> io::Result { - let meta = fd.path_filestat_get(flags, osstr2str(path.as_ref())?)?; - Ok(FileAttr { meta }) -} - -pub fn canonicalize(_p: &Path) -> io::Result { - // This seems to not be in wasi's API yet, and we may need to end up - // emulating it ourselves. For now just return an error. - unsupported() -} - -fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result { - let fd = fd.open( - opts.dirflags, - osstr2str(path.as_ref())?, - opts.oflags, - opts.rights_base(), - opts.rights_inheriting(), - opts.fdflags, - )?; - Ok(File { fd }) -} - -/// Attempts to open a bare path `p`. -/// -/// WASI has no fundamental capability to do this. All syscalls and operations -/// are relative to already-open file descriptors. The C library, however, -/// manages a map of pre-opened file descriptors to their path, and then the C -/// library provides an API to look at this. In other words, when you want to -/// open a path `p`, you have to find a previously opened file descriptor in a -/// global table and then see if `p` is relative to that file descriptor. -/// -/// This function, if successful, will return two items: -/// -/// * The first is a `ManuallyDrop`. This represents a pre-opened file -/// descriptor which we don't have ownership of, but we can use. You shouldn't -/// actually drop the `fd`. -/// -/// * The second is a path that should be a part of `p` and represents a -/// relative traversal from the file descriptor specified to the desired -/// location `p`. -/// -/// If successful you can use the returned file descriptor to perform -/// file-descriptor-relative operations on the path returned as well. The -/// `rights` argument indicates what operations are desired on the returned file -/// descriptor, and if successful the returned file descriptor should have the -/// appropriate rights for performing `rights` actions. -/// -/// Note that this can fail if `p` doesn't look like it can be opened relative -/// to any pre-opened file descriptor. -fn open_parent(p: &Path) -> io::Result<(ManuallyDrop, PathBuf)> { - run_path_with_cstr(p, &|p| { - let mut buf = Vec::::with_capacity(512); - loop { - unsafe { - let mut relative_path = buf.as_ptr().cast(); - let mut abs_prefix = ptr::null(); - let fd = __wasilibc_find_relpath( - p.as_ptr(), - &mut abs_prefix, - &mut relative_path, - buf.capacity(), - ); - if fd == -1 { - if io::Error::last_os_error().raw_os_error() == Some(libc::ENOMEM) { - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. - let cap = buf.capacity(); - buf.set_len(cap); - buf.reserve(1); - continue; - } - let msg = format!( - "failed to find a pre-opened file descriptor \ - through which {p:?} could be opened", - ); - return Err(io::Error::new(io::ErrorKind::Uncategorized, msg)); - } - let relative = CStr::from_ptr(relative_path).to_bytes().to_vec(); - - return Ok(( - ManuallyDrop::new(WasiFd::from_raw_fd(fd as c_int)), - PathBuf::from(OsString::from_vec(relative)), - )); - } - } - - unsafe extern "C" { - pub fn __wasilibc_find_relpath( - path: *const libc::c_char, - abs_prefix: *mut *const libc::c_char, - relative_path: *mut *const libc::c_char, - relative_path_len: libc::size_t, - ) -> libc::c_int; - } - }) -} - -pub fn osstr2str(f: &OsStr) -> io::Result<&str> { - f.to_str().ok_or_else(|| io::const_error!(io::ErrorKind::Uncategorized, "input must be utf-8")) -} - -pub fn copy(from: &Path, to: &Path) -> io::Result { - use crate::fs::File; - - let mut reader = File::open(from)?; - let mut writer = File::create(to)?; - - io::copy(&mut reader, &mut writer) -} - -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let (parent, path) = open_parent(path)?; - remove_dir_all_recursive(&parent, &path) -} - -fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> { - // Open up a file descriptor for the directory itself. Note that we don't - // follow symlinks here and we specifically open directories. - // - // At the root invocation of this function this will correctly handle - // symlinks passed to the top-level `remove_dir_all`. At the recursive - // level this will double-check that after the `readdir` call deduced this - // was a directory it's still a directory by the time we open it up. - // - // If the opened file was actually a symlink then the symlink is deleted, - // not the directory recursively. - let mut opts = OpenOptions::new(); - opts.lookup_flags(0); - opts.directory(true); - opts.read(true); - let fd = open_at(parent, path, &opts)?; - if fd.file_attr()?.file_type().is_symlink() { - return parent.unlink_file(osstr2str(path.as_ref())?); - } - - // this "root" is only used by `DirEntry::path` which we don't use below so - // it's ok for this to be a bogus value - let dummy_root = PathBuf::new(); - - // Iterate over all the entries in this directory, and travel recursively if - // necessary - // - // Note that all directory entries for this directory are read first before - // any removal is done. This works around the fact that the WASIp1 API for - // reading directories is not well-designed for handling mutations between - // invocations of reading a directory. By reading all the entries at once - // this ensures that, at least without concurrent modifications, it should - // be possible to delete everything. - for entry in ReadDir::new(fd, dummy_root).collect::>() { - let entry = entry?; - let path = crate::str::from_utf8(&entry.name).map_err(|_| { - io::const_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found") - })?; - - let result: io::Result<()> = try { - if entry.file_type()?.is_dir() { - remove_dir_all_recursive(&entry.inner.dir.fd, path.as_ref())?; - } else { - entry.inner.dir.fd.unlink_file(path)?; - } - }; - // ignore internal NotFound errors - if let Err(err) = &result - && err.kind() != io::ErrorKind::NotFound - { - return result; - } - } - - // Once all this directory's contents are deleted it should be safe to - // delete the directory tiself. - ignore_notfound(parent.remove_directory(osstr2str(path.as_ref())?)) -} diff --git a/library/std/src/sys/io/io_slice/iovec.rs b/library/std/src/sys/io/io_slice/iovec.rs index df56358969a3..d549aca250d5 100644 --- a/library/std/src/sys/io/io_slice/iovec.rs +++ b/library/std/src/sys/io/io_slice/iovec.rs @@ -1,6 +1,6 @@ #[cfg(target_os = "hermit")] use hermit_abi::iovec; -#[cfg(any(target_family = "unix", target_os = "trusty"))] +#[cfg(any(target_family = "unix", target_os = "trusty", target_os = "wasi"))] use libc::iovec; use crate::ffi::c_void; diff --git a/library/std/src/sys/io/io_slice/wasi.rs b/library/std/src/sys/io/io_slice/wasi.rs deleted file mode 100644 index 87acbbd924e5..000000000000 --- a/library/std/src/sys/io/io_slice/wasi.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::marker::PhantomData; -use crate::slice; - -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct IoSlice<'a> { - vec: wasi::Ciovec, - _p: PhantomData<&'a [u8]>, -} - -impl<'a> IoSlice<'a> { - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - IoSlice { vec: wasi::Ciovec { buf: buf.as_ptr(), buf_len: buf.len() }, _p: PhantomData } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if self.vec.buf_len < n { - panic!("advancing IoSlice beyond its length"); - } - - unsafe { - self.vec.buf_len -= n; - self.vec.buf = self.vec.buf.add(n); - } - } - - #[inline] - pub const fn as_slice(&self) -> &'a [u8] { - unsafe { slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len) } - } -} - -#[repr(transparent)] -pub struct IoSliceMut<'a> { - vec: wasi::Iovec, - _p: PhantomData<&'a mut [u8]>, -} - -impl<'a> IoSliceMut<'a> { - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - IoSliceMut { - vec: wasi::Iovec { buf: buf.as_mut_ptr(), buf_len: buf.len() }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if self.vec.buf_len < n { - panic!("advancing IoSlice beyond its length"); - } - - unsafe { - self.vec.buf_len -= n; - self.vec.buf = self.vec.buf.add(n); - } - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len) } - } - - #[inline] - pub const fn into_slice(self) -> &'a mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) } - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) } - } -} diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs index e2c5e7f88d49..b4e4e6ec7312 100644 --- a/library/std/src/sys/io/mod.rs +++ b/library/std/src/sys/io/mod.rs @@ -2,7 +2,7 @@ mod io_slice { cfg_select! { - any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty") => { + any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty", target_os = "wasi") => { mod iovec; pub use iovec::*; } @@ -10,10 +10,6 @@ mod io_slice { mod windows; pub use windows::*; } - target_os = "wasi" => { - mod wasi; - pub use wasi::*; - } target_os = "uefi" => { mod uefi; pub use uefi::*; diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 1d941dec1b79..63d5c1d23124 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -22,14 +22,10 @@ mod solid; pub use solid::*; } - target_family = "unix" => { + any(target_family = "unix", target_os = "wasi") => { mod unix; pub use unix::*; } - all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { - mod wasip2; - pub use wasip2::*; - } target_os = "windows" => { mod windows; pub use windows::*; diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index c892daf0d39c..d30f6054077d 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -4,7 +4,7 @@ use crate::ffi::CStr; use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; -use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; +use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::FileDesc; use crate::sys::net::{getsockopt, setsockopt}; use crate::sys::pal::IsMinusOne; @@ -107,7 +107,7 @@ pub fn new(family: c_int, ty: c_int) -> io::Result { } } - #[cfg(not(target_os = "vxworks"))] + #[cfg(not(any(target_os = "vxworks", target_os = "wasi")))] pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> { unsafe { let mut fds = [0, 0]; @@ -275,6 +275,7 @@ pub fn duplicate(&self) -> io::Result { self.0.duplicate().map(Socket) } + #[cfg(not(target_os = "wasi"))] pub fn send_with_flags(&self, buf: &[u8], flags: c_int) -> io::Result { let len = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; let ret = cvt(unsafe { @@ -361,6 +362,7 @@ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { self.recv_from_with_flags(buf, MSG_PEEK) } + #[cfg(not(target_os = "wasi"))] pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } diff --git a/library/std/src/sys/net/connection/socket/wasip2.rs b/library/std/src/sys/net/connection/socket/wasip2.rs deleted file mode 100644 index f86034266c26..000000000000 --- a/library/std/src/sys/net/connection/socket/wasip2.rs +++ /dev/null @@ -1,408 +0,0 @@ -#![deny(unsafe_op_in_unsafe_fn)] - -pub(super) use libc as netc; -use libc::{c_int, c_void, size_t}; - -use super::{getsockopt, setsockopt, socket_addr_from_c, socket_addr_to_c}; -use crate::ffi::CStr; -use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::net::{Shutdown, SocketAddr}; -use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; -use crate::sys::unsupported; -use crate::sys_common::{AsInner, FromInner, IntoInner}; -use crate::time::{Duration, Instant}; -use crate::{cmp, mem, str}; - -#[allow(non_camel_case_types)] -pub type wrlen_t = size_t; - -#[doc(hidden)] -pub trait IsMinusOne { - fn is_minus_one(&self) -> bool; -} - -macro_rules! impl_is_minus_one { - ($($t:ident)*) => ($(impl IsMinusOne for $t { - fn is_minus_one(&self) -> bool { - *self == -1 - } - })*) -} - -impl_is_minus_one! { i8 i16 i32 i64 isize } - -pub fn cvt(t: T) -> crate::io::Result { - if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) } -} - -pub fn cvt_r(mut f: F) -> crate::io::Result -where - T: IsMinusOne, - F: FnMut() -> T, -{ - loop { - match cvt(f()) { - Err(ref e) if e.is_interrupted() => {} - other => return other, - } - } -} - -pub fn cvt_gai(err: c_int) -> io::Result<()> { - if err == 0 { - return Ok(()); - } - - if err == netc::EAI_SYSTEM { - return Err(io::Error::last_os_error()); - } - - let detail = unsafe { - str::from_utf8(CStr::from_ptr(netc::gai_strerror(err)).to_bytes()).unwrap().to_owned() - }; - - Err(io::Error::new( - io::ErrorKind::Uncategorized, - &format!("failed to lookup address information: {detail}")[..], - )) -} - -pub fn init() {} - -pub struct WasiSocket(OwnedFd); - -pub struct Socket(WasiSocket); - -impl Socket { - pub fn new(family: c_int, ty: c_int) -> io::Result { - let fd = cvt(unsafe { netc::socket(family, ty, 0) })?; - Ok(unsafe { Self::from_raw_fd(fd) }) - } - - pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { - let (addr, len) = socket_addr_to_c(addr); - cvt_r(|| unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?; - Ok(()) - } - - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = self.connect(addr); - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - // there's no ErrorKind for EINPROGRESS - Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {} - Err(e) => return Err(e), - } - - let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 }; - - if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::Error::ZERO_TIMEOUT); - } - - let start = Instant::now(); - - loop { - let elapsed = start.elapsed(); - if elapsed >= timeout { - return Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")); - } - - let timeout = timeout - elapsed; - let mut timeout = timeout - .as_secs() - .saturating_mul(1_000) - .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000); - if timeout == 0 { - timeout = 1; - } - - let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int; - - match unsafe { netc::poll(&mut pollfd, 1, timeout) } { - -1 => { - let err = io::Error::last_os_error(); - if !err.is_interrupted() { - return Err(err); - } - } - 0 => {} - _ => { - // WASI poll does not return POLLHUP or POLLERR in revents. Check if the - // connection actually succeeded and return ok only when the socket is - // ready and no errors were found. - if let Some(e) = self.take_error()? { - return Err(e); - } - - return Ok(()); - } - } - } - } - - pub fn accept( - &self, - storage: *mut netc::sockaddr, - len: *mut netc::socklen_t, - ) -> io::Result { - let fd = cvt_r(|| unsafe { netc::accept(self.as_raw_fd(), storage, len) })?; - Ok(unsafe { Self::from_raw_fd(fd) }) - } - - pub fn duplicate(&self) -> io::Result { - unsupported() - } - - fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> { - let ret = cvt(unsafe { - netc::recv( - self.as_raw_fd(), - buf.as_mut().as_mut_ptr() as *mut c_void, - buf.capacity(), - flags, - ) - })?; - unsafe { - buf.advance(ret as usize); - } - Ok(()) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - let mut buf = BorrowedBuf::from(buf); - self.recv_with_flags(buf.unfilled(), 0)?; - Ok(buf.len()) - } - - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - let mut buf = BorrowedBuf::from(buf); - self.recv_with_flags(buf.unfilled(), netc::MSG_PEEK)?; - Ok(buf.len()) - } - - pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { - self.recv_with_flags(buf, 0) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - io::default_read_vectored(|b| self.read(b), bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - false - } - - fn recv_from_with_flags( - &self, - buf: &mut [u8], - flags: c_int, - ) -> io::Result<(usize, SocketAddr)> { - let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() }; - let mut addrlen = size_of_val(&storage) as netc::socklen_t; - - let n = cvt(unsafe { - netc::recvfrom( - self.as_raw_fd(), - buf.as_mut_ptr() as *mut c_void, - buf.len(), - flags, - core::ptr::addr_of_mut!(storage) as *mut _, - &mut addrlen, - ) - })?; - Ok((n as usize, unsafe { socket_addr_from_c(&storage, addrlen as usize)? })) - } - - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, 0) - } - - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, netc::MSG_PEEK) - } - - fn write(&self, buf: &[u8]) -> io::Result { - let len = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; - let ret = cvt(unsafe { - netc::send(self.as_raw(), buf.as_ptr() as *const c_void, len, netc::MSG_NOSIGNAL) - })?; - Ok(ret as usize) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - io::default_write_vectored(|b| self.write(b), bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - false - } - - pub fn set_timeout(&self, dur: Option, kind: c_int) -> io::Result<()> { - let timeout = match dur { - Some(dur) => { - if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { - return Err(io::Error::ZERO_TIMEOUT); - } - - let secs = dur.as_secs().try_into().unwrap_or(netc::time_t::MAX); - let mut timeout = netc::timeval { - tv_sec: secs, - tv_usec: dur.subsec_micros() as netc::suseconds_t, - }; - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - timeout.tv_usec = 1; - } - timeout - } - None => netc::timeval { tv_sec: 0, tv_usec: 0 }, - }; - unsafe { setsockopt(self, netc::SOL_SOCKET, kind, timeout) } - } - - pub fn timeout(&self, kind: c_int) -> io::Result> { - let raw: netc::timeval = unsafe { getsockopt(self, netc::SOL_SOCKET, kind)? }; - if raw.tv_sec == 0 && raw.tv_usec == 0 { - Ok(None) - } else { - let sec = raw.tv_sec as u64; - let nsec = (raw.tv_usec as u32) * 1000; - Ok(Some(Duration::new(sec, nsec))) - } - } - - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - let how = match how { - Shutdown::Write => netc::SHUT_WR, - Shutdown::Read => netc::SHUT_RD, - Shutdown::Both => netc::SHUT_RDWR, - }; - cvt(unsafe { netc::shutdown(self.as_raw_fd(), how) })?; - Ok(()) - } - - pub fn set_linger(&self, _linger: Option) -> io::Result<()> { - unsupported() - } - - pub fn linger(&self) -> io::Result> { - unsupported() - } - - pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - unsafe { setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) } - } - - pub fn nodelay(&self) -> io::Result { - let raw: c_int = unsafe { getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)? }; - Ok(raw != 0) - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut nonblocking = nonblocking as c_int; - cvt(unsafe { netc::ioctl(self.as_raw_fd(), netc::FIONBIO, &mut nonblocking) }).map(drop) - } - - pub fn take_error(&self) -> io::Result> { - let raw: c_int = unsafe { getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)? }; - if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } - } - - // This is used by sys_common code to abstract over Windows and Unix. - pub fn as_raw(&self) -> RawFd { - self.as_raw_fd() - } -} - -impl AsInner for WasiSocket { - #[inline] - fn as_inner(&self) -> &OwnedFd { - &self.0 - } -} - -impl IntoInner for WasiSocket { - fn into_inner(self) -> OwnedFd { - self.0 - } -} - -impl FromInner for WasiSocket { - fn from_inner(owned_fd: OwnedFd) -> Self { - Self(owned_fd) - } -} - -impl AsFd for WasiSocket { - fn as_fd(&self) -> BorrowedFd<'_> { - self.0.as_fd() - } -} - -impl AsRawFd for WasiSocket { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} - -impl IntoRawFd for WasiSocket { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw_fd() - } -} - -impl FromRawFd for WasiSocket { - unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { - unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) } - } -} - -impl AsInner for Socket { - #[inline] - fn as_inner(&self) -> &WasiSocket { - &self.0 - } -} - -impl IntoInner for Socket { - fn into_inner(self) -> WasiSocket { - self.0 - } -} - -impl FromInner for Socket { - fn from_inner(sock: WasiSocket) -> Socket { - Socket(sock) - } -} - -impl AsFd for Socket { - fn as_fd(&self) -> BorrowedFd<'_> { - self.0.as_fd() - } -} - -impl AsRawFd for Socket { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} - -impl IntoRawFd for Socket { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw_fd() - } -} - -impl FromRawFd for Socket { - unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { - unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) } - } -} diff --git a/library/std/src/sys/net/connection/wasip1.rs b/library/std/src/sys/net/connection/wasip1.rs index 048dafdcd7f7..3a0ac5552a64 100644 --- a/library/std/src/sys/net/connection/wasip1.rs +++ b/library/std/src/sys/net/connection/wasip1.rs @@ -4,32 +4,32 @@ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; -use crate::sys::fd::WasiFd; +use crate::sys::fd::FileDesc; use crate::sys::{err2io, unsupported}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; -pub struct Socket(WasiFd); +pub struct Socket(FileDesc); pub struct TcpStream { inner: Socket, } -impl AsInner for Socket { +impl AsInner for Socket { #[inline] - fn as_inner(&self) -> &WasiFd { + fn as_inner(&self) -> &FileDesc { &self.0 } } -impl IntoInner for Socket { - fn into_inner(self) -> WasiFd { +impl IntoInner for Socket { + fn into_inner(self) -> FileDesc { self.0 } } -impl FromInner for Socket { - fn from_inner(inner: WasiFd) -> Socket { +impl FromInner for Socket { + fn from_inner(inner: FileDesc) -> Socket { Socket(inner) } } @@ -97,7 +97,7 @@ pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.socket().as_inner().read(bufs) + self.socket().as_inner().read_vectored(bufs) } pub fn is_read_vectored(&self) -> bool { @@ -109,7 +109,7 @@ pub fn write(&self, buf: &[u8]) -> io::Result { } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - self.socket().as_inner().write(bufs) + self.socket().as_inner().write_vectored(bufs) } pub fn is_write_vectored(&self) -> bool { diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index e11df38a8ee6..2bd3ec8188a7 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -53,13 +53,9 @@ mod vexos; pub use self::vexos::*; } - all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { - mod wasip2; - pub use self::wasip2::*; - } - all(target_os = "wasi", target_env = "p1") => { - mod wasip1; - pub use self::wasip1::*; + target_os = "wasi" => { + mod wasi; + pub use self::wasi::*; } target_family = "wasm" => { mod wasm; diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index c207f41cad4b..24f13853b96b 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -1,5 +1,6 @@ use core::num::niche_types::Nanoseconds; +use crate::sys_common::AsInner; use crate::time::Duration; use crate::{fmt, io}; @@ -298,6 +299,12 @@ pub(crate) fn into_timespec(self) -> Timespec { } } +impl AsInner for Instant { + fn as_inner(&self) -> &Timespec { + &self.t + } +} + impl fmt::Debug for Instant { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Instant") diff --git a/library/std/src/sys/pal/wasip2/cabi_realloc.rs b/library/std/src/sys/pal/wasi/cabi_realloc.rs similarity index 100% rename from library/std/src/sys/pal/wasip2/cabi_realloc.rs rename to library/std/src/sys/pal/wasi/cabi_realloc.rs diff --git a/library/std/src/sys/pal/wasi/helpers.rs b/library/std/src/sys/pal/wasi/helpers.rs new file mode 100644 index 000000000000..6bc41d469584 --- /dev/null +++ b/library/std/src/sys/pal/wasi/helpers.rs @@ -0,0 +1,63 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + +use crate::io as std_io; + +#[inline] +pub fn is_interrupted(errno: i32) -> bool { + errno == libc::EINTR +} + +pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { + use std_io::ErrorKind::*; + match errno as libc::c_int { + libc::E2BIG => ArgumentListTooLong, + libc::EADDRINUSE => AddrInUse, + libc::EADDRNOTAVAIL => AddrNotAvailable, + libc::EBUSY => ResourceBusy, + libc::ECONNABORTED => ConnectionAborted, + libc::ECONNREFUSED => ConnectionRefused, + libc::ECONNRESET => ConnectionReset, + libc::EDEADLK => Deadlock, + libc::EDQUOT => QuotaExceeded, + libc::EEXIST => AlreadyExists, + libc::EFBIG => FileTooLarge, + libc::EHOSTUNREACH => HostUnreachable, + libc::EINTR => Interrupted, + libc::EINVAL => InvalidInput, + libc::EISDIR => IsADirectory, + libc::ELOOP => FilesystemLoop, + libc::ENOENT => NotFound, + libc::ENOMEM => OutOfMemory, + libc::ENOSPC => StorageFull, + libc::ENOSYS => Unsupported, + libc::EMLINK => TooManyLinks, + libc::ENAMETOOLONG => InvalidFilename, + libc::ENETDOWN => NetworkDown, + libc::ENETUNREACH => NetworkUnreachable, + libc::ENOTCONN => NotConnected, + libc::ENOTDIR => NotADirectory, + libc::EPIPE => BrokenPipe, + libc::EROFS => ReadOnlyFilesystem, + libc::ESPIPE => NotSeekable, + libc::ESTALE => StaleNetworkFileHandle, + libc::ETIMEDOUT => TimedOut, + libc::ETXTBSY => ExecutableFileBusy, + libc::EXDEV => CrossesDevices, + libc::EINPROGRESS => InProgress, + libc::EOPNOTSUPP => Unsupported, + libc::EACCES | libc::EPERM => PermissionDenied, + libc::EWOULDBLOCK => WouldBlock, + + _ => Uncategorized, + } +} + +pub fn abort_internal() -> ! { + unsafe { libc::abort() } +} + +#[inline] +#[cfg(target_env = "p1")] +pub(crate) fn err2io(err: wasi::Errno) -> std_io::Error { + std_io::Error::from_raw_os_error(err.raw().into()) +} diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs new file mode 100644 index 000000000000..42629a91e1af --- /dev/null +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -0,0 +1,39 @@ +//! System bindings for the WASI platforms. +//! +//! This module contains the facade (aka platform-specific) implementations of +//! OS level functionality for WASI. Currently this includes both WASIp1 and +//! WASIp2. + +#[allow(unused)] +#[path = "../wasm/atomics/futex.rs"] +pub mod futex; + +pub mod os; +#[path = "../unsupported/pipe.rs"] +pub mod pipe; +pub mod stack_overflow; +#[path = "../unix/time.rs"] +pub mod time; + +#[path = "../unsupported/common.rs"] +#[deny(unsafe_op_in_unsafe_fn)] +#[allow(unused)] +mod common; + +pub use common::*; + +mod helpers; + +// The following exports are listed individually to work around Rust's glob +// import conflict rules. If we glob export `helpers` and `common` together, +// then the compiler complains about conflicts. + +#[cfg(target_env = "p1")] +pub(crate) use helpers::err2io; +pub(crate) use helpers::{abort_internal, decode_error_kind, is_interrupted}; +#[cfg(not(target_env = "p1"))] +pub use os::IsMinusOne; +pub use os::{cvt, cvt_r}; + +#[cfg(not(target_env = "p1"))] +mod cabi_realloc; diff --git a/library/std/src/sys/pal/wasip1/os.rs b/library/std/src/sys/pal/wasi/os.rs similarity index 88% rename from library/std/src/sys/pal/wasip1/os.rs rename to library/std/src/sys/pal/wasi/os.rs index 151ba254ec4c..367c63dfc59e 100644 --- a/library/std/src/sys/pal/wasip1/os.rs +++ b/library/std/src/sys/pal/wasi/os.rs @@ -19,13 +19,20 @@ pub mod libc { } } -pub fn errno() -> i32 { - unsafe extern "C" { - #[thread_local] - static errno: libc::c_int; - } +unsafe extern "C" { + #[thread_local] + #[link_name = "errno"] + static mut libc_errno: libc::c_int; +} - unsafe { errno as i32 } +pub fn errno() -> i32 { + unsafe { libc_errno as i32 } +} + +pub fn set_errno(val: i32) { + unsafe { + libc_errno = val; + } } pub fn error_string(errno: i32) -> String { @@ -149,3 +156,16 @@ fn is_minus_one(&self) -> bool { pub fn cvt(t: T) -> io::Result { if t.is_minus_one() { Err(io::Error::last_os_error()) } else { Ok(t) } } + +pub fn cvt_r(mut f: F) -> crate::io::Result +where + T: IsMinusOne, + F: FnMut() -> T, +{ + loop { + match cvt(f()) { + Err(ref e) if e.is_interrupted() => {} + other => return other, + } + } +} diff --git a/library/std/src/sys/pal/wasi/stack_overflow.rs b/library/std/src/sys/pal/wasi/stack_overflow.rs new file mode 100644 index 000000000000..9fef1ef5ab58 --- /dev/null +++ b/library/std/src/sys/pal/wasi/stack_overflow.rs @@ -0,0 +1,7 @@ +pub struct Handler; + +impl Handler { + pub unsafe fn new() -> Handler { + Handler + } +} diff --git a/library/std/src/sys/pal/wasip1/helpers.rs b/library/std/src/sys/pal/wasip1/helpers.rs deleted file mode 100644 index 404747f0dc75..000000000000 --- a/library/std/src/sys/pal/wasip1/helpers.rs +++ /dev/null @@ -1,114 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -use crate::io as std_io; - -#[inline] -pub fn is_interrupted(errno: i32) -> bool { - errno == wasi::ERRNO_INTR.raw().into() -} - -pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { - use std_io::ErrorKind; - - let Ok(errno) = u16::try_from(errno) else { - return ErrorKind::Uncategorized; - }; - - macro_rules! match_errno { - ($($($errno:ident)|+ => $errkind:ident),*, _ => $wildcard:ident $(,)?) => { - match errno { - $(e if $(e == ::wasi::$errno.raw())||+ => ErrorKind::$errkind),*, - _ => ErrorKind::$wildcard, - } - }; - } - - match_errno! { - ERRNO_2BIG => ArgumentListTooLong, - ERRNO_ACCES => PermissionDenied, - ERRNO_ADDRINUSE => AddrInUse, - ERRNO_ADDRNOTAVAIL => AddrNotAvailable, - ERRNO_AFNOSUPPORT => Unsupported, - ERRNO_AGAIN => WouldBlock, - // ALREADY => "connection already in progress", - // BADF => "bad file descriptor", - // BADMSG => "bad message", - ERRNO_BUSY => ResourceBusy, - // CANCELED => "operation canceled", - // CHILD => "no child processes", - ERRNO_CONNABORTED => ConnectionAborted, - ERRNO_CONNREFUSED => ConnectionRefused, - ERRNO_CONNRESET => ConnectionReset, - ERRNO_DEADLK => Deadlock, - // DESTADDRREQ => "destination address required", - ERRNO_DOM => InvalidInput, - // DQUOT => /* reserved */, - ERRNO_EXIST => AlreadyExists, - // FAULT => "bad address", - ERRNO_FBIG => FileTooLarge, - ERRNO_HOSTUNREACH => HostUnreachable, - // IDRM => "identifier removed", - // ILSEQ => "illegal byte sequence", - // INPROGRESS => "operation in progress", - ERRNO_INTR => Interrupted, - ERRNO_INVAL => InvalidInput, - ERRNO_IO => Uncategorized, - // ISCONN => "socket is connected", - ERRNO_ISDIR => IsADirectory, - ERRNO_LOOP => FilesystemLoop, - // MFILE => "file descriptor value too large", - ERRNO_MLINK => TooManyLinks, - // MSGSIZE => "message too large", - // MULTIHOP => /* reserved */, - ERRNO_NAMETOOLONG => InvalidFilename, - ERRNO_NETDOWN => NetworkDown, - // NETRESET => "connection aborted by network", - ERRNO_NETUNREACH => NetworkUnreachable, - // NFILE => "too many files open in system", - // NOBUFS => "no buffer space available", - ERRNO_NODEV => NotFound, - ERRNO_NOENT => NotFound, - // NOEXEC => "executable file format error", - // NOLCK => "no locks available", - // NOLINK => /* reserved */, - ERRNO_NOMEM => OutOfMemory, - // NOMSG => "no message of the desired type", - // NOPROTOOPT => "protocol not available", - ERRNO_NOSPC => StorageFull, - ERRNO_NOSYS => Unsupported, - ERRNO_NOTCONN => NotConnected, - ERRNO_NOTDIR => NotADirectory, - ERRNO_NOTEMPTY => DirectoryNotEmpty, - // NOTRECOVERABLE => "state not recoverable", - // NOTSOCK => "not a socket", - ERRNO_NOTSUP => Unsupported, - // NOTTY => "inappropriate I/O control operation", - ERRNO_NXIO => NotFound, - // OVERFLOW => "value too large to be stored in data type", - // OWNERDEAD => "previous owner died", - ERRNO_PERM => PermissionDenied, - ERRNO_PIPE => BrokenPipe, - // PROTO => "protocol error", - ERRNO_PROTONOSUPPORT => Unsupported, - // PROTOTYPE => "protocol wrong type for socket", - // RANGE => "result too large", - ERRNO_ROFS => ReadOnlyFilesystem, - ERRNO_SPIPE => NotSeekable, - ERRNO_SRCH => NotFound, - // STALE => /* reserved */, - ERRNO_TIMEDOUT => TimedOut, - ERRNO_TXTBSY => ResourceBusy, - ERRNO_XDEV => CrossesDevices, - ERRNO_NOTCAPABLE => PermissionDenied, - _ => Uncategorized, - } -} - -pub fn abort_internal() -> ! { - unsafe { libc::abort() } -} - -#[inline] -pub(crate) fn err2io(err: wasi::Errno) -> std_io::Error { - std_io::Error::from_raw_os_error(err.raw().into()) -} diff --git a/library/std/src/sys/pal/wasip1/mod.rs b/library/std/src/sys/pal/wasip1/mod.rs deleted file mode 100644 index ae5da3c1f77b..000000000000 --- a/library/std/src/sys/pal/wasip1/mod.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! System bindings for the wasm/web platform -//! -//! This module contains the facade (aka platform-specific) implementations of -//! OS level functionality for wasm. -//! -//! This is all super highly experimental and not actually intended for -//! wide/production use yet, it's still all in the experimental category. This -//! will likely change over time. -//! -//! Currently all functions here are basically stubs that immediately return -//! errors. The hope is that with a portability lint we can turn actually just -//! remove all this and just omit parts of the standard library if we're -//! compiling for wasm. That way it's a compile time error for something that's -//! guaranteed to be a runtime error! - -#[allow(unused)] -#[path = "../wasm/atomics/futex.rs"] -pub mod futex; - -pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; -pub mod time; - -#[path = "../unsupported/common.rs"] -#[deny(unsafe_op_in_unsafe_fn)] -#[allow(unused)] -mod common; - -pub use common::*; - -mod helpers; - -// The following exports are listed individually to work around Rust's glob -// import conflict rules. If we glob export `helpers` and `common` together, -// then the compiler complains about conflicts. - -pub(crate) use helpers::{abort_internal, decode_error_kind, err2io, is_interrupted}; diff --git a/library/std/src/sys/pal/wasip1/time.rs b/library/std/src/sys/pal/wasip1/time.rs deleted file mode 100644 index 0d8d0b59ac14..000000000000 --- a/library/std/src/sys/pal/wasip1/time.rs +++ /dev/null @@ -1,65 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -use crate::time::Duration; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant(Duration); - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct SystemTime(Duration); - -pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); - -fn current_time(clock: wasi::Clockid) -> Duration { - let ts = unsafe { - wasi::clock_time_get( - clock, 1, // precision... seems ignored though? - ) - .unwrap() - }; - Duration::new((ts / 1_000_000_000) as u64, (ts % 1_000_000_000) as u32) -} - -impl Instant { - pub fn now() -> Instant { - Instant(current_time(wasi::CLOCKID_MONOTONIC)) - } - - pub fn checked_sub_instant(&self, other: &Instant) -> Option { - self.0.checked_sub(other.0) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_add(*other)?)) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_sub(*other)?)) - } -} - -impl SystemTime { - pub fn now() -> SystemTime { - SystemTime(current_time(wasi::CLOCKID_REALTIME)) - } - - pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { - SystemTime(Duration::from_nanos(ts)) - } - - pub fn to_wasi_timestamp(&self) -> Option { - self.0.as_nanos().try_into().ok() - } - - pub fn sub_time(&self, other: &SystemTime) -> Result { - self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_add(*other)?)) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_sub(*other)?)) - } -} diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs deleted file mode 100644 index c1d89da2677c..000000000000 --- a/library/std/src/sys/pal/wasip2/mod.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! System bindings for the wasi preview 2 target. -//! -//! This is the next evolution of the original wasi target, and is intended to -//! replace that target over time. -//! -//! To begin with, this target mirrors the wasi target 1 to 1, but over -//! time this will change significantly. - -#[allow(unused)] -#[path = "../wasm/atomics/futex.rs"] -pub mod futex; - -#[path = "../wasip1/os.rs"] -pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; -pub mod time; - -#[path = "../unsupported/common.rs"] -#[deny(unsafe_op_in_unsafe_fn)] -#[allow(unused)] -mod common; - -pub use common::*; - -#[path = "../wasip1/helpers.rs"] -mod helpers; - -// The following exports are listed individually to work around Rust's glob -// import conflict rules. If we glob export `helpers` and `common` together, -// then the compiler complains about conflicts. - -pub(crate) use helpers::{abort_internal, decode_error_kind, err2io, is_interrupted}; - -mod cabi_realloc; diff --git a/library/std/src/sys/pal/wasip2/time.rs b/library/std/src/sys/pal/wasip2/time.rs deleted file mode 100644 index 434891839944..000000000000 --- a/library/std/src/sys/pal/wasip2/time.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::time::Duration; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant(Duration); - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct SystemTime(Duration); - -pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); - -impl Instant { - pub fn now() -> Instant { - Instant(Duration::from_nanos(wasip2::clocks::monotonic_clock::now())) - } - - pub fn checked_sub_instant(&self, other: &Instant) -> Option { - self.0.checked_sub(other.0) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_add(*other)?)) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_sub(*other)?)) - } - - pub(crate) fn as_duration(&self) -> &Duration { - &self.0 - } -} - -impl SystemTime { - pub fn now() -> SystemTime { - let now = wasip2::clocks::wall_clock::now(); - SystemTime(Duration::new(now.seconds, now.nanoseconds)) - } - - pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { - SystemTime(Duration::from_nanos(ts)) - } - - pub fn to_wasi_timestamp(&self) -> Option { - self.0.as_nanos().try_into().ok() - } - - pub fn sub_time(&self, other: &SystemTime) -> Result { - self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_add(*other)?)) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_sub(*other)?)) - } -} diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs index d51ea9ad726b..86d0f3fe49cb 100644 --- a/library/std/src/sys/stdio/mod.rs +++ b/library/std/src/sys/stdio/mod.rs @@ -1,7 +1,7 @@ #![forbid(unsafe_op_in_unsafe_fn)] cfg_select! { - any(target_family = "unix", target_os = "hermit") => { + any(target_family = "unix", target_os = "hermit", target_os = "wasi") => { mod unix; pub use unix::*; } @@ -37,14 +37,6 @@ mod vexos; pub use vexos::*; } - all(target_os = "wasi", target_env = "p1") => { - mod wasip1; - pub use wasip1::*; - } - all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { - mod wasip2; - pub use wasip2::*; - } target_os = "xous" => { mod xous; pub use xous::*; diff --git a/library/std/src/sys/stdio/unix.rs b/library/std/src/sys/stdio/unix.rs index 8535e3539e9f..ffed376a8e96 100644 --- a/library/std/src/sys/stdio/unix.rs +++ b/library/std/src/sys/stdio/unix.rs @@ -1,14 +1,11 @@ #[cfg(target_os = "hermit")] use hermit_abi::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; -#[cfg(target_family = "unix")] +#[cfg(any(target_family = "unix", target_os = "wasi"))] use libc::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; -#[cfg(target_os = "hermit")] -use crate::os::hermit::io::FromRawFd; -#[cfg(target_family = "unix")] -use crate::os::unix::io::FromRawFd; +use crate::os::fd::FromRawFd; use crate::sys::fd::FileDesc; pub struct Stdin; diff --git a/library/std/src/sys/stdio/wasip1.rs b/library/std/src/sys/stdio/wasip1.rs deleted file mode 100644 index b70efd026f94..000000000000 --- a/library/std/src/sys/stdio/wasip1.rs +++ /dev/null @@ -1,117 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::mem::ManuallyDrop; -use crate::os::raw; -use crate::os::wasi::io::{AsRawFd, FromRawFd}; -use crate::sys::fd::WasiFd; - -pub struct Stdin; -pub struct Stdout; -pub struct Stderr; - -impl Stdin { - pub const fn new() -> Stdin { - Stdin - } -} - -impl AsRawFd for Stdin { - #[inline] - fn as_raw_fd(&self) -> raw::c_int { - 0 - } -} - -impl io::Read for Stdin { - fn read(&mut self, data: &mut [u8]) -> io::Result { - self.read_vectored(&mut [IoSliceMut::new(data)]) - } - - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { - ManuallyDrop::new(unsafe { WasiFd::from_raw_fd(self.as_raw_fd()) }).read_buf(buf) - } - - fn read_vectored(&mut self, data: &mut [IoSliceMut<'_>]) -> io::Result { - ManuallyDrop::new(unsafe { WasiFd::from_raw_fd(self.as_raw_fd()) }).read(data) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - true - } -} - -impl Stdout { - pub const fn new() -> Stdout { - Stdout - } -} - -impl AsRawFd for Stdout { - #[inline] - fn as_raw_fd(&self) -> raw::c_int { - 1 - } -} - -impl io::Write for Stdout { - fn write(&mut self, data: &[u8]) -> io::Result { - self.write_vectored(&[IoSlice::new(data)]) - } - - fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result { - ManuallyDrop::new(unsafe { WasiFd::from_raw_fd(self.as_raw_fd()) }).write(data) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub const fn new() -> Stderr { - Stderr - } -} - -impl AsRawFd for Stderr { - #[inline] - fn as_raw_fd(&self) -> raw::c_int { - 2 - } -} - -impl io::Write for Stderr { - fn write(&mut self, data: &[u8]) -> io::Result { - self.write_vectored(&[IoSlice::new(data)]) - } - - fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result { - ManuallyDrop::new(unsafe { WasiFd::from_raw_fd(self.as_raw_fd()) }).write(data) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(wasi::ERRNO_BADF.raw().into()) -} - -pub fn panic_output() -> Option { - Some(Stderr::new()) -} diff --git a/library/std/src/sys/stdio/wasip2.rs b/library/std/src/sys/stdio/wasip2.rs deleted file mode 100644 index 1fcb49a083dd..000000000000 --- a/library/std/src/sys/stdio/wasip2.rs +++ /dev/null @@ -1,120 +0,0 @@ -use wasip2::cli; -use wasip2::io::streams::{Error, InputStream, OutputStream, StreamError}; - -use crate::io::{self, BorrowedBuf, BorrowedCursor}; - -pub struct Stdin(Option); -pub struct Stdout(Option); -pub struct Stderr(Option); - -fn error_to_io(err: Error) -> io::Error { - // There exists a function in `wasi:filesystem` to optionally acquire an - // error code from an error, but the streams in use in this module are - // exclusively used with stdio meaning that a filesystem error is not - // possible here. - // - // In lieu of an error code, which WASIp2 does not specify, this instead - // carries along the `to_debug_string` implementation that the host - // supplies. If this becomes too expensive in the future this could also - // become `io::Error::from_raw_os_error(libc::EIO)` or similar. - io::Error::new(io::ErrorKind::Other, err.to_debug_string()) -} - -impl Stdin { - pub const fn new() -> Stdin { - Stdin(None) - } - - fn stream(&mut self) -> &InputStream { - self.0.get_or_insert_with(cli::stdin::get_stdin) - } -} - -impl io::Read for Stdin { - fn read(&mut self, data: &mut [u8]) -> io::Result { - let mut buf = BorrowedBuf::from(data); - self.read_buf(buf.unfilled())?; - Ok(buf.len()) - } - - fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { - match self.stream().blocking_read(u64::try_from(buf.capacity()).unwrap()) { - Ok(result) => { - buf.append(&result); - Ok(()) - } - Err(StreamError::Closed) => Ok(()), - Err(StreamError::LastOperationFailed(e)) => Err(error_to_io(e)), - } - } -} - -impl Stdout { - pub const fn new() -> Stdout { - Stdout(None) - } - - fn stream(&mut self) -> &OutputStream { - self.0.get_or_insert_with(cli::stdout::get_stdout) - } -} - -fn write(stream: &OutputStream, buf: &[u8]) -> io::Result { - // WASIp2's `blocking_write_and_flush` function is defined as accepting no - // more than 4096 bytes. Larger writes can be issued by manually using - // `check_write`, `write`, and `blocking_flush`, but for now just go ahead - // and use `blocking_write_and_flush` and report a short write and let a - // higher level loop over the result. - const MAX: usize = 4096; - let buf = &buf[..buf.len().min(MAX)]; - match stream.blocking_write_and_flush(buf) { - Ok(()) => Ok(buf.len()), - Err(StreamError::Closed) => Ok(0), - Err(StreamError::LastOperationFailed(e)) => Err(error_to_io(e)), - } -} - -impl io::Write for Stdout { - fn write(&mut self, data: &[u8]) -> io::Result { - write(self.stream(), data) - } - - fn flush(&mut self) -> io::Result<()> { - // Note that `OutputStream` has a `flush` function but for stdio all - // writes are accompanied with a flush which means that this flush - // doesn't need to do anything. - Ok(()) - } -} - -impl Stderr { - pub const fn new() -> Stderr { - Stderr(None) - } - - fn stream(&mut self) -> &OutputStream { - self.0.get_or_insert_with(cli::stderr::get_stderr) - } -} - -impl io::Write for Stderr { - fn write(&mut self, data: &[u8]) -> io::Result { - write(self.stream(), data) - } - - fn flush(&mut self) -> io::Result<()> { - // See `Stdout::flush` for why this is a noop. - Ok(()) - } -} - -pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; - -pub fn is_ebadf(_err: &io::Error) -> bool { - // WASIp2 stdio streams are always available so ebadf never shows up. - false -} - -pub fn panic_output() -> Option { - Some(Stderr::new()) -} diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs index b98be62be0ad..cb6bf6518f81 100644 --- a/library/std/src/sys/thread/mod.rs +++ b/library/std/src/sys/thread/mod.rs @@ -48,7 +48,7 @@ mod unsupported; pub use unsupported::{Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE}; } - target_family = "unix" => { + any(target_family = "unix", target_os = "wasi") => { mod unix; pub use unix::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; #[cfg(not(any( @@ -58,6 +58,7 @@ target_os = "redox", target_os = "hurd", target_os = "aix", + target_os = "wasi", )))] pub use unix::set_name; #[cfg(any( @@ -71,6 +72,7 @@ target_os = "hurd", target_os = "fuchsia", target_os = "vxworks", + target_os = "wasi", ))] pub use unix::sleep_until; #[expect(dead_code)] @@ -82,6 +84,7 @@ target_os = "redox", target_os = "hurd", target_os = "aix", + target_os = "wasi", ))] pub use unsupported::set_name; } @@ -92,27 +95,6 @@ mod unsupported; pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, DEFAULT_MIN_STACK_SIZE}; } - all(target_os = "wasi", target_env = "p1") => { - mod wasip1; - pub use wasip1::{DEFAULT_MIN_STACK_SIZE, sleep, yield_now}; - #[cfg(target_feature = "atomics")] - pub use wasip1::{Thread, available_parallelism}; - #[expect(dead_code)] - mod unsupported; - pub use unsupported::{current_os_id, set_name}; - #[cfg(not(target_feature = "atomics"))] - pub use unsupported::{Thread, available_parallelism}; - } - all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { - mod wasip2; - pub use wasip2::{sleep, sleep_until}; - #[expect(dead_code)] - mod unsupported; - // Note that unlike WASIp1 even if the wasm `atomics` feature is enabled - // there is no support for threads, not even experimentally, not even in - // wasi-libc. Thus this is unconditionally unsupported. - pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE}; - } all(target_family = "wasm", target_feature = "atomics") => { mod wasm; pub use wasm::sleep; @@ -150,7 +132,7 @@ target_os = "hurd", target_os = "fuchsia", target_os = "vxworks", - all(target_os = "wasi", not(target_env = "p1")), + target_os = "wasi", )))] pub fn sleep_until(deadline: crate::time::Instant) { use crate::time::Instant; diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index 4adc94d0e5c9..18cdea0e1b1b 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -5,6 +5,7 @@ target_os = "redox", target_os = "hurd", target_os = "aix", + target_os = "wasi", )))] use crate::ffi::CStr; use crate::mem::{self, DropGuard, ManuallyDrop}; @@ -127,6 +128,7 @@ pub fn join(self) { assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); } + #[cfg(not(target_os = "wasi"))] pub fn id(&self) -> libc::pthread_t { self.id } @@ -588,6 +590,7 @@ pub fn sleep(dur: Duration) { target_os = "hurd", target_os = "fuchsia", target_os = "vxworks", + target_os = "wasi", ))] pub fn sleep_until(deadline: crate::time::Instant) { use crate::time::Instant; diff --git a/library/std/src/sys/thread/wasip1.rs b/library/std/src/sys/thread/wasip1.rs deleted file mode 100644 index 9287a9c5485c..000000000000 --- a/library/std/src/sys/thread/wasip1.rs +++ /dev/null @@ -1,183 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -#[cfg(target_feature = "atomics")] -use crate::io; -use crate::mem; -#[cfg(target_feature = "atomics")] -use crate::num::NonZero; -#[cfg(target_feature = "atomics")] -use crate::sys::os; -#[cfg(target_feature = "atomics")] -use crate::thread::ThreadInit; -use crate::time::Duration; -#[cfg(target_feature = "atomics")] -use crate::{cmp, ptr}; - -// Add a few symbols not in upstream `libc` just yet. -#[cfg(target_feature = "atomics")] -mod libc { - pub use libc::*; - - pub use crate::ffi; - - // defined in wasi-libc - // https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/include/alltypes.h.in#L108 - #[repr(C)] - union pthread_attr_union { - __i: [ffi::c_int; if size_of::() == 8 { 14 } else { 9 }], - __vi: [ffi::c_int; if size_of::() == 8 { 14 } else { 9 }], - __s: [ffi::c_ulong; if size_of::() == 8 { 7 } else { 9 }], - } - - #[repr(C)] - pub struct pthread_attr_t { - __u: pthread_attr_union, - } - - #[allow(non_camel_case_types)] - pub type pthread_t = *mut ffi::c_void; - - pub const _SC_NPROCESSORS_ONLN: ffi::c_int = 84; - - unsafe extern "C" { - pub fn pthread_create( - native: *mut pthread_t, - attr: *const pthread_attr_t, - f: extern "C" fn(*mut ffi::c_void) -> *mut ffi::c_void, - value: *mut ffi::c_void, - ) -> ffi::c_int; - pub fn pthread_join(native: pthread_t, value: *mut *mut ffi::c_void) -> ffi::c_int; - pub fn pthread_attr_init(attrp: *mut pthread_attr_t) -> ffi::c_int; - pub fn pthread_attr_setstacksize( - attr: *mut pthread_attr_t, - stack_size: libc::size_t, - ) -> ffi::c_int; - pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> ffi::c_int; - pub fn pthread_detach(thread: pthread_t) -> ffi::c_int; - } -} - -#[cfg(target_feature = "atomics")] -pub struct Thread { - id: libc::pthread_t, -} - -#[cfg(target_feature = "atomics")] -impl Drop for Thread { - fn drop(&mut self) { - let ret = unsafe { libc::pthread_detach(self.id) }; - debug_assert_eq!(ret, 0); - } -} - -pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; - -#[cfg(target_feature = "atomics")] -impl Thread { - // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, init: Box) -> io::Result { - let data = Box::into_raw(init); - let mut native: libc::pthread_t = unsafe { mem::zeroed() }; - let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() }; - assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0); - - let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE); - - match unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) } { - 0 => {} - n => { - assert_eq!(n, libc::EINVAL); - // EINVAL means |stack_size| is either too small or not a - // multiple of the system page size. Because it's definitely - // >= PTHREAD_STACK_MIN, it must be an alignment issue. - // Round up to the nearest page and try again. - let page_size = os::page_size(); - let stack_size = - (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0); - } - }; - - let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, data as *mut _) }; - // Note: if the thread creation fails and this assert fails, then data will - // be leaked. However, an alternative design could cause double-free - // which is clearly worse. - assert_eq!(unsafe { libc::pthread_attr_destroy(&mut attr) }, 0); - - return if ret != 0 { - // The thread failed to start and as a result data was not consumed. Therefore, it is - // safe to reconstruct the box so that it gets deallocated. - unsafe { - drop(Box::from_raw(data)); - } - Err(io::Error::from_raw_os_error(ret)) - } else { - Ok(Thread { id: native }) - }; - - extern "C" fn thread_start(data: *mut libc::c_void) -> *mut libc::c_void { - // SAFETY: we are simply recreating the box that was leaked earlier. - let init = unsafe { Box::from_raw(data as *mut ThreadInit) }; - let rust_start = init.init(); - rust_start(); - ptr::null_mut() - } - } - - pub fn join(self) { - let id = mem::ManuallyDrop::new(self).id; - let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; - if ret != 0 { - rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret)); - } - } -} - -#[cfg(target_feature = "atomics")] -pub fn available_parallelism() -> io::Result> { - match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } { - -1 => Err(io::Error::last_os_error()), - cpus => NonZero::new(cpus as usize).ok_or(io::Error::UNKNOWN_THREAD_COUNT), - } -} - -pub fn yield_now() { - let ret = unsafe { wasi::sched_yield() }; - debug_assert_eq!(ret, Ok(())); -} - -pub fn sleep(dur: Duration) { - let mut nanos = dur.as_nanos(); - while nanos > 0 { - const USERDATA: wasi::Userdata = 0x0123_45678; - - let clock = wasi::SubscriptionClock { - id: wasi::CLOCKID_MONOTONIC, - timeout: u64::try_from(nanos).unwrap_or(u64::MAX), - precision: 0, - flags: 0, - }; - nanos -= u128::from(clock.timeout); - - let in_ = wasi::Subscription { - userdata: USERDATA, - u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } }, - }; - unsafe { - let mut event: wasi::Event = mem::zeroed(); - let res = wasi::poll_oneoff(&in_, &mut event, 1); - match (res, event) { - ( - Ok(1), - wasi::Event { - userdata: USERDATA, - error: wasi::ERRNO_SUCCESS, - type_: wasi::EVENTTYPE_CLOCK, - .. - }, - ) => {} - _ => panic!("thread::sleep(): unexpected result of poll_oneoff"), - } - } - } -} diff --git a/library/std/src/sys/thread/wasip2.rs b/library/std/src/sys/thread/wasip2.rs deleted file mode 100644 index 420cad2a5e4a..000000000000 --- a/library/std/src/sys/thread/wasip2.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::time::{Duration, Instant}; - -pub fn sleep(dur: Duration) { - // Sleep in increments of `u64::MAX` nanoseconds until the `dur` is - // entirely drained. - let mut remaining = dur.as_nanos(); - while remaining > 0 { - let amt = u64::try_from(remaining).unwrap_or(u64::MAX); - wasip2::clocks::monotonic_clock::subscribe_duration(amt).block(); - remaining -= u128::from(amt); - } -} - -pub fn sleep_until(deadline: Instant) { - match u64::try_from(deadline.into_inner().as_duration().as_nanos()) { - // If the point in time we're sleeping to fits within a 64-bit - // number of nanoseconds then directly use `subscribe_instant`. - Ok(deadline) => { - wasip2::clocks::monotonic_clock::subscribe_instant(deadline).block(); - } - // ... otherwise we're sleeping for 500+ years relative to the - // "start" of what the system is using as a clock so speed/accuracy - // is not so much of a concern. Use `sleep` instead. - Err(_) => { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - sleep(delay); - } - } - } -} diff --git a/tests/rustdoc-js-std/unbox-type-result.js b/tests/rustdoc-js-std/unbox-type-result.js index 1f5cba58adf6..e4765d87637c 100644 --- a/tests/rustdoc-js-std/unbox-type-result.js +++ b/tests/rustdoc-js-std/unbox-type-result.js @@ -8,7 +8,6 @@ const EXPECTED = [ query: "File -> Metadata", others: [ { path: "std::fs::File", name: "metadata" }, - { path: "std::fs::File", name: "metadata_at" }, ] }, { diff --git a/triagebot.toml b/triagebot.toml index 6ad8dd6b4c88..db859bd54efb 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -455,8 +455,7 @@ trigger_files = [ [autolabel."O-wasi"] trigger_files = [ - "library/std/src/sys/pal/wasip1", - "library/std/src/sys/pal/wasip2", + "library/std/src/sys/pal/wasi", "library/std/src/os/wasi" ] From e0c09b546a1278ec185ba3d9348223ab11e1f394 Mon Sep 17 00:00:00 2001 From: Eduard Stefes Date: Mon, 8 Dec 2025 15:50:21 +0100 Subject: [PATCH 404/585] fix va_list test by adding a llvmir signext check s390x has no option to directly pass 32bit values therefor i32 parameters need an optional llvmir signext attribute. --- tests/codegen-llvm/cffi/c-variadic-va_list.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/codegen-llvm/cffi/c-variadic-va_list.rs b/tests/codegen-llvm/cffi/c-variadic-va_list.rs index e2652491f421..b2f5ffc3495b 100644 --- a/tests/codegen-llvm/cffi/c-variadic-va_list.rs +++ b/tests/codegen-llvm/cffi/c-variadic-va_list.rs @@ -22,15 +22,15 @@ // CHECK-LABEL: use_foreign_c_variadic_1_1 pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef 42) + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef{{( signext)?}} 42) foreign_c_variadic_1(ap, 42i32); } pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef 2, i32 noundef 42) + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef{{( signext)?}} 2, i32 noundef{{( signext)?}} 42) foreign_c_variadic_1(ap, 2i32, 42i32); } pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef 2, i32 noundef 42, i32 noundef 0) + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, i32 noundef{{( signext)?}} 2, i32 noundef{{( signext)?}} 42, i32 noundef{{( signext)?}} 0) foreign_c_variadic_1(ap, 2i32, 42i32, 0i32); } From cb49fe585458f2d0b2d4a37a53c72a989ad9a284 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 8 Dec 2025 16:26:26 +0000 Subject: [PATCH 405/585] Update list of allowed cg_clif dependencies --- src/tools/tidy/src/deps.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index bac426495c2f..592ba9c5c794 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -589,6 +589,7 @@ macro_rules! location { "region", "rustc-hash", "serde", + "serde_core", "serde_derive", "smallvec", "stable_deref_trait", From 8cf942d89fcaef9eea4a472cd2213856ba27ccc5 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Mon, 8 Dec 2025 19:56:47 +0300 Subject: [PATCH 406/585] Add inline attribute to generated delegation function if needed --- compiler/rustc_ast_lowering/src/delegation.rs | 28 +++++ tests/pretty/delegation_inline_attribute.pp | 94 ++++++++++++++++ tests/pretty/delegation_inline_attribute.rs | 104 ++++++++++++++++++ tests/pretty/hir-delegation.pp | 2 + 4 files changed, 228 insertions(+) create mode 100644 tests/pretty/delegation_inline_attribute.pp create mode 100644 tests/pretty/delegation_inline_attribute.rs diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index e6e88eff2d5b..0e7db7c9503c 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -44,6 +44,7 @@ use rustc_abi::ExternAbi; use rustc_ast::*; use rustc_errors::ErrorGuaranteed; +use rustc_hir::attrs::{AttributeKind, InlineAttr}; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; use rustc_middle::ty::{Asyncness, ResolverAstLowering}; @@ -87,6 +88,8 @@ pub(crate) fn lower_delegation( let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl); match sig_id { Ok(sig_id) => { + self.add_inline_attribute_if_needed(span); + let is_method = self.is_method(sig_id, span); let (param_count, c_variadic) = self.param_count(sig_id); let decl = self.lower_delegation_decl(sig_id, param_count, c_variadic, span); @@ -100,6 +103,31 @@ pub(crate) fn lower_delegation( } } + fn add_inline_attribute_if_needed(&mut self, span: Span) { + const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO; + let create_inline_attr_slice = + || [hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span))]; + + let new_attributes = match self.attrs.get(&PARENT_ID) { + Some(attrs) => { + // Check if reuse already specifies any inline attribute, if so, do nothing + if attrs + .iter() + .any(|a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..)))) + { + return; + } + + self.arena.alloc_from_iter( + attrs.into_iter().map(|a| a.clone()).chain(create_inline_attr_slice()), + ) + } + None => self.arena.alloc_from_iter(create_inline_attr_slice()), + }; + + self.attrs.insert(PARENT_ID, new_attributes); + } + fn get_delegation_sig_id( &self, item_id: NodeId, diff --git a/tests/pretty/delegation_inline_attribute.pp b/tests/pretty/delegation_inline_attribute.pp new file mode 100644 index 000000000000..4b3b2aa8f80a --- /dev/null +++ b/tests/pretty/delegation_inline_attribute.pp @@ -0,0 +1,94 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:delegation_inline_attribute.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] +#[attr = MacroUse {arguments: UseAll}] +extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; + +mod to_reuse { + fn foo(x: usize) -> usize { x } +} + +// Check that #[inline(hint)] is added to foo reuse +#[attr = Inline(Hint)] +fn bar(arg0: _) -> _ { to_reuse::foo(self + 1) } + +trait Trait { + fn foo(&self) { } + fn foo1(&self) { } + fn foo2(&self) { } + fn foo3(&self) { } + fn foo4(&self) { } +} + +impl Trait for u8 { } + +struct S(u8); + +mod to_import { + fn check(arg: &'_ u8) -> &'_ u8 { arg } +} + +impl Trait for S { + // Check that #[inline(hint)] is added to foo reuse + #[attr = Inline(Hint)] + fn foo(self: _) + -> + _ { + { + // Check that #[inline(hint)] is added to foo0 reuse inside another reuse + #[attr = Inline(Hint)] + fn foo0(arg0: _) -> _ { to_reuse::foo(self + 1) } + + // Check that #[inline(hint)] is added when other attributes present in inner reuse + #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = MustUse] + #[attr = Cold] + #[attr = Inline(Hint)] + fn foo1(arg0: _) -> _ { to_reuse::foo(self / 2) } + + // Check that #[inline(never)] is preserved in inner reuse + #[attr = Inline(Never)] + fn foo2(arg0: _) -> _ { to_reuse::foo(self / 2) } + + // Check that #[inline(always)] is preserved in inner reuse + #[attr = Inline(Always)] + fn foo3(arg0: _) -> _ { to_reuse::foo(self / 2) } + + // Check that #[inline(never)] is preserved when there are other attributes in inner reuse + #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = Inline(Never)] + #[attr = MustUse] + #[attr = Cold] + fn foo4(arg0: _) -> _ { to_reuse::foo(self / 2) } + }.foo() + } + + // Check that #[inline(hint)] is added when there are other attributes present in trait reuse + #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = MustUse] + #[attr = Cold] + #[attr = Inline(Hint)] + fn foo1(self: _) -> _ { self.0.foo1() } + + // Check that #[inline(never)] is preserved in trait reuse + #[attr = Inline(Never)] + fn foo2(self: _) -> _ { self.0.foo2() } + + // Check that #[inline(always)] is preserved in trait reuse + #[attr = Inline(Always)] + fn foo3(self: _) -> _ { self.0.foo3() } + + // Check that #[inline(never)] is preserved when there are other attributes in trait reuse + #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = Inline(Never)] + #[attr = MustUse] + #[attr = Cold] + fn foo4(self: _) -> _ { self.0.foo4() } +} + +fn main() { } diff --git a/tests/pretty/delegation_inline_attribute.rs b/tests/pretty/delegation_inline_attribute.rs new file mode 100644 index 000000000000..0716cfc51f5d --- /dev/null +++ b/tests/pretty/delegation_inline_attribute.rs @@ -0,0 +1,104 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:delegation_inline_attribute.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +mod to_reuse { + pub fn foo(x: usize) -> usize { + x + } +} + +// Check that #[inline(hint)] is added to foo reuse +reuse to_reuse::foo as bar { + self + 1 +} + +trait Trait { + fn foo(&self) {} + fn foo1(&self) {} + fn foo2(&self) {} + fn foo3(&self) {} + fn foo4(&self) {} +} + +impl Trait for u8 {} + +struct S(u8); + +mod to_import { + pub fn check(arg: &u8) -> &u8 { arg } +} + +impl Trait for S { + // Check that #[inline(hint)] is added to foo reuse + reuse Trait::foo { + // Check that #[inline(hint)] is added to foo0 reuse inside another reuse + reuse to_reuse::foo as foo0 { + self + 1 + } + + // Check that #[inline(hint)] is added when other attributes present in inner reuse + #[cold] + #[must_use] + #[deprecated] + reuse to_reuse::foo as foo1 { + self / 2 + } + + // Check that #[inline(never)] is preserved in inner reuse + #[inline(never)] + reuse to_reuse::foo as foo2 { + self / 2 + } + + // Check that #[inline(always)] is preserved in inner reuse + #[inline(always)] + reuse to_reuse::foo as foo3 { + self / 2 + } + + // Check that #[inline(never)] is preserved when there are other attributes in inner reuse + #[cold] + #[must_use] + #[inline(never)] + #[deprecated] + reuse to_reuse::foo as foo4 { + self / 2 + } + } + + // Check that #[inline(hint)] is added when there are other attributes present in trait reuse + #[cold] + #[must_use] + #[deprecated] + reuse Trait::foo1 { + self.0 + } + + // Check that #[inline(never)] is preserved in trait reuse + #[inline(never)] + reuse Trait::foo2 { + self.0 + } + + // Check that #[inline(always)] is preserved in trait reuse + #[inline(always)] + reuse Trait::foo3 { + self.0 + } + + // Check that #[inline(never)] is preserved when there are other attributes in trait reuse + #[cold] + #[must_use] + #[inline(never)] + #[deprecated] + reuse Trait::foo4 { + self.0 + } +} + +fn main() { +} diff --git a/tests/pretty/hir-delegation.pp b/tests/pretty/hir-delegation.pp index f8ad02f2fccc..b5f7a14eb2fc 100644 --- a/tests/pretty/hir-delegation.pp +++ b/tests/pretty/hir-delegation.pp @@ -12,6 +12,7 @@ use ::std::prelude::rust_2015::*; fn b(e: C) { } trait G { + #[attr = Inline(Hint)] fn b(arg0: _) -> _ { b({ }) } } @@ -19,6 +20,7 @@ mod m { fn add(a: u32, b: u32) -> u32 { a + b } } +#[attr = Inline(Hint)] fn add(arg0: _, arg1: _) -> _ { m::add(arg0, arg1) } fn main() { { let _ = add(1, 2); }; } From 4648af67516fe0387f287486b5f19f7518032423 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 8 Dec 2025 18:42:10 +0100 Subject: [PATCH 407/585] Remove `[no-mentions]` handler in our triagebot config https://github.blog/changelog/2025-11-07-removing-notifications-for-mentions-in-commit-messages/ --- triagebot.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 6633b87f04e8..09dec7675e7e 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -22,9 +22,6 @@ allow-unauthenticated = [ [mentions."clippy_lints/src/doc"] cc = ["@notriddle"] -# Prevents mentions in commits to avoid users being spammed -[no-mentions] - # Have rustbot inform users about the *No Merge Policy* [no-merges] exclude_titles = ["Rustup"] # exclude syncs from rust-lang/rust From 27a4aabffc40beda87c5990cb9b3c95e56177da9 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 8 Dec 2025 18:52:46 +0100 Subject: [PATCH 408/585] =?UTF-8?q?Fix=20typo=20"an"=20=E2=86=92=20"and"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- library/std/src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 8b3e943b4ccd..d14d0ad2f0ea 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1324,7 +1324,7 @@ fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { /// /// # Platform-specific behavior /// - /// This function currently returns `true` on Unix an `false` on Windows. + /// This function currently returns `true` on Unix and `false` on Windows. /// Note that this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior @@ -1385,7 +1385,7 @@ fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { /// /// # Platform-specific behavior /// - /// This function currently returns `true` on Unix an `false` on Windows. + /// This function currently returns `true` on Unix and `false` on Windows. /// Note that this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior From b8581ddecc2adb994f8ddd54a8c3dc3205dec547 Mon Sep 17 00:00:00 2001 From: Urgau <3616612+Urgau@users.noreply.github.com> Date: Mon, 8 Dec 2025 19:34:19 +0100 Subject: [PATCH 409/585] Remove `[no-mentions]` handler in the triagebot config https://github.blog/changelog/2025-11-07-removing-notifications-for-mentions-in-commit-messages/ --- triagebot.toml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 6ad8dd6b4c88..c459f69d06bb 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1680,12 +1680,6 @@ days-threshold = 28 # Documentation at: https://forge.rust-lang.org/triagebot/issue-links.html [issue-links] -# Prevents mentions in commits to avoid users being spammed -# Documentation at: https://forge.rust-lang.org/triagebot/no-mentions.html -[no-mentions] -# Subtree update authors can't fix it, no point in warning. -exclude-titles = ["subtree update"] - # Allow members to formally register concerns (`@rustbot concern my concern`) # Documentation at: https://forge.rust-lang.org/triagebot/concern.html [concern] From 5a1936fd3fd21fd2f7459ab6f6b886b7aea5ad30 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 8 Dec 2025 19:11:04 +0000 Subject: [PATCH 410/585] Revert build_llvm_sysroot_for_triple back from reading the manifest to filtering Reading the manifest doesn't work when running in the context of the rust build system. --- .../build_system/build_sysroot.rs | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs index e7363e37a45d..7b4c604580c1 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs @@ -161,18 +161,35 @@ fn build_sysroot_for_triple( fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget { let default_sysroot = crate::rustc_info::get_default_sysroot(&compiler.rustc); - let std_manifest_path = default_sysroot - .join("lib") - .join("rustlib") - .join(format!("manifest-rust-std-{}", compiler.triple)); + let mut target_libs = SysrootTarget { triple: compiler.triple, libs: vec![] }; - let libs = fs::read_to_string(std_manifest_path) - .unwrap() - .lines() - .map(|entry| default_sysroot.join(entry.strip_prefix("file:").unwrap())) - .collect(); + for entry in fs::read_dir( + default_sysroot.join("lib").join("rustlib").join(&target_libs.triple).join("lib"), + ) + .unwrap() + { + let entry = entry.unwrap(); + if entry.file_type().unwrap().is_dir() { + continue; + } + let file = entry.path(); + let file_name_str = file.file_name().unwrap().to_str().unwrap(); + if (file_name_str.contains("rustc_") + && !file_name_str.contains("rustc_std_workspace_") + && !file_name_str.contains("rustc_demangle") + && !file_name_str.contains("rustc_literal_escaper")) + || file_name_str.contains("chalk") + || file_name_str.contains("tracing") + || file_name_str.contains("regex") + { + // These are large crates that are part of the rustc-dev component and are not + // necessary to run regular programs. + continue; + } + target_libs.libs.push(file); + } - SysrootTarget { triple: compiler.triple, libs } + target_libs } fn build_clif_sysroot_for_triple( From 90d2477e4e35927b20237b27869200fb1d47e7bf Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 4 Dec 2025 09:49:31 -0800 Subject: [PATCH 411/585] Add release notes for 1.92.0 --- RELEASES.md | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index b14cc499b46d..0dffe931e6eb 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,88 @@ +Version 1.92.0 (2025-12-11) +========================== + + + +Language +-------- +- [Document `MaybeUninit` representation and validity](https://github.com/rust-lang/rust/pull/140463) +- [Allow `&raw [mut | const]` for union field in safe code](https://github.com/rust-lang/rust/pull/141469) +- [Prefer item bounds of associated types over where-bounds for auto-traits and `Sized`](https://github.com/rust-lang/rust/pull/144064) +- [Do not materialize `X` in `[X; 0]` when `X` is unsizing a const](https://github.com/rust-lang/rust/pull/145277) +- [Support combining `#[track_caller]` and `#[no_mangle]` (requires every declaration specifying `#[track_caller]` as well)](https://github.com/rust-lang/rust/pull/145724) +- [Make never type lints `never_type_fallback_flowing_into_unsafe` and `dependency_on_unit_never_type_fallback` deny-by-default](https://github.com/rust-lang/rust/pull/146167) +- [Allow specifying multiple bounds for same associated item, except in trait objects](https://github.com/rust-lang/rust/pull/146593) +- [Slightly strengthen higher-ranked region handling in coherence](https://github.com/rust-lang/rust/pull/146725) +- [The `unused_must_use` lint no longer warns on `Result<(), Uninhabited>` (for instance, `Result<(), !>`), or `ControlFlow`](https://github.com/rust-lang/rust/pull/147382). This avoids having to check for an error that can never happen. + + + +Compiler +-------- +- [Make `mips64el-unknown-linux-muslabi64` link dynamically](https://github.com/rust-lang/rust/pull/146858) +- [Remove current code for embedding command-line args in PDB](https://github.com/rust-lang/rust/pull/147022) + Command-line information is typically not needed by debugging tools, and the removed code + was causing problems for incremental builds even on targets that don't use PDB debuginfo. + + + +Libraries +--------- +- [Specialize `Iterator::eq{_by}` for `TrustedLen` iterators](https://github.com/rust-lang/rust/pull/137122) +- [Simplify `Extend` for tuples](https://github.com/rust-lang/rust/pull/138799) +- [Added details to `Debug` for `EncodeWide`](https://github.com/rust-lang/rust/pull/140153). +- [`iter::Repeat::last`](https://github.com/rust-lang/rust/pull/147258) and [`count`](https://github.com/rust-lang/rust/pull/146410) will now panic, rather than looping infinitely. + + + +Stabilized APIs +--------------- + +- [`NonZero::div_ceil`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.div_ceil) +- [`Location::file_as_c_str`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.file_as_c_str) +- [`RwLockWriteGuard::downgrade`](https://doc.rust-lang.org/stable/std/sync/struct.RwLockWriteGuard.html#method.downgrade) +- [`Box::new_zeroed`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.new_zeroed) +- [`Box::new_zeroed_slice`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.new_zeroed_slice) +- [`Rc::new_zeroed`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.new_zeroed) +- [`Rc::new_zeroed_slice`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.new_zeroed_slice) +- [`Arc::new_zeroed`](https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.new_zeroed) +- [`Arc::new_zeroed_slice`](https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.new_zeroed_slice) +- [`btree_map::Entry::insert_entry`](https://doc.rust-lang.org/stable/std/collections/btree_map/enum.Entry.html#method.insert_entry) +- [`btree_map::VacantEntry::insert_entry`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.VacantEntry.html#method.insert_entry) +- [`impl Extend for proc_macro::TokenStream`](https://doc.rust-lang.org/stable/proc_macro/struct.TokenStream.html#impl-Extend%3CGroup%3E-for-TokenStream) +- [`impl Extend for proc_macro::TokenStream`](https://doc.rust-lang.org/stable/proc_macro/struct.TokenStream.html#impl-Extend%3CLiteral%3E-for-TokenStream) +- [`impl Extend for proc_macro::TokenStream`](https://doc.rust-lang.org/stable/proc_macro/struct.TokenStream.html#impl-Extend%3CPunct%3E-for-TokenStream) +- [`impl Extend for proc_macro::TokenStream`](https://doc.rust-lang.org/stable/proc_macro/struct.TokenStream.html#impl-Extend%3CIdent%3E-for-TokenStream) + +These previously stable APIs are now stable in const contexts: + +- [`<[_]>::rotate_left`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.rotate_left) +- [`<[_]>::rotate_right`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.rotate_right) + + + +Cargo +----- +- [Added a new chapter](https://github.com/rust-lang/cargo/issues/16119) to the Cargo book, ["Optimizing Build Performance"](https://doc.rust-lang.org/stable/cargo/guide/build-performance.html). + + + +Rustdoc +----- +- [If a trait item appears in rustdoc search, hide the corresponding impl items](https://github.com/rust-lang/rust/pull/145898). Previously a search for "last" would show both `Iterator::last` as well as impl methods like `std::vec::IntoIter::last`. Now these impl methods will be hidden, freeing up space for inherent methods like `BTreeSet::last`. +- [Relax rules for identifiers in search](https://github.com/rust-lang/rust/pull/147860). Previously you could only search for identifiers that were valid in rust code, now searches only need to be valid as part of an identifier. For example, you can now perform a search that starts with a digit. + + + +Compatibility Notes +------------------- +* [Fix backtraces with `-C panic=abort` on Linux by generating unwind tables by default](https://github.com/rust-lang/rust/pull/143613). Build with `-C force-unwind-tables=no` to keep omitting unwind tables. +- As part of the larger effort refactoring compiler built-in attributes and their diagnostics, [the future-compatibility lint `invalid_macro_export_arguments` is upgraded to deny-by-default and will be reported in dependencies too.](https://github.com/rust-lang/rust/pull/143857) +- [Update the minimum external LLVM to 20](https://github.com/rust-lang/rust/pull/145071) +- [Prevent downstream `impl DerefMut for Pin`](https://github.com/rust-lang/rust/pull/145608) +- [Don't apply temporary lifetime extension rules to the arguments of non-extended `pin!` and formatting macros](https://github.com/rust-lang/rust/pull/145838) + + Version 1.91.1 (2025-11-10) =========================== From 01e2cf8f44b0d99c019f292140cfc58b9bc67501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 15 Sep 2025 02:28:43 -0700 Subject: [PATCH 412/585] Handle macro invocation in attribute during parse ``` error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro `concat` --> $DIR/macro-in-attribute.rs:4:21 | LL | #[deprecated(note = concat!("a", "b"))] | ^^^^^^^^^^^^^^^^^ macros are not allowed here ``` --- compiler/rustc_attr_parsing/messages.ftl | 1 + compiler/rustc_attr_parsing/src/parser.rs | 40 ++++++++++++++----- .../src/session_diagnostics.rs | 2 + .../rustc_parse/src/parser/diagnostics.rs | 2 +- tests/ui/parser/macro/macro-in-attribute.rs | 9 +++++ .../ui/parser/macro/macro-in-attribute.stderr | 8 ++++ 6 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 tests/ui/parser/macro/macro-in-attribute.rs create mode 100644 tests/ui/parser/macro/macro-in-attribute.stderr diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 0d53ed9d97a5..5cb34f96d130 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -87,6 +87,7 @@ attr_parsing_invalid_link_modifier = attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr} .remove_neg_sugg = negative numbers are not literals, try removing the `-` sign .quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal + .label = macros are not allowed here attr_parsing_invalid_predicate = invalid predicate `{$predicate}` diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 7474471f2fe0..23f0e4fa0330 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -13,7 +13,7 @@ use rustc_errors::{Diag, PResult}; use rustc_hir::{self as hir, AttrPath}; use rustc_parse::exp; -use rustc_parse::parser::{Parser, PathStyle, token_descr}; +use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr}; use rustc_session::errors::{create_lit_error, report_lit_error}; use rustc_session::parse::ParseSess; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym}; @@ -488,6 +488,7 @@ fn expected_lit(&mut self) -> Diag<'sess> { descr: token_descr(&self.parser.token), quote_ident_sugg: None, remove_neg_sugg: None, + macro_call: None, }; // Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and @@ -496,20 +497,37 @@ fn expected_lit(&mut self) -> Diag<'sess> { if self.parser.prev_token == token::Eq && let token::Ident(..) = self.parser.token.kind { - let before = self.parser.token.span.shrink_to_lo(); - while let token::Ident(..) = self.parser.token.kind { - self.parser.bump(); + if self.parser.look_ahead(1, |t| matches!(t.kind, token::TokenKind::Bang)) { + let snapshot = self.parser.create_snapshot_for_diagnostic(); + let stmt = self.parser.parse_stmt_without_recovery(false, ForceCollect::No, false); + match stmt { + Ok(Some(stmt)) => { + // The user tried to write something like + // `#[deprecated(note = concat!("a", "b"))]`. + err.descr = format!("macro {}", err.descr); + err.macro_call = Some(stmt.span); + err.span = stmt.span; + } + Ok(None) => {} + Err(err) => { + err.cancel(); + self.parser.restore_snapshot(snapshot); + } + } + } else { + let before = self.parser.token.span.shrink_to_lo(); + while let token::Ident(..) = self.parser.token.kind { + self.parser.bump(); + } + err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg { + before, + after: self.parser.prev_token.span.shrink_to_hi(), + }); } - err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg { - before, - after: self.parser.prev_token.span.shrink_to_hi(), - }); } if self.parser.token == token::Minus - && self - .parser - .look_ahead(1, |t| matches!(t.kind, rustc_ast::token::TokenKind::Literal { .. })) + && self.parser.look_ahead(1, |t| matches!(t.kind, token::TokenKind::Literal { .. })) { err.remove_neg_sugg = Some(InvalidMetaItemRemoveNegSugg { negative_sign: self.parser.token.span }); diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index c4f6f9c6a38c..95eca25fd362 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -804,6 +804,8 @@ pub(crate) struct InvalidMetaItem { pub quote_ident_sugg: Option, #[subdiagnostic] pub remove_neg_sugg: Option, + #[label] + pub macro_call: Option, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index d4667a09af6d..4f6860fead8d 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -284,7 +284,7 @@ pub fn dcx(&self) -> DiagCtxtHandle<'a> { } /// Replace `self` with `snapshot.parser`. - pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) { + pub fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) { *self = snapshot.parser; } diff --git a/tests/ui/parser/macro/macro-in-attribute.rs b/tests/ui/parser/macro/macro-in-attribute.rs new file mode 100644 index 000000000000..57808c6fd27d --- /dev/null +++ b/tests/ui/parser/macro/macro-in-attribute.rs @@ -0,0 +1,9 @@ +// Test for #146325. +// Ensure that when we encounter a macro invocation in an attribute, we don't suggest nonsense. + +#[deprecated(note = concat!("a", "b"))] +struct X; +//~^^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro `concat` +//~| NOTE: macros are not allowed here + +fn main() {} diff --git a/tests/ui/parser/macro/macro-in-attribute.stderr b/tests/ui/parser/macro/macro-in-attribute.stderr new file mode 100644 index 000000000000..e0ae51365a85 --- /dev/null +++ b/tests/ui/parser/macro/macro-in-attribute.stderr @@ -0,0 +1,8 @@ +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro `concat` + --> $DIR/macro-in-attribute.rs:4:21 + | +LL | #[deprecated(note = concat!("a", "b"))] + | ^^^^^^^^^^^^^^^^^ macros are not allowed here + +error: aborting due to 1 previous error + From 0b0e826c0fc09eb54487658ab782e816d92619d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 28 Sep 2025 20:52:57 +0000 Subject: [PATCH 413/585] Rework attribute recovery logic --- compiler/rustc_ast/src/ast.rs | 13 +++ compiler/rustc_attr_parsing/messages.ftl | 2 +- compiler/rustc_attr_parsing/src/parser.rs | 80 ++++++++++--------- .../src/session_diagnostics.rs | 2 +- tests/ui/attributes/malformed-fn-align.rs | 2 +- tests/ui/attributes/malformed-fn-align.stderr | 4 +- ...-66340-deprecated-attr-non-meta-grammar.rs | 2 +- ...40-deprecated-attr-non-meta-grammar.stderr | 4 +- tests/ui/parser/attribute/attr-bad-meta-4.rs | 2 +- .../parser/attribute/attr-bad-meta-4.stderr | 4 +- .../parser/attribute/attr-unquoted-ident.rs | 19 +++-- .../attribute/attr-unquoted-ident.stderr | 25 ++++-- tests/ui/parser/macro/expr-in-attribute.rs | 9 +++ .../ui/parser/macro/expr-in-attribute.stderr | 8 ++ tests/ui/parser/macro/macro-in-attribute.rs | 2 +- .../ui/parser/macro/macro-in-attribute.stderr | 2 +- 16 files changed, 116 insertions(+), 64 deletions(-) create mode 100644 tests/ui/parser/macro/expr-in-attribute.rs create mode 100644 tests/ui/parser/macro/expr-in-attribute.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index db7cace49ae8..b696ebeba992 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1259,6 +1259,19 @@ pub enum StmtKind { MacCall(Box), } +impl StmtKind { + pub fn descr(&self) -> &'static str { + match self { + StmtKind::Let(_) => "local", + StmtKind::Item(_) => "item", + StmtKind::Expr(_) => "expression", + StmtKind::Semi(_) => "statement", + StmtKind::Empty => "semicolon", + StmtKind::MacCall(_) => "macro", + } + } +} + #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct MacCallStmt { pub mac: Box, diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 5cb34f96d130..02ddf8ac0023 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -87,7 +87,7 @@ attr_parsing_invalid_link_modifier = attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr} .remove_neg_sugg = negative numbers are not literals, try removing the `-` sign .quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal - .label = macros are not allowed here + .label = {$descr}s are not allowed here attr_parsing_invalid_predicate = invalid predicate `{$predicate}` diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 23f0e4fa0330..819e5630561d 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -8,7 +8,7 @@ use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path}; +use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path, StmtKind, UnOp}; use rustc_ast_pretty::pprust; use rustc_errors::{Diag, PResult}; use rustc_hir::{self as hir, AttrPath}; @@ -488,51 +488,55 @@ fn expected_lit(&mut self) -> Diag<'sess> { descr: token_descr(&self.parser.token), quote_ident_sugg: None, remove_neg_sugg: None, - macro_call: None, + label: None, }; + if let token::OpenInvisible(_) = self.parser.token.kind { + // Do not attempt to suggest anything when encountered as part of a macro expansion. + return self.parser.dcx().create_err(err); + } + // Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and // don't `uninterpolate` the token to avoid suggesting anything butchered or questionable // when macro metavariables are involved. - if self.parser.prev_token == token::Eq - && let token::Ident(..) = self.parser.token.kind - { - if self.parser.look_ahead(1, |t| matches!(t.kind, token::TokenKind::Bang)) { - let snapshot = self.parser.create_snapshot_for_diagnostic(); - let stmt = self.parser.parse_stmt_without_recovery(false, ForceCollect::No, false); - match stmt { - Ok(Some(stmt)) => { - // The user tried to write something like - // `#[deprecated(note = concat!("a", "b"))]`. - err.descr = format!("macro {}", err.descr); - err.macro_call = Some(stmt.span); - err.span = stmt.span; - } - Ok(None) => {} - Err(err) => { - err.cancel(); - self.parser.restore_snapshot(snapshot); + let snapshot = self.parser.create_snapshot_for_diagnostic(); + let stmt = self.parser.parse_stmt_without_recovery(false, ForceCollect::No, false); + match stmt { + Ok(Some(stmt)) => { + // The user tried to write something like + // `#[deprecated(note = concat!("a", "b"))]`. + err.descr = stmt.kind.descr().to_string(); + err.label = Some(stmt.span); + err.span = stmt.span; + if let StmtKind::Expr(expr) = &stmt.kind + && let ExprKind::Unary(UnOp::Neg, val) = &expr.kind + && let ExprKind::Lit(_) = val.kind + { + err.remove_neg_sugg = Some(InvalidMetaItemRemoveNegSugg { + negative_sign: expr.span.until(val.span), + }); + } else if let StmtKind::Expr(expr) = &stmt.kind + && let ExprKind::Path(None, Path { segments, .. }) = &expr.kind + && segments.len() == 1 + { + while let token::Ident(..) | token::Literal(_) | token::Dot = + self.parser.token.kind + { + // We've got a word, so we try to consume the rest of a potential sentence. + // We include `.` to correctly handle things like `A sentence here.`. + self.parser.bump(); } + err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg { + before: expr.span.shrink_to_lo(), + after: self.parser.prev_token.span.shrink_to_hi(), + }); } - } else { - let before = self.parser.token.span.shrink_to_lo(); - while let token::Ident(..) = self.parser.token.kind { - self.parser.bump(); - } - err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg { - before, - after: self.parser.prev_token.span.shrink_to_hi(), - }); } - } - - if self.parser.token == token::Minus - && self.parser.look_ahead(1, |t| matches!(t.kind, token::TokenKind::Literal { .. })) - { - err.remove_neg_sugg = - Some(InvalidMetaItemRemoveNegSugg { negative_sign: self.parser.token.span }); - self.parser.bump(); - self.parser.bump(); + Ok(None) => {} + Err(e) => { + e.cancel(); + self.parser.restore_snapshot(snapshot); + } } self.parser.dcx().create_err(err) diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 95eca25fd362..2b3108a8d3ed 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -805,7 +805,7 @@ pub(crate) struct InvalidMetaItem { #[subdiagnostic] pub remove_neg_sugg: Option, #[label] - pub macro_call: Option, + pub label: Option, } #[derive(Subdiagnostic)] diff --git a/tests/ui/attributes/malformed-fn-align.rs b/tests/ui/attributes/malformed-fn-align.rs index c76eda65a75b..219218f03479 100644 --- a/tests/ui/attributes/malformed-fn-align.rs +++ b/tests/ui/attributes/malformed-fn-align.rs @@ -26,7 +26,7 @@ fn f3() {} #[repr(align(16))] //~ ERROR `#[repr(align(...))]` is not supported on functions fn f4() {} -#[rustc_align(-1)] //~ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-` +#[rustc_align(-1)] //~ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found fn f5() {} #[rustc_align(3)] //~ ERROR invalid alignment value: not a power of two diff --git a/tests/ui/attributes/malformed-fn-align.stderr b/tests/ui/attributes/malformed-fn-align.stderr index 33f789b62695..b419df8ea2d1 100644 --- a/tests/ui/attributes/malformed-fn-align.stderr +++ b/tests/ui/attributes/malformed-fn-align.stderr @@ -37,11 +37,11 @@ error[E0589]: invalid alignment value: not a power of two LL | #[rustc_align(0)] | ^ -error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-` +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression --> $DIR/malformed-fn-align.rs:29:15 | LL | #[rustc_align(-1)] - | ^ + | ^^ expressions are not allowed here | help: negative numbers are not literals, try removing the `-` sign | diff --git a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs index 378d0a3e7235..cdf2b76a1ccc 100644 --- a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs +++ b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs @@ -7,5 +7,5 @@ fn main() { } #[deprecated(note = test)] -//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `test` +//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found fn foo() {} diff --git a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr index cd985ab5a182..379c7f581224 100644 --- a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr +++ b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr @@ -1,8 +1,8 @@ -error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `test` +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression --> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:9:21 | LL | #[deprecated(note = test)] - | ^^^^ + | ^^^^ expressions are not allowed here | help: surround the identifier with quotation marks to make it into a string literal | diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.rs b/tests/ui/parser/attribute/attr-bad-meta-4.rs index 606b41e89a5f..bfd2958ad565 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.rs +++ b/tests/ui/parser/attribute/attr-bad-meta-4.rs @@ -9,7 +9,7 @@ macro_rules! mac { mac!(an(arbitrary token stream)); #[cfg(feature = -1)] -//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-` +//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found fn handler() {} fn main() {} diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.stderr b/tests/ui/parser/attribute/attr-bad-meta-4.stderr index 1d939942fb9a..8f4edca226d3 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.stderr +++ b/tests/ui/parser/attribute/attr-bad-meta-4.stderr @@ -1,8 +1,8 @@ -error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-` +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression --> $DIR/attr-bad-meta-4.rs:11:17 | LL | #[cfg(feature = -1)] - | ^ + | ^^ expressions are not allowed here | help: negative numbers are not literals, try removing the `-` sign | diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.rs b/tests/ui/parser/attribute/attr-unquoted-ident.rs index 8a0c65b783a7..152448bf8a0f 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.rs +++ b/tests/ui/parser/attribute/attr-unquoted-ident.rs @@ -4,14 +4,21 @@ fn main() { #[cfg(key=foo)] - //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo` - //~| HELP surround the identifier with quotation marks to make it into a string literal + //~^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found + //~| HELP: surround the identifier with quotation marks to make it into a string literal + //~| NOTE: expressions are not allowed here println!(); #[cfg(key="bar")] println!(); #[cfg(key=foo bar baz)] - //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo` - //~| HELP surround the identifier with quotation marks to make it into a string literal + //~^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found + //~| HELP: surround the identifier with quotation marks to make it into a string literal + //~| NOTE: expressions are not allowed here + println!(); + #[cfg(key=foo 1 bar 2.0 baz.)] + //~^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found + //~| HELP: surround the identifier with quotation marks to make it into a string literal + //~| NOTE: expressions are not allowed here println!(); } @@ -19,7 +26,7 @@ fn main() { macro_rules! make { ($name:ident) => { #[doc(alias = $name)] pub struct S; } - //~^ ERROR expected unsuffixed literal, found identifier `nickname` + //~^ ERROR: expected unsuffixed literal, found identifier `nickname` } -make!(nickname); //~ NOTE in this expansion +make!(nickname); //~ NOTE: in this expansion diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.stderr b/tests/ui/parser/attribute/attr-unquoted-ident.stderr index 8a2785280adc..f1af60dec9bb 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.stderr +++ b/tests/ui/parser/attribute/attr-unquoted-ident.stderr @@ -1,27 +1,38 @@ -error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo` +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression --> $DIR/attr-unquoted-ident.rs:6:15 | LL | #[cfg(key=foo)] - | ^^^ + | ^^^ expressions are not allowed here | help: surround the identifier with quotation marks to make it into a string literal | LL | #[cfg(key="foo")] | + + -error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo` - --> $DIR/attr-unquoted-ident.rs:12:15 +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression + --> $DIR/attr-unquoted-ident.rs:13:15 | LL | #[cfg(key=foo bar baz)] - | ^^^ + | ^^^ expressions are not allowed here | help: surround the identifier with quotation marks to make it into a string literal | LL | #[cfg(key="foo bar baz")] | + + +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression + --> $DIR/attr-unquoted-ident.rs:18:15 + | +LL | #[cfg(key=foo 1 bar 2.0 baz.)] + | ^^^ expressions are not allowed here + | +help: surround the identifier with quotation marks to make it into a string literal + | +LL | #[cfg(key="foo 1 bar 2.0 baz.")] + | + + + error: expected unsuffixed literal, found identifier `nickname` - --> $DIR/attr-unquoted-ident.rs:21:38 + --> $DIR/attr-unquoted-ident.rs:28:38 | LL | ($name:ident) => { #[doc(alias = $name)] pub struct S; } | ^^^^^ @@ -31,5 +42,5 @@ LL | make!(nickname); | = note: this error originates in the macro `make` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/parser/macro/expr-in-attribute.rs b/tests/ui/parser/macro/expr-in-attribute.rs new file mode 100644 index 000000000000..8c8934493361 --- /dev/null +++ b/tests/ui/parser/macro/expr-in-attribute.rs @@ -0,0 +1,9 @@ +// Test for #146325. +// Ensure that when we encounter an expr invocation in an attribute, we don't suggest nonsense. + +#[deprecated(note = a!=b)] +struct X; +//~^^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression +//~| NOTE: expressions are not allowed here + +fn main() {} diff --git a/tests/ui/parser/macro/expr-in-attribute.stderr b/tests/ui/parser/macro/expr-in-attribute.stderr new file mode 100644 index 000000000000..08d6f12d1e64 --- /dev/null +++ b/tests/ui/parser/macro/expr-in-attribute.stderr @@ -0,0 +1,8 @@ +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression + --> $DIR/expr-in-attribute.rs:4:21 + | +LL | #[deprecated(note = a!=b)] + | ^^^^ expressions are not allowed here + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/macro/macro-in-attribute.rs b/tests/ui/parser/macro/macro-in-attribute.rs index 57808c6fd27d..efb7de9f01c4 100644 --- a/tests/ui/parser/macro/macro-in-attribute.rs +++ b/tests/ui/parser/macro/macro-in-attribute.rs @@ -3,7 +3,7 @@ #[deprecated(note = concat!("a", "b"))] struct X; -//~^^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro `concat` +//~^^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found //~| NOTE: macros are not allowed here fn main() {} diff --git a/tests/ui/parser/macro/macro-in-attribute.stderr b/tests/ui/parser/macro/macro-in-attribute.stderr index e0ae51365a85..08fb66440757 100644 --- a/tests/ui/parser/macro/macro-in-attribute.stderr +++ b/tests/ui/parser/macro/macro-in-attribute.stderr @@ -1,4 +1,4 @@ -error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro `concat` +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro --> $DIR/macro-in-attribute.rs:4:21 | LL | #[deprecated(note = concat!("a", "b"))] From c1500f986f2a814378714b5a7939f4d43350c121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 3 Nov 2025 19:21:31 +0000 Subject: [PATCH 414/585] review comment --- compiler/rustc_ast/src/ast.rs | 2 +- tests/ui/parser/macro/macro-in-attribute.rs | 2 +- tests/ui/parser/macro/macro-in-attribute.stderr | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b696ebeba992..78da2fa9163c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1267,7 +1267,7 @@ pub fn descr(&self) -> &'static str { StmtKind::Expr(_) => "expression", StmtKind::Semi(_) => "statement", StmtKind::Empty => "semicolon", - StmtKind::MacCall(_) => "macro", + StmtKind::MacCall(_) => "macro call", } } } diff --git a/tests/ui/parser/macro/macro-in-attribute.rs b/tests/ui/parser/macro/macro-in-attribute.rs index efb7de9f01c4..7a4b3b22baa9 100644 --- a/tests/ui/parser/macro/macro-in-attribute.rs +++ b/tests/ui/parser/macro/macro-in-attribute.rs @@ -4,6 +4,6 @@ #[deprecated(note = concat!("a", "b"))] struct X; //~^^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found -//~| NOTE: macros are not allowed here +//~| NOTE: macro calls are not allowed here fn main() {} diff --git a/tests/ui/parser/macro/macro-in-attribute.stderr b/tests/ui/parser/macro/macro-in-attribute.stderr index 08fb66440757..d057c93ede07 100644 --- a/tests/ui/parser/macro/macro-in-attribute.stderr +++ b/tests/ui/parser/macro/macro-in-attribute.stderr @@ -1,8 +1,8 @@ -error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro call --> $DIR/macro-in-attribute.rs:4:21 | LL | #[deprecated(note = concat!("a", "b"))] - | ^^^^^^^^^^^^^^^^^ macros are not allowed here + | ^^^^^^^^^^^^^^^^^ macro calls are not allowed here error: aborting due to 1 previous error From 761cb57aef119745ed8eab68f03508a1e5950d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Dec 2025 01:20:58 +0000 Subject: [PATCH 415/585] fix test --- tests/ui/macros/cfg_select.rs | 2 +- tests/ui/macros/cfg_select.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/macros/cfg_select.rs b/tests/ui/macros/cfg_select.rs index 2a627cc05b93..586e4037d7c1 100644 --- a/tests/ui/macros/cfg_select.rs +++ b/tests/ui/macros/cfg_select.rs @@ -68,7 +68,7 @@ fn arm_rhs_expr_3() -> i32 { cfg_select! { () => {} - //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `(` + //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression } cfg_select! { diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr index 3a5d2b0a1e1e..a14e24334661 100644 --- a/tests/ui/macros/cfg_select.stderr +++ b/tests/ui/macros/cfg_select.stderr @@ -27,11 +27,11 @@ error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>` LL | => {} | ^^ -error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `(` +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression --> $DIR/cfg_select.rs:70:5 | LL | () => {} - | ^ + | ^^ expressions are not allowed here error[E0539]: malformed `cfg_select` macro input --> $DIR/cfg_select.rs:75:5 From 5c91f2c4d3635192cbed539c0c3ef88e4bfdd2a5 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 8 Dec 2025 22:41:13 +1100 Subject: [PATCH 416/585] Make `--print=backend-has-zstd` work by default on any backend Using a defaulted `CodegenBackend` method that querying for zstd support should automatically print a safe value of `false` on any backend that doesn't specifically indicate the presence or absence of zstd. --- compiler/rustc_codegen_cranelift/src/lib.rs | 12 +----------- compiler/rustc_codegen_llvm/src/lib.rs | 8 ++++---- compiler/rustc_codegen_ssa/src/traits/backend.rs | 8 ++++++++ compiler/rustc_driver_impl/src/lib.rs | 5 ++++- src/tools/compiletest/src/directives/needs.rs | 4 ++++ 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index b47b9afa4f07..5fdecd014ac0 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -47,7 +47,7 @@ use rustc_log::tracing::info; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; -use rustc_session::config::{OutputFilenames, PrintKind, PrintRequest}; +use rustc_session::config::OutputFilenames; use rustc_span::{Symbol, sym}; use rustc_target::spec::{Abi, Arch, Env, Os}; @@ -160,16 +160,6 @@ fn init(&self, sess: &Session) { } } - fn print(&self, req: &PrintRequest, out: &mut String, _sess: &Session) { - match req.kind { - // FIXME have a default impl that returns false - PrintKind::BackendHasZstd => { - out.push_str("false\n"); - } - _ => {} - } - } - fn target_config(&self, sess: &Session) -> TargetConfig { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] let target_features = match sess.target.arch { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 8c0c0afcc1dd..0da5810518c5 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -257,10 +257,6 @@ fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) { } writeln!(out).unwrap(); } - PrintKind::BackendHasZstd => { - let has_zstd = llvm::LLVMRustLLVMHasZstdCompression(); - writeln!(out, "{has_zstd}").unwrap(); - } PrintKind::CodeModels => { writeln!(out, "Available code models:").unwrap(); for name in &["tiny", "small", "kernel", "medium", "large"] { @@ -314,6 +310,10 @@ fn print_version(&self) { llvm_util::print_version(); } + fn has_zstd(&self) -> bool { + llvm::LLVMRustLLVMHasZstdCompression() + } + fn target_config(&self, sess: &Session) -> TargetConfig { target_config(sess) } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 85bff4540814..cb74e2e46d65 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -78,6 +78,14 @@ fn print_passes(&self) {} fn print_version(&self) {} + /// Value printed by `--print=backend-has-zstd`. + /// + /// Used by compiletest to determine whether tests involving zstd compression + /// (e.g. `-Zdebuginfo-compression=zstd`) should be executed or skipped. + fn has_zstd(&self) -> bool { + false + } + /// The metadata loader used to load rlib and dylib metadata. /// /// Alternative codegen backends may want to use different rlib or dylib formats than the diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 0853f638509f..63fc9c96f450 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -798,8 +798,11 @@ fn print_crate_info( let calling_conventions = rustc_abi::all_names(); println_info!("{}", calling_conventions.join("\n")); } + BackendHasZstd => { + let has_zstd: bool = codegen_backend.has_zstd(); + println_info!("{has_zstd}"); + } RelocationModels - | BackendHasZstd | CodeModels | TlsModels | TargetCPUs diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs index 208e96166021..92b596c70ae9 100644 --- a/src/tools/compiletest/src/directives/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -432,6 +432,10 @@ fn has_symlinks() -> bool { } fn llvm_has_zstd(config: &Config) -> bool { + // FIXME(#149764): This actually queries the compiler's _default_ backend, + // which is usually LLVM, but can be another backend depending on the value + // of `rust.codegen-backends` in bootstrap.toml. + // The compiler already knows whether LLVM was built with zstd or not, // so compiletest can just ask the compiler. let output = query_rustc_output( From 34392a99c0434c93bdaab5c6655f83417303c21c Mon Sep 17 00:00:00 2001 From: DrAsu33 <3537555264@qq.com> Date: Sat, 29 Nov 2025 06:22:41 +0000 Subject: [PATCH 417/585] Fix(alloc): Correctly handle ZST alignment for IntoIter::nth_back This commit consolidates all changes, including the core logic fix for IntoIter::nth_back and the addition of the Miri regression test in `library/alloctests/tests/vec.rs`, to prevent Undefined Behavior (UB) when dealing with highly-aligned Zero-Sized Types. --- library/alloc/src/vec/into_iter.rs | 7 ++++++- library/alloctests/tests/vec.rs | 32 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 358bdeacae79..af1bd5317973 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -411,7 +411,12 @@ fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { // SAFETY: same as for advance_by() self.end = unsafe { self.end.sub(step_size) }; } - let to_drop = ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size); + let to_drop = if T::IS_ZST { + // ZST may cause unalignment + ptr::slice_from_raw_parts_mut(ptr::NonNull::::dangling().as_ptr(), step_size) + } else { + ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size) + }; // SAFETY: same as for advance_by() unsafe { ptr::drop_in_place(to_drop); diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index dd42230d2e00..cd5b14f6eff3 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -2717,3 +2717,35 @@ fn vec_null_ptr_roundtrip() { let new = roundtripped.with_addr(ptr.addr()); unsafe { new.read() }; } + +// Regression test for Undefined Behavior (UB) caused by IntoIter::nth_back (#148682) +// when dealing with high-aligned Zero-Sized Types (ZSTs). +use std::collections::{BTreeMap, BinaryHeap, HashMap, LinkedList, VecDeque}; +#[test] +fn zst_collections_iter_nth_back_regression() { + #[repr(align(8))] + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] + struct Thing; + let v = vec![Thing, Thing]; + let _ = v.into_iter().nth_back(1); + let mut d = VecDeque::new(); + d.push_back(Thing); + d.push_back(Thing); + let _ = d.into_iter().nth_back(1); + let mut map = BTreeMap::new(); + map.insert(0, Thing); + map.insert(1, Thing); + let _ = map.into_values().nth_back(0); + let mut hash_map = HashMap::new(); + hash_map.insert(1, Thing); + hash_map.insert(2, Thing); + let _ = hash_map.into_values().nth(1); + let mut heap = BinaryHeap::new(); + heap.push(Thing); + heap.push(Thing); + let _ = heap.into_iter().nth_back(1); + let mut list = LinkedList::new(); + list.push_back(Thing); + list.push_back(Thing); + let _ = list.into_iter().nth_back(1); +} From 75df299225d56977ebacca0400c4fcaa3b316726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 9 Dec 2025 11:30:03 +0100 Subject: [PATCH 418/585] Mirror `ubuntu:24.04` on ghcr --- .github/workflows/ghcr.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ghcr.yml b/.github/workflows/ghcr.yml index a89867efe666..ddb3b2ce0dd5 100644 --- a/.github/workflows/ghcr.yml +++ b/.github/workflows/ghcr.yml @@ -55,6 +55,8 @@ jobs: images=( # Mirrored because used by the tidy job, which doesn't cache Docker images "ubuntu:22.04" + # Mirrored because used by x86-64-gnu-miri + "ubuntu:24.04" # Mirrored because used by all linux CI jobs, including tidy "moby/buildkit:buildx-stable-1" # Mirrored because used when CI is running inside a Docker container From 51780a53f65906e5fd3ee213fb005a0864cfc06a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 17 Oct 2025 20:45:51 +0300 Subject: [PATCH 419/585] resolve: Preserve ambiguous glob reexports in crate metadata So in cross-crate scenarios they can work in the same way as in crate-local scenarios. --- compiler/rustc_metadata/src/lib.rs | 1 + compiler/rustc_metadata/src/rmeta/decoder.rs | 15 +++ .../src/rmeta/decoder/cstore_impl.rs | 10 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 8 ++ compiler/rustc_metadata/src/rmeta/mod.rs | 3 +- .../rustc_metadata/src/rmeta/parameterized.rs | 1 + compiler/rustc_middle/src/metadata.rs | 14 +++ compiler/rustc_middle/src/ty/mod.rs | 3 +- .../rustc_resolve/src/build_reduced_graph.rs | 79 +++++++++++----- compiler/rustc_resolve/src/diagnostics.rs | 7 +- compiler/rustc_resolve/src/imports.rs | 50 +++++++--- compiler/rustc_resolve/src/lib.rs | 27 +++++- tests/ui/imports/ambiguous-2.rs | 5 +- tests/ui/imports/ambiguous-2.stderr | 45 +++++++++ tests/ui/imports/ambiguous-4.rs | 5 +- tests/ui/imports/ambiguous-4.stderr | 45 +++++++++ .../ambiguous-glob-vs-expanded-extern.rs | 6 ++ .../ambiguous-glob-vs-expanded-extern.stderr | 47 ++++++++++ .../ui/imports/auxiliary/glob-vs-expanded.rs | 11 +++ tests/ui/imports/extern-with-ambiguous-2.rs | 5 +- .../ui/imports/extern-with-ambiguous-2.stderr | 23 +++++ tests/ui/imports/extern-with-ambiguous-3.rs | 5 +- .../ui/imports/extern-with-ambiguous-3.stderr | 23 +++++ .../ui/imports/glob-conflict-cross-crate-1.rs | 10 +- .../glob-conflict-cross-crate-1.stderr | 84 +++++++++++++++-- .../ui/imports/glob-conflict-cross-crate-2.rs | 4 +- .../glob-conflict-cross-crate-2.stderr | 42 ++++++++- .../ui/imports/glob-conflict-cross-crate-3.rs | 6 +- .../glob-conflict-cross-crate-3.stderr | 91 +++++++++++++++++++ tests/ui/imports/issue-114682-2.rs | 15 +-- tests/ui/imports/issue-114682-2.stderr | 88 +++++++++++++++++- tests/ui/imports/issue-114682-3.rs | 4 +- tests/ui/imports/issue-114682-3.stderr | 18 ++++ tests/ui/imports/issue-114682-4.rs | 5 +- tests/ui/imports/issue-114682-4.stderr | 60 ++++++++++++ tests/ui/imports/issue-114682-5.rs | 7 +- tests/ui/imports/issue-114682-5.stderr | 77 ++++++++++++++++ tests/ui/imports/issue-114682-6.rs | 5 +- tests/ui/imports/issue-114682-6.stderr | 45 +++++++++ 39 files changed, 896 insertions(+), 103 deletions(-) create mode 100644 tests/ui/imports/ambiguous-2.stderr create mode 100644 tests/ui/imports/ambiguous-4.stderr create mode 100644 tests/ui/imports/ambiguous-glob-vs-expanded-extern.rs create mode 100644 tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr create mode 100644 tests/ui/imports/auxiliary/glob-vs-expanded.rs create mode 100644 tests/ui/imports/extern-with-ambiguous-2.stderr create mode 100644 tests/ui/imports/extern-with-ambiguous-3.stderr create mode 100644 tests/ui/imports/glob-conflict-cross-crate-3.stderr create mode 100644 tests/ui/imports/issue-114682-3.stderr create mode 100644 tests/ui/imports/issue-114682-4.stderr create mode 100644 tests/ui/imports/issue-114682-5.stderr create mode 100644 tests/ui/imports/issue-114682-6.stderr diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 01060eb7e32c..114301083883 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -9,6 +9,7 @@ #![feature(min_specialization)] #![feature(never_type)] #![feature(proc_macro_internals)] +#![feature(result_option_map_or_default)] #![feature(trusted_len)] // tidy-alphabetical-end diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index bf7818b49933..65cbdc675962 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1284,6 +1284,21 @@ fn get_module_children(self, tcx: TyCtxt<'_>, id: DefIndex) -> impl Iterator, + id: DefIndex, + ) -> impl Iterator { + gen move { + let children = self.root.tables.ambig_module_children.get((self, tcx), id); + if !children.is_default() { + for child in children.decode((self, tcx)) { + yield child; + } + } + } + } + fn is_ctfe_mir_available(self, tcx: TyCtxt<'_>, id: DefIndex) -> bool { self.root.tables.mir_for_ctfe.get((self, tcx), id).is_some() } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index ac4faae5a87a..c48cf36930f4 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -8,7 +8,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::bug; -use rustc_middle::metadata::ModChild; +use rustc_middle::metadata::{AmbigModChild, ModChild}; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::query::{ExternProviders, LocalCrate}; @@ -585,6 +585,14 @@ pub fn expn_that_defined_untracked(&self, tcx: TyCtxt<'_>, def_id: DefId) -> Exp self.get_crate_data(def_id.krate).get_expn_that_defined(tcx, def_id.index) } + pub fn ambig_module_children_untracked( + &self, + tcx: TyCtxt<'_>, + def_id: DefId, + ) -> impl Iterator { + self.get_crate_data(def_id.krate).get_ambig_module_children(tcx, def_id.index) + } + /// Only public-facing way to traverse all the definitions in a non-local crate. /// Critically useful for this third-party project: . /// See for context. diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 94bba9445610..86719581a209 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1731,6 +1731,14 @@ fn encode_info_for_mod(&mut self, local_def_id: LocalDefId) { record_defaulted_array!(self.tables.module_children_reexports[def_id] <- module_children.iter().filter(|child| !child.reexport_chain.is_empty())); + + let ambig_module_children = tcx + .resolutions(()) + .ambig_module_children + .get(&local_def_id) + .map_or_default(|v| &v[..]); + record_defaulted_array!(self.tables.ambig_module_children[def_id] <- + ambig_module_children); } } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 8ac1dd83ee5d..c5230685bfaf 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -21,7 +21,7 @@ use rustc_macros::{ BlobDecodable, Decodable, Encodable, LazyDecodable, MetadataEncodable, TyDecodable, TyEncodable, }; -use rustc_middle::metadata::ModChild; +use rustc_middle::metadata::{AmbigModChild, ModChild}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::deduced_param_attrs::DeducedParamAttrs; @@ -399,6 +399,7 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables { // That's why the encoded list needs to contain `ModChild` structures describing all the names // individually instead of `DefId`s. module_children_reexports: Table>, + ambig_module_children: Table>, cross_crate_inlinable: Table, asyncness: Table, constness: Table, diff --git a/compiler/rustc_metadata/src/rmeta/parameterized.rs b/compiler/rustc_metadata/src/rmeta/parameterized.rs index d8bae5a54e31..d6ccad798112 100644 --- a/compiler/rustc_metadata/src/rmeta/parameterized.rs +++ b/compiler/rustc_metadata/src/rmeta/parameterized.rs @@ -94,6 +94,7 @@ impl ParameterizedOverTcx for $ty { rustc_hir::def_id::DefIndex, rustc_hir::definitions::DefKey, rustc_index::bit_set::DenseBitSet, + rustc_middle::metadata::AmbigModChild, rustc_middle::metadata::ModChild, rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs, rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile, diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs index 57c8960943b1..2b0be9865799 100644 --- a/compiler/rustc_middle/src/metadata.rs +++ b/compiler/rustc_middle/src/metadata.rs @@ -44,3 +44,17 @@ pub struct ModChild { /// Empty if the module child is a proper item. pub reexport_chain: SmallVec<[Reexport; 2]>, } + +#[derive(Debug, TyEncodable, TyDecodable, HashStable)] +pub enum AmbigModChildKind { + GlobVsGlob, + GlobVsExpanded, +} + +/// Same as `ModChild`, however, it includes ambiguity error. +#[derive(Debug, TyEncodable, TyDecodable, HashStable)] +pub struct AmbigModChild { + pub main: ModChild, + pub second: ModChild, + pub kind: AmbigModChildKind, +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b4c20d7cadf9..2f2f35d3633d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -108,7 +108,7 @@ Rust2024IncompatiblePatInfo, TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind, }; use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; -use crate::metadata::ModChild; +use crate::metadata::{AmbigModChild, ModChild}; use crate::middle::privacy::EffectiveVisibilities; use crate::mir::{Body, CoroutineLayout, CoroutineSavedLocal, SourceInfo}; use crate::query::{IntoQueryParam, Providers}; @@ -173,6 +173,7 @@ pub struct ResolverGlobalCtxt { pub extern_crate_map: UnordMap, pub maybe_unused_trait_imports: FxIndexSet, pub module_children: LocalDefIdMap>, + pub ambig_module_children: LocalDefIdMap>, pub glob_map: FxIndexMap>, pub main_def: Option, pub trait_impls: FxIndexMap>, diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 26658aef3359..b9c945a440f8 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -22,7 +22,7 @@ use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::LoadedMacro; -use rustc_middle::metadata::ModChild; +use rustc_middle::metadata::{AmbigModChildKind, ModChild, Reexport}; use rustc_middle::ty::{Feed, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; @@ -36,9 +36,9 @@ use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::ref_mut::CmCell; use crate::{ - BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, - NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Used, - VisResolutionError, errors, + AmbiguityKind, BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, + ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, + ResolutionError, Resolver, Segment, Used, VisResolutionError, errors, }; type Res = def::Res; @@ -81,9 +81,18 @@ fn define_extern( res: Res, vis: Visibility, span: Span, - expn_id: LocalExpnId, + expansion: LocalExpnId, + ambiguity: Option<(NameBinding<'ra>, AmbiguityKind)>, ) { - let binding = self.arenas.new_res_binding(res, vis, span, expn_id); + let binding = self.arenas.alloc_name_binding(NameBindingData { + kind: NameBindingKind::Res(res), + ambiguity, + // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. + warn_ambiguity: true, + vis, + span, + expansion, + }); // Even if underscore names cannot be looked up, we still need to add them to modules, // because they can be fetched by glob imports from those modules, and bring traits // into scope both directly and through glob imports. @@ -232,9 +241,21 @@ pub(crate) fn build_reduced_graph( } pub(crate) fn build_reduced_graph_external(&self, module: Module<'ra>) { - for (i, child) in self.tcx.module_children(module.def_id()).into_iter().enumerate() { - let parent_scope = ParentScope::module(module, self.arenas); - self.build_reduced_graph_for_external_crate_res(child, parent_scope, i) + let def_id = module.def_id(); + let children = self.tcx.module_children(def_id); + let parent_scope = ParentScope::module(module, self.arenas); + for (i, child) in children.iter().enumerate() { + self.build_reduced_graph_for_external_crate_res(child, parent_scope, i, None) + } + for (i, child) in + self.cstore().ambig_module_children_untracked(self.tcx, def_id).enumerate() + { + self.build_reduced_graph_for_external_crate_res( + &child.main, + parent_scope, + children.len() + i, + Some((&child.second, child.kind)), + ) } } @@ -244,18 +265,36 @@ fn build_reduced_graph_for_external_crate_res( child: &ModChild, parent_scope: ParentScope<'ra>, child_index: usize, + ambig_child: Option<(&ModChild, AmbigModChildKind)>, ) { let parent = parent_scope.module; + let child_span = |this: &Self, reexport_chain: &[Reexport], res: def::Res<_>| { + this.def_span( + reexport_chain + .first() + .and_then(|reexport| reexport.id()) + .unwrap_or_else(|| res.def_id()), + ) + }; let ModChild { ident, res, vis, ref reexport_chain } = *child; - let span = self.def_span( - reexport_chain - .first() - .and_then(|reexport| reexport.id()) - .unwrap_or_else(|| res.def_id()), - ); + let span = child_span(self, reexport_chain, res); let res = res.expect_non_local(); let expansion = parent_scope.expansion; + let ambig = ambig_child.map(|(ambig_child, ambig_kind)| { + let ModChild { ident: _, res, vis, ref reexport_chain } = *ambig_child; + let span = child_span(self, reexport_chain, res); + let res = res.expect_non_local(); + let ambig_kind = match ambig_kind { + AmbigModChildKind::GlobVsGlob => AmbiguityKind::GlobVsGlob, + AmbigModChildKind::GlobVsExpanded => AmbiguityKind::GlobVsExpanded, + }; + (self.arenas.new_res_binding(res, vis, span, expansion), ambig_kind) + }); + // Record primary definitions. + let define_extern = |ns| { + self.define_extern(parent, ident, ns, child_index, res, vis, span, expansion, ambig) + }; match res { Res::Def( DefKind::Mod @@ -272,9 +311,7 @@ fn build_reduced_graph_for_external_crate_res( _, ) | Res::PrimTy(..) - | Res::ToolMod => { - self.define_extern(parent, ident, TypeNS, child_index, res, vis, span, expansion) - } + | Res::ToolMod => define_extern(TypeNS), Res::Def( DefKind::Fn | DefKind::AssocFn @@ -283,10 +320,8 @@ fn build_reduced_graph_for_external_crate_res( | DefKind::AssocConst | DefKind::Ctor(..), _, - ) => self.define_extern(parent, ident, ValueNS, child_index, res, vis, span, expansion), - Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => { - self.define_extern(parent, ident, MacroNS, child_index, res, vis, span, expansion) - } + ) => define_extern(ValueNS), + Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => define_extern(MacroNS), Res::Def( DefKind::TyParam | DefKind::ConstParam diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 33c111708e36..19b8d6c9dead 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -148,12 +148,13 @@ pub(crate) fn report_errors(&mut self, krate: &Crate) { let diag = self.ambiguity_diagnostic(ambiguity_error); if ambiguity_error.warning { - let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else { - unreachable!() + let node_id = match ambiguity_error.b1.0.kind { + NameBindingKind::Import { import, .. } => import.root_id, + NameBindingKind::Res(_) => CRATE_NODE_ID, }; self.lint_buffer.buffer_lint( AMBIGUOUS_GLOB_IMPORTS, - import.root_id, + node_id, diag.ident.span, diag, ); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index f844e7b9cc12..4ef87af56050 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -9,7 +9,7 @@ use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_hir::def_id::{DefId, LocalDefIdMap}; -use rustc_middle::metadata::{ModChild, Reexport}; +use rustc_middle::metadata::{AmbigModChild, AmbigModChildKind, ModChild, Reexport}; use rustc_middle::span_bug; use rustc_middle::ty::Visibility; use rustc_session::lint::BuiltinLintDiag; @@ -21,7 +21,6 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::LocalExpnId; use rustc_span::{Ident, Span, Symbol, kw, sym}; -use smallvec::SmallVec; use tracing::debug; use crate::Namespace::{self, *}; @@ -227,7 +226,7 @@ pub(crate) fn id(&self) -> Option { } } - fn simplify(&self, r: &Resolver<'_, '_>) -> Reexport { + pub(crate) fn simplify(&self, r: &Resolver<'_, '_>) -> Reexport { let to_def_id = |id| r.local_def_id(id).to_def_id(); match self.kind { ImportKind::Single { id, .. } => Reexport::Single(to_def_id(id)), @@ -571,10 +570,12 @@ pub(crate) fn resolve_imports(&mut self) { pub(crate) fn finalize_imports(&mut self) { let mut module_children = Default::default(); + let mut ambig_module_children = Default::default(); for module in &self.local_modules { - self.finalize_resolutions_in(*module, &mut module_children); + self.finalize_resolutions_in(*module, &mut module_children, &mut ambig_module_children); } self.module_children = module_children; + self.ambig_module_children = ambig_module_children; let mut seen_spans = FxHashSet::default(); let mut errors = vec![]; @@ -1546,6 +1547,7 @@ fn finalize_resolutions_in( &self, module: Module<'ra>, module_children: &mut LocalDefIdMap>, + ambig_module_children: &mut LocalDefIdMap>, ) { // Since import resolution is finished, globs will not define any more names. *module.globs.borrow_mut(self) = Vec::new(); @@ -1553,26 +1555,46 @@ fn finalize_resolutions_in( let Some(def_id) = module.opt_def_id() else { return }; let mut children = Vec::new(); + let mut ambig_children = Vec::new(); module.for_each_child(self, |this, ident, _, binding| { let res = binding.res().expect_non_local(); - let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity; - if res != def::Res::Err && !error_ambiguity { - let mut reexport_chain = SmallVec::new(); - let mut next_binding = binding; - while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { - reexport_chain.push(import.simplify(this)); - next_binding = binding; - } + if res != def::Res::Err { + let child = |reexport_chain| ModChild { + ident: ident.0, + res, + vis: binding.vis, + reexport_chain, + }; + if let Some((ambig_binding1, ambig_binding2, ambig_kind)) = + binding.descent_to_ambiguity() + { + let main = child(ambig_binding1.reexport_chain(this)); + let second = ModChild { + ident: ident.0, + res: ambig_binding2.res().expect_non_local(), + vis: ambig_binding2.vis, + reexport_chain: ambig_binding2.reexport_chain(this), + }; + let kind = match ambig_kind { + AmbiguityKind::GlobVsGlob => AmbigModChildKind::GlobVsGlob, + AmbiguityKind::GlobVsExpanded => AmbigModChildKind::GlobVsExpanded, + _ => unreachable!(), + }; - children.push(ModChild { ident: ident.0, res, vis: binding.vis, reexport_chain }); + ambig_children.push(AmbigModChild { main, second, kind }) + } else { + children.push(child(binding.reexport_chain(this))); + } } }); if !children.is_empty() { - // Should be fine because this code is only called for local modules. module_children.insert(def_id.expect_local(), children); } + if !ambig_children.is_empty() { + ambig_module_children.insert(def_id.expect_local(), ambig_children); + } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 35d54615772b..8132bf577d88 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -64,7 +64,7 @@ use rustc_hir::{PrimTy, TraitCandidate}; use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::CStore; -use rustc_middle::metadata::ModChild; +use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; use rustc_middle::span_bug; @@ -927,6 +927,18 @@ fn import_source(&self) -> NameBinding<'ra> { } } + fn descent_to_ambiguity( + self: NameBinding<'ra>, + ) -> Option<(NameBinding<'ra>, NameBinding<'ra>, AmbiguityKind)> { + match self.ambiguity { + Some((ambig_binding, ambig_kind)) => Some((self, ambig_binding, ambig_kind)), + None => match self.kind { + NameBindingKind::Import { binding, .. } => binding.descent_to_ambiguity(), + _ => None, + }, + } + } + fn is_ambiguity_recursive(&self) -> bool { self.ambiguity.is_some() || match self.kind { @@ -990,6 +1002,16 @@ fn macro_kinds(&self) -> Option { self.res().macro_kinds() } + fn reexport_chain(self: NameBinding<'ra>, r: &Resolver<'_, '_>) -> SmallVec<[Reexport; 2]> { + let mut reexport_chain = SmallVec::new(); + let mut next_binding = self; + while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { + reexport_chain.push(import.simplify(r)); + next_binding = binding; + } + reexport_chain + } + // Suppose that we resolved macro invocation with `invoc_parent_expansion` to binding `binding` // at some expansion round `max(invoc, binding)` when they both emerged from macros. // Then this function returns `true` if `self` may emerge from a macro *after* that @@ -1123,6 +1145,7 @@ pub struct Resolver<'ra, 'tcx> { /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: UnordMap, module_children: LocalDefIdMap>, + ambig_module_children: LocalDefIdMap>, trait_map: NodeMap>, /// A map from nodes to anonymous modules. @@ -1580,6 +1603,7 @@ pub fn new( extra_lifetime_params_map: Default::default(), extern_crate_map: Default::default(), module_children: Default::default(), + ambig_module_children: Default::default(), trait_map: NodeMap::default(), empty_module, local_modules, @@ -1766,6 +1790,7 @@ pub fn into_outputs(self) -> ResolverOutputs { effective_visibilities, extern_crate_map, module_children: self.module_children, + ambig_module_children: self.ambig_module_children, glob_map, maybe_unused_trait_imports, main_def, diff --git a/tests/ui/imports/ambiguous-2.rs b/tests/ui/imports/ambiguous-2.rs index 087431485ad6..65c971c00b9a 100644 --- a/tests/ui/imports/ambiguous-2.rs +++ b/tests/ui/imports/ambiguous-2.rs @@ -1,10 +1,9 @@ -//@ check-pass //@ aux-build: ../ambiguous-1.rs // https://github.com/rust-lang/rust/pull/113099#issuecomment-1633574396 extern crate ambiguous_1; fn main() { - ambiguous_1::id(); - //^ FIXME: `id` should be identified as an ambiguous item. + ambiguous_1::id(); //~ ERROR `id` is ambiguous + //~| WARN this was previously accepted } diff --git a/tests/ui/imports/ambiguous-2.stderr b/tests/ui/imports/ambiguous-2.stderr new file mode 100644 index 000000000000..d428e58a78fd --- /dev/null +++ b/tests/ui/imports/ambiguous-2.stderr @@ -0,0 +1,45 @@ +error: `id` is ambiguous + --> $DIR/ambiguous-2.rs:7:18 + | +LL | ambiguous_1::id(); + | ^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `id` could refer to the function defined here + --> $DIR/auxiliary/../ambiguous-1.rs:13:13 + | +LL | pub use self::evp::*; + | ^^^^^^^^^ +note: `id` could also refer to the function defined here + --> $DIR/auxiliary/../ambiguous-1.rs:15:13 + | +LL | pub use self::handwritten::*; + | ^^^^^^^^^^^^^^^^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + +error: aborting due to 1 previous error + +Future incompatibility report: Future breakage diagnostic: +error: `id` is ambiguous + --> $DIR/ambiguous-2.rs:7:18 + | +LL | ambiguous_1::id(); + | ^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `id` could refer to the function defined here + --> $DIR/auxiliary/../ambiguous-1.rs:13:13 + | +LL | pub use self::evp::*; + | ^^^^^^^^^ +note: `id` could also refer to the function defined here + --> $DIR/auxiliary/../ambiguous-1.rs:15:13 + | +LL | pub use self::handwritten::*; + | ^^^^^^^^^^^^^^^^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + diff --git a/tests/ui/imports/ambiguous-4.rs b/tests/ui/imports/ambiguous-4.rs index d604dca30eed..e66d231f93cc 100644 --- a/tests/ui/imports/ambiguous-4.rs +++ b/tests/ui/imports/ambiguous-4.rs @@ -1,10 +1,9 @@ //@ edition:2015 -//@ check-pass //@ aux-build: ../ambiguous-4-extern.rs extern crate ambiguous_4_extern; fn main() { - ambiguous_4_extern::id(); - //^ FIXME: `id` should be identified as an ambiguous item. + ambiguous_4_extern::id(); //~ ERROR `id` is ambiguous + //~| WARN this was previously accepted } diff --git a/tests/ui/imports/ambiguous-4.stderr b/tests/ui/imports/ambiguous-4.stderr new file mode 100644 index 000000000000..cf4127cbbb1c --- /dev/null +++ b/tests/ui/imports/ambiguous-4.stderr @@ -0,0 +1,45 @@ +error: `id` is ambiguous + --> $DIR/ambiguous-4.rs:7:25 + | +LL | ambiguous_4_extern::id(); + | ^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `id` could refer to the function defined here + --> $DIR/auxiliary/../ambiguous-4-extern.rs:13:9 + | +LL | pub use evp::*; + | ^^^ +note: `id` could also refer to the function defined here + --> $DIR/auxiliary/../ambiguous-4-extern.rs:14:9 + | +LL | pub use handwritten::*; + | ^^^^^^^^^^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + +error: aborting due to 1 previous error + +Future incompatibility report: Future breakage diagnostic: +error: `id` is ambiguous + --> $DIR/ambiguous-4.rs:7:25 + | +LL | ambiguous_4_extern::id(); + | ^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `id` could refer to the function defined here + --> $DIR/auxiliary/../ambiguous-4-extern.rs:13:9 + | +LL | pub use evp::*; + | ^^^ +note: `id` could also refer to the function defined here + --> $DIR/auxiliary/../ambiguous-4-extern.rs:14:9 + | +LL | pub use handwritten::*; + | ^^^^^^^^^^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + diff --git a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.rs b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.rs new file mode 100644 index 000000000000..de632119ecba --- /dev/null +++ b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.rs @@ -0,0 +1,6 @@ +//@ aux-crate: glob_vs_expanded=glob-vs-expanded.rs + +fn main() { + glob_vs_expanded::mac!(); //~ ERROR `mac` is ambiguous + //~| WARN this was previously accepted +} diff --git a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr new file mode 100644 index 000000000000..c2e775e6c862 --- /dev/null +++ b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr @@ -0,0 +1,47 @@ +error: `mac` is ambiguous + --> $DIR/ambiguous-glob-vs-expanded-extern.rs:4:23 + | +LL | glob_vs_expanded::mac!(); + | ^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution +note: `mac` could refer to the macro defined here + --> $DIR/auxiliary/glob-vs-expanded.rs:11:1 + | +LL | define_mac!(); + | ^^^^^^^^^^^^^ +note: `mac` could also refer to the macro defined here + --> $DIR/auxiliary/glob-vs-expanded.rs:5:9 + | +LL | pub use inner::*; + | ^^^^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: this error originates in the macro `define_mac` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +Future incompatibility report: Future breakage diagnostic: +error: `mac` is ambiguous + --> $DIR/ambiguous-glob-vs-expanded-extern.rs:4:23 + | +LL | glob_vs_expanded::mac!(); + | ^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution +note: `mac` could refer to the macro defined here + --> $DIR/auxiliary/glob-vs-expanded.rs:11:1 + | +LL | define_mac!(); + | ^^^^^^^^^^^^^ +note: `mac` could also refer to the macro defined here + --> $DIR/auxiliary/glob-vs-expanded.rs:5:9 + | +LL | pub use inner::*; + | ^^^^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: this error originates in the macro `define_mac` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/imports/auxiliary/glob-vs-expanded.rs b/tests/ui/imports/auxiliary/glob-vs-expanded.rs new file mode 100644 index 000000000000..fcbe54f73264 --- /dev/null +++ b/tests/ui/imports/auxiliary/glob-vs-expanded.rs @@ -0,0 +1,11 @@ +#![feature(decl_macro)] + +// Glob import in macro namespace +mod inner { pub macro mac() {} } +pub use inner::*; + +// Macro-expanded single import in macro namespace +macro_rules! define_mac { + () => { pub macro mac() {} } +} +define_mac!(); diff --git a/tests/ui/imports/extern-with-ambiguous-2.rs b/tests/ui/imports/extern-with-ambiguous-2.rs index dcab2bcc18ea..477d29ad0120 100644 --- a/tests/ui/imports/extern-with-ambiguous-2.rs +++ b/tests/ui/imports/extern-with-ambiguous-2.rs @@ -1,4 +1,3 @@ -//@ check-pass //@ edition: 2021 //@ aux-build: extern-with-ambiguous-2-extern.rs @@ -11,8 +10,6 @@ pub mod error { } use s::*; use extern_with_ambiguous_2_extern::*; -use error::*; -//^ FIXME: An ambiguity error should be thrown for `error`, -// as there is ambiguity present within `extern-with-ambiguous-2-extern.rs`. +use error::*; //~ ERROR `error` is ambiguous fn main() {} diff --git a/tests/ui/imports/extern-with-ambiguous-2.stderr b/tests/ui/imports/extern-with-ambiguous-2.stderr new file mode 100644 index 000000000000..2fd66932e4ed --- /dev/null +++ b/tests/ui/imports/extern-with-ambiguous-2.stderr @@ -0,0 +1,23 @@ +error[E0659]: `error` is ambiguous + --> $DIR/extern-with-ambiguous-2.rs:13:5 + | +LL | use error::*; + | ^^^^^ ambiguous name + | + = note: ambiguous because of multiple glob imports of a name in the same module +note: `error` could refer to the module imported here + --> $DIR/extern-with-ambiguous-2.rs:11:5 + | +LL | use s::*; + | ^^^^ + = help: consider adding an explicit import of `error` to disambiguate +note: `error` could also refer to the module imported here + --> $DIR/extern-with-ambiguous-2.rs:12:5 + | +LL | use extern_with_ambiguous_2_extern::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider adding an explicit import of `error` to disambiguate + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/extern-with-ambiguous-3.rs b/tests/ui/imports/extern-with-ambiguous-3.rs index c65fedbe2c1d..c0c4741ec56a 100644 --- a/tests/ui/imports/extern-with-ambiguous-3.rs +++ b/tests/ui/imports/extern-with-ambiguous-3.rs @@ -1,4 +1,3 @@ -//@ check-pass //@ edition: 2021 //@ aux-build: extern-with-ambiguous-3-extern.rs // https://github.com/rust-lang/rust/pull/113099#issuecomment-1643974121 @@ -12,8 +11,6 @@ pub mod error { } use s::*; use extern_with_ambiguous_3_extern::*; -use error::*; -//^ FIXME: An ambiguity error should be thrown for `error`, -// as there is ambiguity present within `extern-with-ambiguous-3-extern.rs`. +use error::*; //~ ERROR `error` is ambiguous fn main() {} diff --git a/tests/ui/imports/extern-with-ambiguous-3.stderr b/tests/ui/imports/extern-with-ambiguous-3.stderr new file mode 100644 index 000000000000..95a1175c56b3 --- /dev/null +++ b/tests/ui/imports/extern-with-ambiguous-3.stderr @@ -0,0 +1,23 @@ +error[E0659]: `error` is ambiguous + --> $DIR/extern-with-ambiguous-3.rs:14:5 + | +LL | use error::*; + | ^^^^^ ambiguous name + | + = note: ambiguous because of multiple glob imports of a name in the same module +note: `error` could refer to the module imported here + --> $DIR/extern-with-ambiguous-3.rs:12:5 + | +LL | use s::*; + | ^^^^ + = help: consider adding an explicit import of `error` to disambiguate +note: `error` could also refer to the module imported here + --> $DIR/extern-with-ambiguous-3.rs:13:5 + | +LL | use extern_with_ambiguous_3_extern::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider adding an explicit import of `error` to disambiguate + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/glob-conflict-cross-crate-1.rs b/tests/ui/imports/glob-conflict-cross-crate-1.rs index 6e3200329616..08ce6166b5c1 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-1.rs +++ b/tests/ui/imports/glob-conflict-cross-crate-1.rs @@ -4,10 +4,8 @@ extern crate glob_conflict; fn main() { - glob_conflict::f(); //~ ERROR cannot find function `f` in crate `glob_conflict` - //^ FIXME: `glob_conflict::f` should raise an - // ambiguity error instead of a not found error. - glob_conflict::glob::f(); //~ ERROR cannot find function `f` in module `glob_conflict::glob` - //^ FIXME: `glob_conflict::glob::f` should raise an - // ambiguity error instead of a not found error. + glob_conflict::f(); //~ ERROR `f` is ambiguous + //~| WARN this was previously accepted + glob_conflict::glob::f(); //~ ERROR `f` is ambiguous + //~| WARN this was previously accepted } diff --git a/tests/ui/imports/glob-conflict-cross-crate-1.stderr b/tests/ui/imports/glob-conflict-cross-crate-1.stderr index cf40076ecb86..54b7976b057e 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-1.stderr +++ b/tests/ui/imports/glob-conflict-cross-crate-1.stderr @@ -1,15 +1,87 @@ -error[E0425]: cannot find function `f` in crate `glob_conflict` +error: `f` is ambiguous --> $DIR/glob-conflict-cross-crate-1.rs:7:20 | LL | glob_conflict::f(); - | ^ not found in `glob_conflict` + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `f` could refer to the function defined here + --> $DIR/auxiliary/glob-conflict.rs:12:9 + | +LL | pub use m1::*; + | ^^ +note: `f` could also refer to the function defined here + --> $DIR/auxiliary/glob-conflict.rs:13:9 + | +LL | pub use m2::*; + | ^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default -error[E0425]: cannot find function `f` in module `glob_conflict::glob` - --> $DIR/glob-conflict-cross-crate-1.rs:10:26 +error: `f` is ambiguous + --> $DIR/glob-conflict-cross-crate-1.rs:9:26 | LL | glob_conflict::glob::f(); - | ^ not found in `glob_conflict::glob` + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `f` could refer to the function defined here + --> $DIR/auxiliary/glob-conflict.rs:12:9 + | +LL | pub use m1::*; + | ^^ +note: `f` could also refer to the function defined here + --> $DIR/auxiliary/glob-conflict.rs:13:9 + | +LL | pub use m2::*; + | ^^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0425`. +Future incompatibility report: Future breakage diagnostic: +error: `f` is ambiguous + --> $DIR/glob-conflict-cross-crate-1.rs:7:20 + | +LL | glob_conflict::f(); + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `f` could refer to the function defined here + --> $DIR/auxiliary/glob-conflict.rs:12:9 + | +LL | pub use m1::*; + | ^^ +note: `f` could also refer to the function defined here + --> $DIR/auxiliary/glob-conflict.rs:13:9 + | +LL | pub use m2::*; + | ^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + +Future breakage diagnostic: +error: `f` is ambiguous + --> $DIR/glob-conflict-cross-crate-1.rs:9:26 + | +LL | glob_conflict::glob::f(); + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `f` could refer to the function defined here + --> $DIR/auxiliary/glob-conflict.rs:12:9 + | +LL | pub use m1::*; + | ^^ +note: `f` could also refer to the function defined here + --> $DIR/auxiliary/glob-conflict.rs:13:9 + | +LL | pub use m2::*; + | ^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + diff --git a/tests/ui/imports/glob-conflict-cross-crate-2.rs b/tests/ui/imports/glob-conflict-cross-crate-2.rs index b764685dd579..b4dd3d8eeb44 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-2.rs +++ b/tests/ui/imports/glob-conflict-cross-crate-2.rs @@ -5,6 +5,6 @@ use glob_conflict_cross_crate_2_extern::*; fn main() { - let _a: C = 1; //~ ERROR cannot find type `C` in this scope - //^ FIXME: `C` should be identified as an ambiguous item. + let _a: C = 1; //~ ERROR `C` is ambiguous + //~| WARN this was previously accepted } diff --git a/tests/ui/imports/glob-conflict-cross-crate-2.stderr b/tests/ui/imports/glob-conflict-cross-crate-2.stderr index 41912ed63f42..cbc2180c14f4 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-2.stderr +++ b/tests/ui/imports/glob-conflict-cross-crate-2.stderr @@ -1,9 +1,45 @@ -error[E0425]: cannot find type `C` in this scope +error: `C` is ambiguous --> $DIR/glob-conflict-cross-crate-2.rs:8:13 | LL | let _a: C = 1; - | ^ not found in this scope + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `C` could refer to the type alias defined here + --> $DIR/auxiliary/glob-conflict-cross-crate-2-extern.rs:9:9 + | +LL | pub use a::*; + | ^ +note: `C` could also refer to the type alias defined here + --> $DIR/auxiliary/glob-conflict-cross-crate-2-extern.rs:10:9 + | +LL | pub use b::*; + | ^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0425`. +Future incompatibility report: Future breakage diagnostic: +error: `C` is ambiguous + --> $DIR/glob-conflict-cross-crate-2.rs:8:13 + | +LL | let _a: C = 1; + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `C` could refer to the type alias defined here + --> $DIR/auxiliary/glob-conflict-cross-crate-2-extern.rs:9:9 + | +LL | pub use a::*; + | ^ +note: `C` could also refer to the type alias defined here + --> $DIR/auxiliary/glob-conflict-cross-crate-2-extern.rs:10:9 + | +LL | pub use b::*; + | ^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + diff --git a/tests/ui/imports/glob-conflict-cross-crate-3.rs b/tests/ui/imports/glob-conflict-cross-crate-3.rs index 7797b5b7c069..31c234b9250f 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-3.rs +++ b/tests/ui/imports/glob-conflict-cross-crate-3.rs @@ -1,4 +1,3 @@ -//@ check-pass //@ aux-build:glob-conflict-cross-crate-2-extern.rs extern crate glob_conflict_cross_crate_2_extern; @@ -12,5 +11,8 @@ mod a { fn main() { let _a: C = 1; - //^ FIXME: `C` should be identified as an ambiguous item. + //~^ ERROR `C` is ambiguous + //~| ERROR `C` is ambiguous + //~| WARN this was previously accepted + //~| WARN this was previously accepted } diff --git a/tests/ui/imports/glob-conflict-cross-crate-3.stderr b/tests/ui/imports/glob-conflict-cross-crate-3.stderr new file mode 100644 index 000000000000..213eafda20b7 --- /dev/null +++ b/tests/ui/imports/glob-conflict-cross-crate-3.stderr @@ -0,0 +1,91 @@ +error: `C` is ambiguous + --> $DIR/glob-conflict-cross-crate-3.rs:13:13 + | +LL | let _a: C = 1; + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `C` could refer to the type alias defined here + --> $DIR/auxiliary/glob-conflict-cross-crate-2-extern.rs:9:9 + | +LL | pub use a::*; + | ^ +note: `C` could also refer to the type alias defined here + --> $DIR/auxiliary/glob-conflict-cross-crate-2-extern.rs:10:9 + | +LL | pub use b::*; + | ^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + +error: `C` is ambiguous + --> $DIR/glob-conflict-cross-crate-3.rs:13:13 + | +LL | let _a: C = 1; + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `C` could refer to the type alias imported here + --> $DIR/glob-conflict-cross-crate-3.rs:9:5 + | +LL | use glob_conflict_cross_crate_2_extern::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider adding an explicit import of `C` to disambiguate +note: `C` could also refer to the type alias imported here + --> $DIR/glob-conflict-cross-crate-3.rs:10:5 + | +LL | use a::*; + | ^^^^ + = help: consider adding an explicit import of `C` to disambiguate + +error: aborting due to 2 previous errors + +Future incompatibility report: Future breakage diagnostic: +error: `C` is ambiguous + --> $DIR/glob-conflict-cross-crate-3.rs:13:13 + | +LL | let _a: C = 1; + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `C` could refer to the type alias defined here + --> $DIR/auxiliary/glob-conflict-cross-crate-2-extern.rs:9:9 + | +LL | pub use a::*; + | ^ +note: `C` could also refer to the type alias defined here + --> $DIR/auxiliary/glob-conflict-cross-crate-2-extern.rs:10:9 + | +LL | pub use b::*; + | ^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + +Future breakage diagnostic: +error: `C` is ambiguous + --> $DIR/glob-conflict-cross-crate-3.rs:13:13 + | +LL | let _a: C = 1; + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `C` could refer to the type alias imported here + --> $DIR/glob-conflict-cross-crate-3.rs:9:5 + | +LL | use glob_conflict_cross_crate_2_extern::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider adding an explicit import of `C` to disambiguate +note: `C` could also refer to the type alias imported here + --> $DIR/glob-conflict-cross-crate-3.rs:10:5 + | +LL | use a::*; + | ^^^^ + = help: consider adding an explicit import of `C` to disambiguate + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + diff --git a/tests/ui/imports/issue-114682-2.rs b/tests/ui/imports/issue-114682-2.rs index e99bcf77ab62..a9459c5b02ef 100644 --- a/tests/ui/imports/issue-114682-2.rs +++ b/tests/ui/imports/issue-114682-2.rs @@ -3,17 +3,10 @@ extern crate issue_114682_2_extern; -use issue_114682_2_extern::max; +use issue_114682_2_extern::max; //~ ERROR `max` is ambiguous + //~| WARN this was previously accepted -type A = issue_114682_2_extern::max; -//~^ ERROR: expected type, found function `issue_114682_2_extern::max` -// FIXME: -// The above error was emitted due to `(Mod(issue_114682_2_extern), Namespace(Type), Ident(max))` -// being identified as an ambiguous item. -// However, there are two points worth discussing: -// First, should this ambiguous item be omitted considering the maximum visibility -// of `issue_114682_2_extern::m::max` in the type namespace is only within the extern crate. -// Second, if we retain the ambiguous item of the extern crate, should it be treated -// as an ambiguous item within the local crate for the same reasoning? +type A = issue_114682_2_extern::max; //~ ERROR `max` is ambiguous + //~| WARN this was previously accepted fn main() {} diff --git a/tests/ui/imports/issue-114682-2.stderr b/tests/ui/imports/issue-114682-2.stderr index 972bcecb56bc..07c696651c38 100644 --- a/tests/ui/imports/issue-114682-2.stderr +++ b/tests/ui/imports/issue-114682-2.stderr @@ -1,9 +1,87 @@ -error[E0573]: expected type, found function `issue_114682_2_extern::max` - --> $DIR/issue-114682-2.rs:8:10 +error: `max` is ambiguous + --> $DIR/issue-114682-2.rs:6:28 + | +LL | use issue_114682_2_extern::max; + | ^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `max` could refer to the type alias defined here + --> $DIR/auxiliary/issue-114682-2-extern.rs:17:9 + | +LL | pub use self::e::*; + | ^^^^^^^ +note: `max` could also refer to the module defined here + --> $DIR/auxiliary/issue-114682-2-extern.rs:16:9 + | +LL | pub use self::d::*; + | ^^^^^^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + +error: `max` is ambiguous + --> $DIR/issue-114682-2.rs:9:33 | LL | type A = issue_114682_2_extern::max; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type + | ^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `max` could refer to the type alias defined here + --> $DIR/auxiliary/issue-114682-2-extern.rs:17:9 + | +LL | pub use self::e::*; + | ^^^^^^^ +note: `max` could also refer to the module defined here + --> $DIR/auxiliary/issue-114682-2-extern.rs:16:9 + | +LL | pub use self::d::*; + | ^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors + +Future incompatibility report: Future breakage diagnostic: +error: `max` is ambiguous + --> $DIR/issue-114682-2.rs:6:28 + | +LL | use issue_114682_2_extern::max; + | ^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `max` could refer to the type alias defined here + --> $DIR/auxiliary/issue-114682-2-extern.rs:17:9 + | +LL | pub use self::e::*; + | ^^^^^^^ +note: `max` could also refer to the module defined here + --> $DIR/auxiliary/issue-114682-2-extern.rs:16:9 + | +LL | pub use self::d::*; + | ^^^^^^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + +Future breakage diagnostic: +error: `max` is ambiguous + --> $DIR/issue-114682-2.rs:9:33 + | +LL | type A = issue_114682_2_extern::max; + | ^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `max` could refer to the type alias defined here + --> $DIR/auxiliary/issue-114682-2-extern.rs:17:9 + | +LL | pub use self::e::*; + | ^^^^^^^ +note: `max` could also refer to the module defined here + --> $DIR/auxiliary/issue-114682-2-extern.rs:16:9 + | +LL | pub use self::d::*; + | ^^^^^^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default -For more information about this error, try `rustc --explain E0573`. diff --git a/tests/ui/imports/issue-114682-3.rs b/tests/ui/imports/issue-114682-3.rs index 6dc4df17a2da..ac603b49e321 100644 --- a/tests/ui/imports/issue-114682-3.rs +++ b/tests/ui/imports/issue-114682-3.rs @@ -1,4 +1,3 @@ -//@ check-pass //@ aux-build: issue-114682-3-extern.rs // https://github.com/rust-lang/rust/pull/114682#issuecomment-1880625909 @@ -19,6 +18,5 @@ impl SettingsExt for T {} fn main() { let a: u8 = 1; a.ext(); - //^ FIXME: it should report `ext` not found because `SettingsExt` - // is an ambiguous item in `issue-114682-3-extern.rs`. + //~^ ERROR no method named `ext` found for type `u8` in the current scope } diff --git a/tests/ui/imports/issue-114682-3.stderr b/tests/ui/imports/issue-114682-3.stderr new file mode 100644 index 000000000000..6af7a4e02614 --- /dev/null +++ b/tests/ui/imports/issue-114682-3.stderr @@ -0,0 +1,18 @@ +error[E0599]: no method named `ext` found for type `u8` in the current scope + --> $DIR/issue-114682-3.rs:20:7 + | +LL | fn ext(&self) {} + | --- the method is available for `u8` here +... +LL | a.ext(); + | ^^^ method not found in `u8` + | + = help: items from traits can only be used if the trait is in scope +help: trait `SettingsExt` which provides `ext` is implemented but not in scope; perhaps you want to import it + | +LL + use auto::SettingsExt; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/imports/issue-114682-4.rs b/tests/ui/imports/issue-114682-4.rs index 32c2ca7b2609..01921928a007 100644 --- a/tests/ui/imports/issue-114682-4.rs +++ b/tests/ui/imports/issue-114682-4.rs @@ -1,4 +1,3 @@ -//@ check-pass //@ aux-build: issue-114682-4-extern.rs // https://github.com/rust-lang/rust/pull/114682#issuecomment-1880755441 @@ -6,7 +5,9 @@ use issue_114682_4_extern::*; -fn a() -> Result { // FIXME: `Result` should be identified as an ambiguous item. +//~v ERROR type alias takes 1 generic argument but 2 generic arguments were supplied +fn a() -> Result { //~ ERROR `Result` is ambiguous + //~| WARN this was previously accepted Ok(1) } diff --git a/tests/ui/imports/issue-114682-4.stderr b/tests/ui/imports/issue-114682-4.stderr new file mode 100644 index 000000000000..5e677cd7ae72 --- /dev/null +++ b/tests/ui/imports/issue-114682-4.stderr @@ -0,0 +1,60 @@ +error: `Result` is ambiguous + --> $DIR/issue-114682-4.rs:9:11 + | +LL | fn a() -> Result { + | ^^^^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `Result` could refer to the type alias defined here + --> $DIR/auxiliary/issue-114682-4-extern.rs:9:9 + | +LL | pub use a::*; + | ^ +note: `Result` could also refer to the type alias defined here + --> $DIR/auxiliary/issue-114682-4-extern.rs:10:9 + | +LL | pub use b::*; + | ^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + +error[E0107]: type alias takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/issue-114682-4.rs:9:11 + | +LL | fn a() -> Result { + | ^^^^^^ ---- help: remove the unnecessary generic argument + | | + | expected 1 generic argument + | +note: type alias defined here, with 1 generic parameter: `T` + --> $DIR/auxiliary/issue-114682-4-extern.rs:2:14 + | +LL | pub type Result = std::result::Result; + | ^^^^^^ - + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. +Future incompatibility report: Future breakage diagnostic: +error: `Result` is ambiguous + --> $DIR/issue-114682-4.rs:9:11 + | +LL | fn a() -> Result { + | ^^^^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `Result` could refer to the type alias defined here + --> $DIR/auxiliary/issue-114682-4-extern.rs:9:9 + | +LL | pub use a::*; + | ^ +note: `Result` could also refer to the type alias defined here + --> $DIR/auxiliary/issue-114682-4-extern.rs:10:9 + | +LL | pub use b::*; + | ^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + diff --git a/tests/ui/imports/issue-114682-5.rs b/tests/ui/imports/issue-114682-5.rs index 7c6132ebd6ff..be33960e40b8 100644 --- a/tests/ui/imports/issue-114682-5.rs +++ b/tests/ui/imports/issue-114682-5.rs @@ -1,4 +1,3 @@ -//@ check-pass //@ edition: 2018 //@ aux-build: issue-114682-5-extern-1.rs //@ aux-build: issue-114682-5-extern-2.rs @@ -9,7 +8,9 @@ use issue_114682_5_extern_2::p::*; use issue_114682_5_extern_1::Url; -// FIXME: The `issue_114682_5_extern_1` should be considered an ambiguous item, -// as it has already been recognized as ambiguous in `issue_114682_5_extern_2`. +//~^ ERROR `issue_114682_5_extern_1` is ambiguous +//~| ERROR `issue_114682_5_extern_1` is ambiguous +//~| ERROR unresolved import `issue_114682_5_extern_1::Url` +//~| WARN this was previously accepted fn main() {} diff --git a/tests/ui/imports/issue-114682-5.stderr b/tests/ui/imports/issue-114682-5.stderr new file mode 100644 index 000000000000..427a5b16765b --- /dev/null +++ b/tests/ui/imports/issue-114682-5.stderr @@ -0,0 +1,77 @@ +error[E0432]: unresolved import `issue_114682_5_extern_1::Url` + --> $DIR/issue-114682-5.rs:10:5 + | +LL | use issue_114682_5_extern_1::Url; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `Url` in `types::issue_114682_5_extern_1` + | +help: consider importing this struct instead + | +LL | use ::issue_114682_5_extern_1::Url; + | ++ + +error[E0659]: `issue_114682_5_extern_1` is ambiguous + --> $DIR/issue-114682-5.rs:10:5 + | +LL | use issue_114682_5_extern_1::Url; + | ^^^^^^^^^^^^^^^^^^^^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution + = note: `issue_114682_5_extern_1` could refer to a crate passed with `--extern` + = help: use `::issue_114682_5_extern_1` to refer to this crate unambiguously +note: `issue_114682_5_extern_1` could also refer to the module imported here + --> $DIR/issue-114682-5.rs:9:5 + | +LL | use issue_114682_5_extern_2::p::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider adding an explicit import of `issue_114682_5_extern_1` to disambiguate + = help: or use `crate::issue_114682_5_extern_1` to refer to this module unambiguously + +error: `issue_114682_5_extern_1` is ambiguous + --> $DIR/issue-114682-5.rs:10:5 + | +LL | use issue_114682_5_extern_1::Url; + | ^^^^^^^^^^^^^^^^^^^^^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `issue_114682_5_extern_1` could refer to the module defined here + --> $DIR/auxiliary/issue-114682-5-extern-2.rs:6:13 + | +LL | pub use crate::types::*; + | ^^^^^^^^^^^^ +note: `issue_114682_5_extern_1` could also refer to the crate defined here + --> $DIR/auxiliary/issue-114682-5-extern-2.rs:7:13 + | +LL | pub use crate::*; + | ^^^^^ + = help: use `::issue_114682_5_extern_1` to refer to this crate unambiguously + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0432, E0659. +For more information about an error, try `rustc --explain E0432`. +Future incompatibility report: Future breakage diagnostic: +error: `issue_114682_5_extern_1` is ambiguous + --> $DIR/issue-114682-5.rs:10:5 + | +LL | use issue_114682_5_extern_1::Url; + | ^^^^^^^^^^^^^^^^^^^^^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `issue_114682_5_extern_1` could refer to the module defined here + --> $DIR/auxiliary/issue-114682-5-extern-2.rs:6:13 + | +LL | pub use crate::types::*; + | ^^^^^^^^^^^^ +note: `issue_114682_5_extern_1` could also refer to the crate defined here + --> $DIR/auxiliary/issue-114682-5-extern-2.rs:7:13 + | +LL | pub use crate::*; + | ^^^^^ + = help: use `::issue_114682_5_extern_1` to refer to this crate unambiguously + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + diff --git a/tests/ui/imports/issue-114682-6.rs b/tests/ui/imports/issue-114682-6.rs index d47b9f8a4e85..92173f4b8464 100644 --- a/tests/ui/imports/issue-114682-6.rs +++ b/tests/ui/imports/issue-114682-6.rs @@ -1,4 +1,3 @@ -//@ check-pass //@ aux-build: issue-114682-6-extern.rs // https://github.com/rust-lang/rust/pull/114682#issuecomment-1880755441 @@ -7,7 +6,7 @@ use issue_114682_6_extern::*; fn main() { - let log = 2; - //^ `log` should be identified as an ambiguous item. + let log = 2; //~ ERROR `log` is ambiguous + //~| WARN this was previously accepted let _ = log; } diff --git a/tests/ui/imports/issue-114682-6.stderr b/tests/ui/imports/issue-114682-6.stderr new file mode 100644 index 000000000000..67ad25798c19 --- /dev/null +++ b/tests/ui/imports/issue-114682-6.stderr @@ -0,0 +1,45 @@ +error: `log` is ambiguous + --> $DIR/issue-114682-6.rs:9:9 + | +LL | let log = 2; + | ^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `log` could refer to the function defined here + --> $DIR/auxiliary/issue-114682-6-extern.rs:8:9 + | +LL | pub use self::a::*; + | ^^^^^^^ +note: `log` could also refer to the function defined here + --> $DIR/auxiliary/issue-114682-6-extern.rs:9:9 + | +LL | pub use self::b::*; + | ^^^^^^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + +error: aborting due to 1 previous error + +Future incompatibility report: Future breakage diagnostic: +error: `log` is ambiguous + --> $DIR/issue-114682-6.rs:9:9 + | +LL | let log = 2; + | ^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `log` could refer to the function defined here + --> $DIR/auxiliary/issue-114682-6-extern.rs:8:9 + | +LL | pub use self::a::*; + | ^^^^^^^ +note: `log` could also refer to the function defined here + --> $DIR/auxiliary/issue-114682-6-extern.rs:9:9 + | +LL | pub use self::b::*; + | ^^^^^^^ + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + From 2a2da782d32f25d69b66880b5dca640e2be8fe3e Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Thu, 4 Dec 2025 21:53:11 +0000 Subject: [PATCH 420/585] add check for uninhabited types along side never --- compiler/rustc_mir_build/src/builder/mod.rs | 21 ++++++++++++++++++- .../uninhabited-unreachable-warning-149571.rs | 10 +++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/ui/uninhabited/uninhabited-unreachable-warning-149571.rs diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 206eb9126f54..14a24265a8f4 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -839,6 +839,25 @@ fn lint_and_remove_uninhabited(&mut self) { self.infcx.typing_env(self.param_env), ); + // check if the function's return type is inhabited + // this was added here because of this regression + // https://github.com/rust-lang/rust/issues/149571 + let output_is_inhabited = + if matches!(self.tcx.def_kind(self.def_id), DefKind::Fn | DefKind::AssocFn) { + self.tcx + .fn_sig(self.def_id) + .instantiate_identity() + .skip_binder() + .output() + .is_inhabited_from( + self.tcx, + self.parent_module, + self.infcx.typing_env(self.param_env), + ) + } else { + true + }; + if !ty_is_inhabited { // Unreachable code warnings are already emitted during type checking. // However, during type checking, full type information is being @@ -849,7 +868,7 @@ fn lint_and_remove_uninhabited(&mut self) { // uninhabited types (e.g. empty enums). The check above is used so // that we do not emit the same warning twice if the uninhabited type // is indeed `!`. - if !ty.is_never() { + if !ty.is_never() && output_is_inhabited { lints.push((target_bb, ty, term.source_info.span)); } diff --git a/tests/ui/uninhabited/uninhabited-unreachable-warning-149571.rs b/tests/ui/uninhabited/uninhabited-unreachable-warning-149571.rs new file mode 100644 index 000000000000..a389562d649e --- /dev/null +++ b/tests/ui/uninhabited/uninhabited-unreachable-warning-149571.rs @@ -0,0 +1,10 @@ +#![deny(unreachable_code)] +//@ run-pass + +use std::convert::Infallible; + +pub fn foo(f: impl FnOnce() -> Infallible) -> Infallible { + f() +} + +fn main() {} From 1986be2bcdddf0cd53cf9cb6a4ac59dc66bb86ae Mon Sep 17 00:00:00 2001 From: James Barford-Evans Date: Fri, 28 Nov 2025 10:10:07 +0000 Subject: [PATCH 421/585] Moved `struct Placeholder` --- .../src/diagnostics/bound_region_errors.rs | 39 +++++----- .../src/diagnostics/region_errors.rs | 8 +- .../rustc_borrowck/src/handle_placeholders.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 4 +- .../rustc_borrowck/src/region_infer/mod.rs | 14 ++-- .../region_infer/opaque_types/region_ctxt.rs | 2 +- .../rustc_borrowck/src/region_infer/values.rs | 77 +++++++++++-------- compiler/rustc_borrowck/src/type_check/mod.rs | 4 +- .../src/type_check/relate_tys.rs | 7 +- .../rustc_borrowck/src/universal_regions.rs | 49 ++++++++---- .../src/check/compare_impl_item.rs | 6 +- .../src/infer/canonical/canonicalizer.rs | 24 +++--- .../rustc_infer/src/infer/canonical/mod.rs | 16 ++-- .../src/infer/lexical_region_resolve/mod.rs | 8 +- compiler/rustc_infer/src/infer/mod.rs | 22 +++--- .../src/infer/outlives/obligations.rs | 2 +- .../infer/region_constraints/leak_check.rs | 8 +- .../src/infer/region_constraints/mod.rs | 20 ++--- .../src/infer/relate/higher_ranked.rs | 12 +-- .../rustc_infer/src/infer/snapshot/fudge.rs | 12 +-- compiler/rustc_middle/src/ty/consts.rs | 7 +- compiler/rustc_middle/src/ty/context.rs | 6 +- compiler/rustc_middle/src/ty/mod.rs | 41 ++++------ compiler/rustc_middle/src/ty/print/pretty.rs | 20 ++--- compiler/rustc_middle/src/ty/region.rs | 7 +- .../rustc_middle/src/ty/structural_impls.rs | 12 +-- compiler/rustc_middle/src/ty/sty.rs | 5 +- .../src/error_reporting/infer/region.rs | 4 +- .../src/traits/coherence.rs | 27 +++---- .../rustc_trait_selection/src/traits/mod.rs | 13 ++-- .../rustc_trait_selection/src/traits/util.rs | 12 +-- compiler/rustc_type_ir/src/binder.rs | 55 ++++++++++++- compiler/rustc_type_ir/src/ir_print.rs | 30 +++++--- compiler/rustc_type_ir/src/lib.rs | 2 +- 34 files changed, 326 insertions(+), 251 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 15b2a5ef2e21..254d28d243ff 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -52,8 +52,8 @@ pub(crate) fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> pub(crate) fn report_erroneous_element( &self, mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>, - placeholder: ty::PlaceholderRegion, - error_element: RegionElement, + placeholder: ty::PlaceholderRegion<'tcx>, + error_element: RegionElement<'tcx>, cause: ObligationCause<'tcx>, ) { match *self { @@ -152,8 +152,8 @@ fn nice_error<'infcx>( fn report_erroneous_element( &self, mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>, - placeholder: ty::PlaceholderRegion, - error_element: RegionElement, + placeholder: ty::PlaceholderRegion<'tcx>, + error_element: RegionElement<'tcx>, cause: ObligationCause<'tcx>, ) { let tcx = mbcx.infcx.tcx; @@ -169,23 +169,22 @@ fn report_erroneous_element( let placeholder_region = ty::Region::new_placeholder( tcx, - ty::Placeholder { universe: adjusted_universe.into(), bound: placeholder.bound }, + ty::Placeholder::new(adjusted_universe.into(), placeholder.bound), ); - let error_region = if let RegionElement::PlaceholderRegion(error_placeholder) = - error_element - { - let adjusted_universe = - error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); - adjusted_universe.map(|adjusted| { - ty::Region::new_placeholder( - tcx, - ty::Placeholder { universe: adjusted.into(), bound: error_placeholder.bound }, - ) - }) - } else { - None - }; + let error_region = + if let RegionElement::PlaceholderRegion(error_placeholder) = error_element { + let adjusted_universe = + error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); + adjusted_universe.map(|adjusted| { + ty::Region::new_placeholder( + tcx, + ty::Placeholder::new(adjusted.into(), error_placeholder.bound), + ) + }) + } else { + None + }; debug!(?placeholder_region); @@ -440,7 +439,7 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>( placeholder_region: ty::Region<'tcx>, error_region: Option>, region_constraints: &RegionConstraintData<'tcx>, - mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin, + mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin<'tcx>, mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex, ) -> Option> { let placeholder_universe = match placeholder_region.kind() { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 05826bea66bf..408e0f7e03f6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -109,15 +109,15 @@ pub(crate) enum RegionErrorKind<'tcx> { /// The placeholder free region. longer_fr: RegionVid, /// The region element that erroneously must be outlived by `longer_fr`. - error_element: RegionElement, + error_element: RegionElement<'tcx>, /// The placeholder region. - placeholder: ty::PlaceholderRegion, + placeholder: ty::PlaceholderRegion<'tcx>, }, /// Any other lifetime error. RegionError { /// The origin of the region. - fr_origin: NllRegionVariableOrigin, + fr_origin: NllRegionVariableOrigin<'tcx>, /// The region that should outlive `shorter_fr`. longer_fr: RegionVid, /// The region that should be shorter, but we can't prove it. @@ -427,7 +427,7 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) { pub(crate) fn report_region_error( &mut self, fr: RegionVid, - fr_origin: NllRegionVariableOrigin, + fr_origin: NllRegionVariableOrigin<'tcx>, outlived_fr: RegionVid, outlives_suggestion: &mut OutlivesSuggestionBuilder, ) { diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs index d23ecf6c7079..60be521c29af 100644 --- a/compiler/rustc_borrowck/src/handle_placeholders.rs +++ b/compiler/rustc_borrowck/src/handle_placeholders.rs @@ -32,7 +32,7 @@ pub(crate) struct LoweredConstraints<'tcx> { pub(crate) type_tests: Vec>, pub(crate) liveness_constraints: LivenessValues, pub(crate) universe_causes: FxIndexMap>, - pub(crate) placeholder_indices: PlaceholderIndices, + pub(crate) placeholder_indices: PlaceholderIndices<'tcx>, } impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 20411fcc16fb..8d61ffde116c 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -661,7 +661,7 @@ pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, root_def_id: LocalDefId pub(crate) fn next_region_var( &self, - origin: RegionVariableOrigin, + origin: RegionVariableOrigin<'tcx>, get_ctxt_fn: F, ) -> ty::Region<'tcx> where @@ -683,7 +683,7 @@ pub(crate) fn next_region_var( #[instrument(skip(self, get_ctxt_fn), level = "debug")] pub(crate) fn next_nll_region_var( &self, - origin: NllRegionVariableOrigin, + origin: NllRegionVariableOrigin<'tcx>, get_ctxt_fn: F, ) -> ty::Region<'tcx> where diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index e98c60e63380..847e1ebe56fb 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -110,7 +110,7 @@ pub struct RegionInferenceContext<'tcx> { /// The final inferred values of the region variables; we compute /// one value per SCC. To get the value for any given *region*, /// you first find which scc it is a part of. - scc_values: RegionValues, + scc_values: RegionValues<'tcx, ConstraintSccIndex>, /// Type constraints that we check after solving. type_tests: Vec>, @@ -125,7 +125,7 @@ pub(crate) struct RegionDefinition<'tcx> { /// What kind of variable is this -- a free region? existential /// variable? etc. (See the `NllRegionVariableOrigin` for more /// info.) - pub(crate) origin: NllRegionVariableOrigin, + pub(crate) origin: NllRegionVariableOrigin<'tcx>, /// Which universe is this region variable defined in? This is /// most often `ty::UniverseIndex::ROOT`, but when we encounter @@ -453,7 +453,7 @@ pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, ()>) { /// Returns `true` if the region `r` contains the point `p`. /// /// Panics if called before `solve()` executes, - pub(crate) fn region_contains(&self, r: RegionVid, p: impl ToElementIndex) -> bool { + pub(crate) fn region_contains(&self, r: RegionVid, p: impl ToElementIndex<'tcx>) -> bool { let scc = self.constraint_sccs.scc(r); self.scc_values.contains(scc, p) } @@ -481,7 +481,7 @@ pub(crate) fn region_value_str(&self, r: RegionVid) -> String { pub(crate) fn placeholders_contained_in( &self, r: RegionVid, - ) -> impl Iterator { + ) -> impl Iterator> { let scc = self.constraint_sccs.scc(r); self.scc_values.placeholders_contained_in(scc) } @@ -1311,7 +1311,7 @@ fn try_propagate_universal_region_error( fn check_bound_universal_region( &self, longer_fr: RegionVid, - placeholder: ty::PlaceholderRegion, + placeholder: ty::PlaceholderRegion<'tcx>, errors_buffer: &mut RegionErrors<'tcx>, ) { debug!("check_bound_universal_region(fr={:?}, placeholder={:?})", longer_fr, placeholder,); @@ -1523,7 +1523,7 @@ pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, location: Location) pub(crate) fn region_from_element( &self, longer_fr: RegionVid, - element: &RegionElement, + element: &RegionElement<'tcx>, ) -> RegionVid { match *element { RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l), @@ -1564,7 +1564,7 @@ pub(crate) fn universal_regions(&self) -> &UniversalRegions<'tcx> { pub(crate) fn best_blame_constraint( &self, from_region: RegionVid, - from_region_origin: NllRegionVariableOrigin, + from_region_origin: NllRegionVariableOrigin<'tcx>, to_region: RegionVid, ) -> (BlameConstraint<'tcx>, Vec>) { assert!(from_region != to_region, "Trying to blame a region for itself!"); diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/region_ctxt.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/region_ctxt.rs index 90b15cbdd2cc..ada8908e220a 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/region_ctxt.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/region_ctxt.rs @@ -27,7 +27,7 @@ pub(super) struct RegionCtxt<'a, 'tcx> { pub(super) constraint_sccs: ConstraintSccs, pub(super) scc_annotations: IndexVec, pub(super) rev_scc_graph: ReverseSccGraph, - pub(super) scc_values: RegionValues, + pub(super) scc_values: RegionValues<'tcx, ConstraintSccIndex>, } impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index eb611fa34757..0063af25d781 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -10,8 +10,8 @@ use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; use tracing::debug; -use crate::BorrowIndex; use crate::polonius::LiveLoans; +use crate::{BorrowIndex, TyCtxt}; rustc_index::newtype_index! { /// A single integer representing a `ty::Placeholder`. @@ -22,7 +22,7 @@ pub(crate) struct PlaceholderIndex {} /// An individual element in a region value -- the value of a /// particular region variable consists of a set of these elements. #[derive(Debug, Clone, PartialEq)] -pub(crate) enum RegionElement { +pub(crate) enum RegionElement<'tcx> { /// A point in the control-flow graph. Location(Location), @@ -32,7 +32,7 @@ pub(crate) enum RegionElement { /// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)` /// type). - PlaceholderRegion(ty::PlaceholderRegion), + PlaceholderRegion(ty::PlaceholderRegion<'tcx>), } /// Records the CFG locations where each region is live. When we initially compute liveness, we use @@ -196,25 +196,28 @@ pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, point: PointIndex) - /// NLL. #[derive(Debug, Default)] #[derive(Clone)] // FIXME(#146079) -pub(crate) struct PlaceholderIndices { - indices: FxIndexSet, +pub(crate) struct PlaceholderIndices<'tcx> { + indices: FxIndexSet>, } -impl PlaceholderIndices { +impl<'tcx> PlaceholderIndices<'tcx> { /// Returns the `PlaceholderIndex` for the inserted `PlaceholderRegion` - pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { + pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion<'tcx>) -> PlaceholderIndex { let (index, _) = self.indices.insert_full(placeholder); index.into() } - pub(crate) fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { + pub(crate) fn lookup_index( + &self, + placeholder: ty::PlaceholderRegion<'tcx>, + ) -> PlaceholderIndex { self.indices.get_index_of(&placeholder).unwrap().into() } pub(crate) fn lookup_placeholder( &self, placeholder: PlaceholderIndex, - ) -> ty::PlaceholderRegion { + ) -> ty::PlaceholderRegion<'tcx> { self.indices[placeholder.index()] } @@ -241,9 +244,9 @@ pub(crate) fn len(&self) -> usize { /// Here, the variable `'0` would contain the free region `'a`, /// because (since it is returned) it must live for at least `'a`. But /// it would also contain various points from within the function. -pub(crate) struct RegionValues { +pub(crate) struct RegionValues<'tcx, N: Idx> { location_map: Rc, - placeholder_indices: PlaceholderIndices, + placeholder_indices: PlaceholderIndices<'tcx>, points: SparseIntervalMatrix, free_regions: SparseBitMatrix, @@ -252,14 +255,14 @@ pub(crate) struct RegionValues { placeholders: SparseBitMatrix, } -impl RegionValues { +impl<'tcx, N: Idx> RegionValues<'tcx, N> { /// Creates a new set of "region values" that tracks causal information. /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. pub(crate) fn new( location_map: Rc, num_universal_regions: usize, - placeholder_indices: PlaceholderIndices, + placeholder_indices: PlaceholderIndices<'tcx>, ) -> Self { let num_points = location_map.num_points(); let num_placeholders = placeholder_indices.len(); @@ -274,7 +277,7 @@ pub(crate) fn new( /// Adds the given element to the value for the given region. Returns whether /// the element is newly added (i.e., was not already present). - pub(crate) fn add_element(&mut self, r: N, elem: impl ToElementIndex) -> bool { + pub(crate) fn add_element(&mut self, r: N, elem: impl ToElementIndex<'tcx>) -> bool { debug!("add(r={:?}, elem={:?})", r, elem); elem.add_to_row(self, r) } @@ -293,7 +296,7 @@ pub(crate) fn add_region(&mut self, r_to: N, r_from: N) -> bool { } /// Returns `true` if the region `r` contains the given element. - pub(crate) fn contains(&self, r: N, elem: impl ToElementIndex) -> bool { + pub(crate) fn contains(&self, r: N, elem: impl ToElementIndex<'tcx>) -> bool { elem.contained_in_row(self, r) } @@ -359,7 +362,7 @@ pub(crate) fn universal_regions_outlived_by(&self, r: N) -> impl Iterator impl Iterator { + ) -> impl Iterator> { self.placeholders .row(r) .into_iter() @@ -368,7 +371,7 @@ pub(crate) fn placeholders_contained_in( } /// Returns all the elements contained in a given region's value. - pub(crate) fn elements_contained_in(&self, r: N) -> impl Iterator { + pub(crate) fn elements_contained_in(&self, r: N) -> impl Iterator> { let points_iter = self.locations_outlived_by(r).map(RegionElement::Location); let free_regions_iter = @@ -386,42 +389,50 @@ pub(crate) fn region_value_str(&self, r: N) -> String { } } -pub(crate) trait ToElementIndex: Debug + Copy { - fn add_to_row(self, values: &mut RegionValues, row: N) -> bool; +pub(crate) trait ToElementIndex<'tcx>: Debug + Copy { + fn add_to_row(self, values: &mut RegionValues<'tcx, N>, row: N) -> bool; - fn contained_in_row(self, values: &RegionValues, row: N) -> bool; + fn contained_in_row(self, values: &RegionValues<'tcx, N>, row: N) -> bool; } -impl ToElementIndex for Location { - fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { +impl ToElementIndex<'_> for Location { + fn add_to_row(self, values: &mut RegionValues<'_, N>, row: N) -> bool { let index = values.location_map.point_from_location(self); values.points.insert(row, index) } - fn contained_in_row(self, values: &RegionValues, row: N) -> bool { + fn contained_in_row(self, values: &RegionValues<'_, N>, row: N) -> bool { let index = values.location_map.point_from_location(self); values.points.contains(row, index) } } -impl ToElementIndex for RegionVid { - fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { +impl ToElementIndex<'_> for RegionVid { + fn add_to_row(self, values: &mut RegionValues<'_, N>, row: N) -> bool { values.free_regions.insert(row, self) } - fn contained_in_row(self, values: &RegionValues, row: N) -> bool { + fn contained_in_row(self, values: &RegionValues<'_, N>, row: N) -> bool { values.free_regions.contains(row, self) } } -impl ToElementIndex for ty::PlaceholderRegion { - fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { - let index = values.placeholder_indices.lookup_index(self); +impl<'tcx> ToElementIndex<'tcx> for ty::PlaceholderRegion<'tcx> { + fn add_to_row(self, values: &mut RegionValues<'tcx, N>, row: N) -> bool + where + Self: Into, ty::BoundRegion>>, + { + let placeholder: ty::Placeholder, ty::BoundRegion> = self.into(); + let index = values.placeholder_indices.lookup_index(placeholder); values.placeholders.insert(row, index) } - fn contained_in_row(self, values: &RegionValues, row: N) -> bool { - let index = values.placeholder_indices.lookup_index(self); + fn contained_in_row(self, values: &RegionValues<'tcx, N>, row: N) -> bool + where + Self: Into, ty::BoundRegion>>, + { + let placeholder: ty::Placeholder, ty::BoundRegion> = self.into(); + let index = values.placeholder_indices.lookup_index(placeholder); values.placeholders.contains(row, index) } } @@ -441,7 +452,9 @@ pub(crate) fn pretty_print_points( } /// For debugging purposes, returns a pretty-printed string of the given region elements. -fn pretty_print_region_elements(elements: impl IntoIterator) -> String { +fn pretty_print_region_elements<'tcx>( + elements: impl IntoIterator>, +) -> String { let mut result = String::new(); result.push('{'); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 43005fca2984..e51f059b8de1 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -258,7 +258,7 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> { /// /// To keep everything in sync, do not insert this set /// directly. Instead, use the `placeholder_region` helper. - pub(crate) placeholder_indices: PlaceholderIndices, + pub(crate) placeholder_indices: PlaceholderIndices<'tcx>, /// Each time we add a placeholder to `placeholder_indices`, we /// also create a corresponding "representative" region vid for @@ -289,7 +289,7 @@ impl<'tcx> MirTypeckRegionConstraints<'tcx> { pub(crate) fn placeholder_region( &mut self, infcx: &InferCtxt<'tcx>, - placeholder: ty::PlaceholderRegion, + placeholder: ty::PlaceholderRegion<'tcx>, ) -> ty::Region<'tcx> { let placeholder_index = self.placeholder_indices.insert(placeholder); match self.placeholder_index_to_region.get(placeholder_index) { diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 539912609baa..045507ceb4b4 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -184,7 +184,7 @@ fn enter_forall( universe }); - let placeholder = ty::PlaceholderRegion { universe, bound: br }; + let placeholder = ty::PlaceholderRegion::new(universe, br); debug!(?placeholder); let placeholder_reg = self.next_placeholder_region(placeholder); debug!(?placeholder_reg); @@ -257,7 +257,10 @@ fn next_existential_region_var(&mut self, name: Option) -> ty::Region<'t } #[instrument(skip(self), level = "debug")] - fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { + fn next_placeholder_region( + &mut self, + placeholder: ty::PlaceholderRegion<'tcx>, + ) -> ty::Region<'tcx> { let reg = self.type_checker.constraints.placeholder_region(self.type_checker.infcx, placeholder); diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 64a7b4084349..aee1eb94dc81 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -454,8 +454,6 @@ struct UniversalRegionsBuilder<'infcx, 'tcx> { mir_def: LocalDefId, } -const FR: NllRegionVariableOrigin = NllRegionVariableOrigin::FreeRegion; - impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { fn build(self) -> UniversalRegions<'tcx> { debug!("build(mir_def={:?})", self.mir_def); @@ -466,8 +464,12 @@ fn build(self) -> UniversalRegions<'tcx> { assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars()); // Create the "global" region that is always free in all contexts: 'static. - let fr_static = - self.infcx.next_nll_region_var(FR, || RegionCtxt::Free(kw::Static)).as_var(); + let fr_static = self + .infcx + .next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || { + RegionCtxt::Free(kw::Static) + }) + .as_var(); // We've now added all the global regions. The next ones we // add will be external. @@ -500,7 +502,9 @@ fn build(self) -> UniversalRegions<'tcx> { debug!(?r); let region_vid = { let name = r.get_name_or_anon(self.infcx.tcx); - self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) + self.infcx.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || { + RegionCtxt::LateBound(name) + }) }; debug!(?region_vid); @@ -526,7 +530,9 @@ fn build(self) -> UniversalRegions<'tcx> { let r = ty::Region::new_late_param(self.infcx.tcx, self.mir_def.to_def_id(), kind); let region_vid = { let name = r.get_name_or_anon(self.infcx.tcx); - self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) + self.infcx.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || { + RegionCtxt::LateBound(name) + }) }; debug!(?region_vid); @@ -553,7 +559,9 @@ fn build(self) -> UniversalRegions<'tcx> { let reg_vid = self .infcx - .next_nll_region_var(FR, || RegionCtxt::Free(sym::c_dash_variadic)) + .next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || { + RegionCtxt::Free(sym::c_dash_variadic) + }) .as_var(); let region = ty::Region::new_var(self.infcx.tcx, reg_vid); @@ -569,8 +577,12 @@ fn build(self) -> UniversalRegions<'tcx> { } } - let fr_fn_body = - self.infcx.next_nll_region_var(FR, || RegionCtxt::Free(sym::fn_body)).as_var(); + let fr_fn_body = self + .infcx + .next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || { + RegionCtxt::Free(sym::fn_body) + }) + .as_var(); let num_universals = self.infcx.num_region_vars(); @@ -613,8 +625,10 @@ fn defining_ty(&self) -> DefiningTy<'tcx> { debug!("defining_ty (pre-replacement): {:?}", defining_ty); - let defining_ty = - self.infcx.replace_free_regions_with_nll_infer_vars(FR, defining_ty); + let defining_ty = self.infcx.replace_free_regions_with_nll_infer_vars( + NllRegionVariableOrigin::FreeRegion, + defining_ty, + ); match *defining_ty.kind() { ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args), @@ -638,8 +652,10 @@ fn defining_ty(&self) -> DefiningTy<'tcx> { // Do not ICE when checking default_field_values consts with lifetimes (#135649) && DefKind::Field != tcx.def_kind(tcx.parent(typeck_root_def_id)) { - let args = - self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_args); + let args = self.infcx.replace_free_regions_with_nll_infer_vars( + NllRegionVariableOrigin::FreeRegion, + identity_args, + ); DefiningTy::Const(self.mir_def.to_def_id(), args) } else { // FIXME this line creates a dependency between borrowck and typeck. @@ -659,7 +675,10 @@ fn defining_ty(&self) -> DefiningTy<'tcx> { InlineConstArgsParts { parent_args: identity_args, ty }, ) .args; - let args = self.infcx.replace_free_regions_with_nll_infer_vars(FR, args); + let args = self.infcx.replace_free_regions_with_nll_infer_vars( + NllRegionVariableOrigin::FreeRegion, + args, + ); DefiningTy::InlineConst(self.mir_def.to_def_id(), args) } } @@ -856,7 +875,7 @@ impl<'tcx> BorrowckInferCtxt<'tcx> { #[instrument(skip(self), level = "debug")] fn replace_free_regions_with_nll_infer_vars( &self, - origin: NllRegionVariableOrigin, + origin: NllRegionVariableOrigin<'tcx>, value: T, ) -> T where diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index fa497cc21e40..c18faa785b16 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -590,10 +590,10 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( ty, Ty::new_placeholder( tcx, - ty::Placeholder { + ty::Placeholder::new( universe, - bound: ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon }, - }, + ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon }, + ), ), ) }) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index e445def4faa7..c07b41b56caa 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -684,22 +684,22 @@ fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar { CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]), CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]), CanonicalVarKind::PlaceholderTy(placeholder) => { - CanonicalVarKind::PlaceholderTy(ty::Placeholder { - universe: reverse_universe_map[&placeholder.universe], - ..placeholder - }) + CanonicalVarKind::PlaceholderTy(ty::Placeholder::new( + reverse_universe_map[&placeholder.universe], + placeholder.bound, + )) } CanonicalVarKind::PlaceholderRegion(placeholder) => { - CanonicalVarKind::PlaceholderRegion(ty::Placeholder { - universe: reverse_universe_map[&placeholder.universe], - ..placeholder - }) + CanonicalVarKind::PlaceholderRegion(ty::Placeholder::new( + reverse_universe_map[&placeholder.universe], + placeholder.bound, + )) } CanonicalVarKind::PlaceholderConst(placeholder) => { - CanonicalVarKind::PlaceholderConst(ty::Placeholder { - universe: reverse_universe_map[&placeholder.universe], - ..placeholder - }) + CanonicalVarKind::PlaceholderConst(ty::Placeholder::new( + reverse_universe_map[&placeholder.universe], + placeholder.bound, + )) } }) .collect() diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index f99f228e19d8..9af0e17be4e2 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -109,9 +109,9 @@ pub fn instantiate_canonical_var( CanonicalVarKind::Float => self.next_float_var().into(), - CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound }) => { + CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound, .. }) => { let universe_mapped = universe_map(universe); - let placeholder_mapped = ty::PlaceholderType { universe: universe_mapped, bound }; + let placeholder_mapped = ty::PlaceholderType::new(universe_mapped, bound); Ty::new_placeholder(self.tcx, placeholder_mapped).into() } @@ -119,18 +119,22 @@ pub fn instantiate_canonical_var( .next_region_var_in_universe(RegionVariableOrigin::Misc(span), universe_map(ui)) .into(), - CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, bound }) => { + CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { + universe, bound, .. + }) => { let universe_mapped = universe_map(universe); - let placeholder_mapped = ty::PlaceholderRegion { universe: universe_mapped, bound }; + let placeholder_mapped = ty::PlaceholderRegion::new(universe_mapped, bound); ty::Region::new_placeholder(self.tcx, placeholder_mapped).into() } CanonicalVarKind::Const(ui) => { self.next_const_var_in_universe(span, universe_map(ui)).into() } - CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }) => { + CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { + universe, bound, .. + }) => { let universe_mapped = universe_map(universe); - let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound }; + let placeholder_mapped = ty::PlaceholderConst::new(universe_mapped, bound); ty::Const::new_placeholder(self.tcx, placeholder_mapped).into() } } diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 3adcfb427278..5134b7b7ca8f 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -31,7 +31,7 @@ #[instrument(level = "debug", skip(region_rels, var_infos, data))] pub(crate) fn resolve<'tcx>( region_rels: &RegionRelations<'_, 'tcx>, - var_infos: VarInfos, + var_infos: VarInfos<'tcx>, data: RegionConstraintData<'tcx>, ) -> (LexicalRegionResolutions<'tcx>, Vec>) { let mut errors = vec![]; @@ -80,7 +80,7 @@ pub enum RegionResolutionError<'tcx> { /// `sub_r <= sup_r` does not hold. SubSupConflict( RegionVid, - RegionVariableOrigin, + RegionVariableOrigin<'tcx>, SubregionOrigin<'tcx>, Region<'tcx>, SubregionOrigin<'tcx>, @@ -92,7 +92,7 @@ pub enum RegionResolutionError<'tcx> { /// cannot name the placeholder `'b`. UpperBoundUniverseConflict( RegionVid, - RegionVariableOrigin, + RegionVariableOrigin<'tcx>, ty::UniverseIndex, // the universe index of the region variable SubregionOrigin<'tcx>, // cause of the constraint Region<'tcx>, // the placeholder `'b` @@ -122,7 +122,7 @@ struct RegionAndOrigin<'tcx> { struct LexicalResolver<'cx, 'tcx> { region_rels: &'cx RegionRelations<'cx, 'tcx>, - var_infos: VarInfos, + var_infos: VarInfos<'tcx>, data: RegionConstraintData<'tcx>, } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index dc4ee0d88a06..53567c6071e3 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -421,7 +421,7 @@ pub enum BoundRegionConversionTime { /// /// See `error_reporting` module for more details. #[derive(Copy, Clone, Debug)] -pub enum RegionVariableOrigin { +pub enum RegionVariableOrigin<'tcx> { /// Region variables created for ill-categorized reasons. /// /// They mostly indicate places in need of refactoring. @@ -453,11 +453,11 @@ pub enum RegionVariableOrigin { /// This origin is used for the inference variables that we create /// during NLL region processing. - Nll(NllRegionVariableOrigin), + Nll(NllRegionVariableOrigin<'tcx>), } #[derive(Copy, Clone, Debug)] -pub enum NllRegionVariableOrigin { +pub enum NllRegionVariableOrigin<'tcx> { /// During NLL region processing, we create variables for free /// regions that we encounter in the function signature and /// elsewhere. This origin indices we've got one of those. @@ -465,7 +465,7 @@ pub enum NllRegionVariableOrigin { /// "Universal" instantiation of a higher-ranked region (e.g., /// from a `for<'a> T` binder). Meant to represent "any region". - Placeholder(ty::PlaceholderRegion), + Placeholder(ty::PlaceholderRegion<'tcx>), Existential { name: Option, @@ -838,7 +838,7 @@ pub fn next_float_var(&self) -> Ty<'tcx> { /// Creates a fresh region variable with the next available index. /// The variable will be created in the maximum universe created /// thus far, allowing it to name any region created thus far. - pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region<'tcx> { + pub fn next_region_var(&self, origin: RegionVariableOrigin<'tcx>) -> ty::Region<'tcx> { self.next_region_var_in_universe(origin, self.universe()) } @@ -847,7 +847,7 @@ pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region<'tcx> /// `next_region_var` and just use the maximal universe. pub fn next_region_var_in_universe( &self, - origin: RegionVariableOrigin, + origin: RegionVariableOrigin<'tcx>, universe: ty::UniverseIndex, ) -> ty::Region<'tcx> { let region_var = @@ -878,7 +878,7 @@ pub fn num_region_vars(&self) -> usize { /// Just a convenient wrapper of `next_region_var` for using during NLL. #[instrument(skip(self), level = "debug")] - pub fn next_nll_region_var(&self, origin: NllRegionVariableOrigin) -> ty::Region<'tcx> { + pub fn next_nll_region_var(&self, origin: NllRegionVariableOrigin<'tcx>) -> ty::Region<'tcx> { self.next_region_var(RegionVariableOrigin::Nll(origin)) } @@ -886,7 +886,7 @@ pub fn next_nll_region_var(&self, origin: NllRegionVariableOrigin) -> ty::Region #[instrument(skip(self), level = "debug")] pub fn next_nll_region_var_in_universe( &self, - origin: NllRegionVariableOrigin, + origin: NllRegionVariableOrigin<'tcx>, universe: ty::UniverseIndex, ) -> ty::Region<'tcx> { self.next_region_var_in_universe(RegionVariableOrigin::Nll(origin), universe) @@ -954,7 +954,7 @@ pub fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { self.tainted_by_errors.set(Some(e)); } - pub fn region_var_origin(&self, vid: ty::RegionVid) -> RegionVariableOrigin { + pub fn region_var_origin(&self, vid: ty::RegionVid) -> RegionVariableOrigin<'tcx> { let mut inner = self.inner.borrow_mut(); let inner = &mut *inner; inner.unwrap_region_constraints().var_origin(vid) @@ -962,7 +962,7 @@ pub fn region_var_origin(&self, vid: ty::RegionVid) -> RegionVariableOrigin { /// Clone the list of variable regions. This is used only during NLL processing /// to put the set of region variables into the NLL region context. - pub fn get_region_var_infos(&self) -> VarInfos { + pub fn get_region_var_infos(&self) -> VarInfos<'tcx> { let inner = self.inner.borrow(); assert!(!UndoLogs::>::in_snapshot(&inner.undo_log)); let storage = inner.region_constraint_storage.as_ref().expect("regions already resolved"); @@ -1649,7 +1649,7 @@ pub fn from_obligation_cause(cause: &traits::ObligationCause<'tcx>, default: } } -impl RegionVariableOrigin { +impl<'tcx> RegionVariableOrigin<'tcx> { pub fn span(&self) -> Span { match *self { RegionVariableOrigin::Misc(a) diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index a640dcb1b4e1..f06f50785ecc 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -394,7 +394,7 @@ fn placeholder_ty_must_outlive( &mut self, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, - placeholder_ty: ty::PlaceholderType, + placeholder_ty: ty::PlaceholderType<'tcx>, ) { let verify_bound = self .verify_bound diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 4d76bc2e17a1..4ef1ea5a1c4d 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -105,7 +105,7 @@ struct LeakCheck<'a, 'tcx> { // is repurposed to store some placeholder `P` such that the weaker // condition `S: P` must hold. (This is true if `S: S1` transitively and `S1 // = P`.) - scc_placeholders: IndexVec>, + scc_placeholders: IndexVec>>, // For each SCC S, track the minimum universe that flows into it. Note that // this is both the minimum of the universes for every region that is a @@ -258,15 +258,15 @@ fn propagate_scc_value(&mut self) -> RelateResult<'tcx, ()> { fn placeholder_error( &self, - placeholder1: ty::PlaceholderRegion, - placeholder2: ty::PlaceholderRegion, + placeholder1: ty::PlaceholderRegion<'tcx>, + placeholder2: ty::PlaceholderRegion<'tcx>, ) -> TypeError<'tcx> { self.error(placeholder1, ty::Region::new_placeholder(self.tcx, placeholder2)) } fn error( &self, - placeholder: ty::PlaceholderRegion, + placeholder: ty::PlaceholderRegion<'tcx>, other_region: ty::Region<'tcx>, ) -> TypeError<'tcx> { debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region); diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 85f5e55a8e1e..ae7481b5d1e7 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -23,7 +23,7 @@ #[derive(Clone, Default)] pub struct RegionConstraintStorage<'tcx> { /// For each `RegionVid`, the corresponding `RegionVariableOrigin`. - pub(super) var_infos: IndexVec, + pub(super) var_infos: IndexVec>, pub(super) data: RegionConstraintData<'tcx>, @@ -57,7 +57,7 @@ pub struct RegionConstraintCollector<'a, 'tcx> { undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } -pub type VarInfos = IndexVec; +pub type VarInfos<'tcx> = IndexVec>; /// The full set of region constraints gathered up by the collector. /// Describes constraints between the region variables and other @@ -125,7 +125,7 @@ pub struct Verify<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] pub enum GenericKind<'tcx> { Param(ty::ParamTy), - Placeholder(ty::PlaceholderType), + Placeholder(ty::PlaceholderType<'tcx>), Alias(ty::AliasTy<'tcx>), } @@ -269,8 +269,8 @@ pub(crate) enum CombineMapType { type CombineMap<'tcx> = FxHashMap, RegionVid>; #[derive(Debug, Clone, Copy)] -pub struct RegionVariableInfo { - pub origin: RegionVariableOrigin, +pub struct RegionVariableInfo<'tcx> { + pub origin: RegionVariableOrigin<'tcx>, // FIXME: This is only necessary for `fn take_and_reset_data` and // `lexical_region_resolve`. We should rework `lexical_region_resolve` // in the near/medium future anyways and could move the unverse info @@ -374,7 +374,7 @@ pub(super) fn rollback_to(&mut self, snapshot: RegionSnapshot) { pub(super) fn new_region_var( &mut self, universe: ty::UniverseIndex, - origin: RegionVariableOrigin, + origin: RegionVariableOrigin<'tcx>, ) -> RegionVid { let vid = self.storage.var_infos.push(RegionVariableInfo { origin, universe }); @@ -386,7 +386,7 @@ pub(super) fn new_region_var( } /// Returns the origin for the given variable. - pub(super) fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin { + pub(super) fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin<'tcx> { self.storage.var_infos[vid].origin } @@ -624,10 +624,10 @@ pub fn universe(&mut self, region: Region<'tcx>) -> ty::UniverseIndex { } } - pub fn vars_since_snapshot( - &self, + pub fn vars_since_snapshot<'a>( + &'a self, value_count: usize, - ) -> (Range, Vec) { + ) -> (Range, Vec>) { let range = RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len()); ( diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 16fe591b29bb..7a0f70e979b8 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -34,21 +34,15 @@ pub fn enter_forall_and_leak_universe(&self, binder: ty::Binder<'tcx, T>) -> let delegate = FnMutDelegate { regions: &mut |br: ty::BoundRegion| { - ty::Region::new_placeholder( - self.tcx, - ty::PlaceholderRegion { universe: next_universe, bound: br }, - ) + ty::Region::new_placeholder(self.tcx, ty::PlaceholderRegion::new(next_universe, br)) }, types: &mut |bound_ty: ty::BoundTy| { - Ty::new_placeholder( - self.tcx, - ty::PlaceholderType { universe: next_universe, bound: bound_ty }, - ) + Ty::new_placeholder(self.tcx, ty::PlaceholderType::new(next_universe, bound_ty)) }, consts: &mut |bound_const: ty::BoundConst| { ty::Const::new_placeholder( self.tcx, - ty::PlaceholderConst { universe: next_universe, bound: bound_const }, + ty::PlaceholderConst::new(next_universe, bound_const), ) }, }; diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 3730d215a901..6709c822dc7b 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -113,7 +113,7 @@ pub fn fudge_inference_if_ok(&self, f: F) -> Result fn fudge_inference>>( &self, - snapshot_vars: SnapshotVarData, + snapshot_vars: SnapshotVarData<'tcx>, value: T, ) -> T { // Micro-optimization: if no variables have been created, then @@ -126,16 +126,16 @@ fn fudge_inference>>( } } -struct SnapshotVarData { - region_vars: (Range, Vec), +struct SnapshotVarData<'tcx> { + region_vars: (Range, Vec>), type_vars: (Range, Vec), int_vars: Range, float_vars: Range, const_vars: (Range, Vec), } -impl SnapshotVarData { - fn new(infcx: &InferCtxt<'_>, vars_pre_snapshot: VariableLengths) -> SnapshotVarData { +impl<'tcx> SnapshotVarData<'tcx> { + fn new(infcx: &InferCtxt<'tcx>, vars_pre_snapshot: VariableLengths) -> SnapshotVarData<'tcx> { let mut inner = infcx.inner.borrow_mut(); let region_vars = inner .unwrap_region_constraints() @@ -165,7 +165,7 @@ fn is_empty(&self) -> bool { struct InferenceFudger<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, - snapshot_vars: SnapshotVarData, + snapshot_vars: SnapshotVarData<'tcx>, } impl<'a, 'tcx> TypeFolder> for InferenceFudger<'a, 'tcx> { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 95adb561c704..787ea5f9363d 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -107,7 +107,10 @@ pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Const<'tcx> } #[inline] - pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Const<'tcx> { + pub fn new_placeholder( + tcx: TyCtxt<'tcx>, + placeholder: ty::PlaceholderConst<'tcx>, + ) -> Const<'tcx> { Const::new(tcx, ty::ConstKind::Placeholder(placeholder)) } @@ -192,7 +195,7 @@ fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: rustc_type_ir::BoundVar) -> Self Const::new_canonical_bound(tcx, var) } - fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Self { + fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst<'tcx>) -> Self { Const::new_placeholder(tcx, placeholder) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 88f0a2a7c23c..471bd1d937e9 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -148,7 +148,7 @@ fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, DepNodeIndex) { type BoundTy = ty::BoundTy; type Symbol = Symbol; - type PlaceholderTy = ty::PlaceholderType; + type PlaceholderTy = ty::PlaceholderType<'tcx>; type ErrorGuaranteed = ErrorGuaranteed; type BoundExistentialPredicates = &'tcx List>; @@ -158,7 +158,7 @@ fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, DepNodeIndex) { type Safety = hir::Safety; type Abi = ExternAbi; type Const = ty::Const<'tcx>; - type PlaceholderConst = ty::PlaceholderConst; + type PlaceholderConst = ty::PlaceholderConst<'tcx>; type ParamConst = ty::ParamConst; type BoundConst = ty::BoundConst; @@ -170,7 +170,7 @@ fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, DepNodeIndex) { type EarlyParamRegion = ty::EarlyParamRegion; type LateParamRegion = ty::LateParamRegion; type BoundRegion = ty::BoundRegion; - type PlaceholderRegion = ty::PlaceholderRegion; + type PlaceholderRegion = ty::PlaceholderRegion<'tcx>; type RegionAssumptions = &'tcx ty::List>; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d3e0fbb955c4..f732a7c91d1f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -886,20 +886,9 @@ pub fn build_mismatch_error( } } -/// The "placeholder index" fully defines a placeholder region, type, or const. Placeholders are -/// identified by both a universe, as well as a name residing within that universe. Distinct bound -/// regions/types/consts within the same universe simply have an unknown relationship to one -/// another. -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[derive(HashStable, TyEncodable, TyDecodable)] -pub struct Placeholder { - pub universe: UniverseIndex, - pub bound: T, -} +pub type PlaceholderRegion<'tcx> = ty::Placeholder, BoundRegion>; -pub type PlaceholderRegion = Placeholder; - -impl<'tcx> rustc_type_ir::inherent::PlaceholderLike> for PlaceholderRegion { +impl<'tcx> rustc_type_ir::inherent::PlaceholderLike> for PlaceholderRegion<'tcx> { type Bound = BoundRegion; fn universe(self) -> UniverseIndex { @@ -911,21 +900,21 @@ fn var(self) -> BoundVar { } fn with_updated_universe(self, ui: UniverseIndex) -> Self { - Placeholder { universe: ui, ..self } + ty::Placeholder::new(ui, self.bound) } fn new(ui: UniverseIndex, bound: BoundRegion) -> Self { - Placeholder { universe: ui, bound } + ty::Placeholder::new(ui, bound) } fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self { - Placeholder { universe: ui, bound: BoundRegion { var, kind: BoundRegionKind::Anon } } + ty::Placeholder::new(ui, BoundRegion { var, kind: BoundRegionKind::Anon }) } } -pub type PlaceholderType = Placeholder; +pub type PlaceholderType<'tcx> = ty::Placeholder, BoundTy>; -impl<'tcx> rustc_type_ir::inherent::PlaceholderLike> for PlaceholderType { +impl<'tcx> rustc_type_ir::inherent::PlaceholderLike> for PlaceholderType<'tcx> { type Bound = BoundTy; fn universe(self) -> UniverseIndex { @@ -937,15 +926,15 @@ fn var(self) -> BoundVar { } fn with_updated_universe(self, ui: UniverseIndex) -> Self { - Placeholder { universe: ui, ..self } + ty::Placeholder::new(ui, self.bound) } fn new(ui: UniverseIndex, bound: BoundTy) -> Self { - Placeholder { universe: ui, bound } + ty::Placeholder::new(ui, bound) } fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self { - Placeholder { universe: ui, bound: BoundTy { var, kind: BoundTyKind::Anon } } + ty::Placeholder::new(ui, BoundTy { var, kind: BoundTyKind::Anon }) } } @@ -965,9 +954,9 @@ fn assert_eq(self, var: ty::BoundVariableKind) { } } -pub type PlaceholderConst = Placeholder; +pub type PlaceholderConst<'tcx> = ty::Placeholder, BoundConst>; -impl<'tcx> rustc_type_ir::inherent::PlaceholderLike> for PlaceholderConst { +impl<'tcx> rustc_type_ir::inherent::PlaceholderLike> for PlaceholderConst<'tcx> { type Bound = BoundConst; fn universe(self) -> UniverseIndex { @@ -979,15 +968,15 @@ fn var(self) -> BoundVar { } fn with_updated_universe(self, ui: UniverseIndex) -> Self { - Placeholder { universe: ui, ..self } + ty::Placeholder::new(ui, self.bound) } fn new(ui: UniverseIndex, bound: BoundConst) -> Self { - Placeholder { universe: ui, bound } + ty::Placeholder::new(ui, bound) } fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self { - Placeholder { universe: ui, bound: BoundConst { var } } + ty::Placeholder::new(ui, BoundConst { var }) } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 6a4122ad6717..798e14c6f378 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3274,6 +3274,16 @@ macro_rules! define_print_and_forward_display { p.reset_type_limit(); self.term.print(p)?; } + + ty::PlaceholderType<'tcx> { + match self.bound.kind { + ty::BoundTyKind::Anon => write!(p, "{self:?}")?, + ty::BoundTyKind::Param(def_id) => match p.should_print_verbose() { + true => write!(p, "{self:?}")?, + false => write!(p, "{}", p.tcx().item_name(def_id))?, + }, + } + } } define_print_and_forward_display! { @@ -3338,16 +3348,6 @@ macro_rules! define_print_and_forward_display { write!(p, "{}", self.name)?; } - ty::PlaceholderType { - match self.bound.kind { - ty::BoundTyKind::Anon => write!(p, "{self:?}")?, - ty::BoundTyKind::Param(def_id) => match p.should_print_verbose() { - true => write!(p, "{self:?}")?, - false => write!(p, "{}", p.tcx().item_name(def_id))?, - }, - } - } - ty::ParamConst { write!(p, "{}", self.name)?; } diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index f0687f2bc726..61994d928dec 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -97,7 +97,10 @@ pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::RegionVid) -> Region<'tcx> { } #[inline] - pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Region<'tcx> { + pub fn new_placeholder( + tcx: TyCtxt<'tcx>, + placeholder: ty::PlaceholderRegion<'tcx>, + ) -> Region<'tcx> { tcx.intern_region(ty::RePlaceholder(placeholder)) } @@ -170,7 +173,7 @@ fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: rustc_type_ir::BoundVar) -> Self Region::new_canonical_bound(tcx, var) } - fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Self { + fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion<'tcx>) -> Self { Region::new_placeholder(tcx, placeholder) } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index cff415e9036a..4f70830002ce 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -184,16 +184,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } -impl fmt::Debug for ty::Placeholder { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.universe == ty::UniverseIndex::ROOT { - write!(f, "!{:?}", self.bound) - } else { - write!(f, "!{}_{:?}", self.universe.index(), self.bound) - } - } -} - impl<'tcx> fmt::Debug for GenericArg<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.kind() { @@ -294,8 +284,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // interners). TrivialTypeTraversalAndLiftImpls! { // tidy-alphabetical-start + crate::ty::BoundTy, crate::ty::ParamTy, - crate::ty::PlaceholderType, crate::ty::instance::ReifyReason, rustc_hir::def_id::DefId, // tidy-alphabetical-end diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e71bb9b6bb26..72573d96dc54 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -39,6 +39,7 @@ pub type Binder<'tcx, T> = ir::Binder, T>; pub type EarlyBinder<'tcx, T> = ir::EarlyBinder, T>; pub type TypingMode<'tcx> = ir::TypingMode>; +pub type Placeholder<'tcx, T> = ir::Placeholder, T>; pub trait Article { fn article(&self) -> &'static str; @@ -508,7 +509,7 @@ pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: BoundVar) -> Ty<'tcx> { } #[inline] - pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderType) -> Ty<'tcx> { + pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderType<'tcx>) -> Ty<'tcx> { Ty::new(tcx, Placeholder(placeholder)) } @@ -957,7 +958,7 @@ fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamTy) -> Self { Ty::new_param(tcx, param.index, param.name) } - fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderType) -> Self { + fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderType<'tcx>) -> Self { Ty::new_placeholder(tcx, placeholder) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index da888acc4755..fdaf2d619dd5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -980,7 +980,7 @@ fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) { fn report_sub_sup_conflict( &self, generic_param_scope: LocalDefId, - var_origin: RegionVariableOrigin, + var_origin: RegionVariableOrigin<'tcx>, sub_origin: SubregionOrigin<'tcx>, sub_region: Region<'tcx>, sup_origin: SubregionOrigin<'tcx>, @@ -1051,7 +1051,7 @@ fn report_sub_sup_conflict( if sub_region.is_error() | sup_region.is_error() { err.delay_as_bug() } else { err.emit() } } - fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_> { + fn report_inference_failure(&self, var_origin: RegionVariableOrigin<'tcx>) -> Diag<'_> { let br_string = |br: ty::BoundRegionKind| { let mut s = match br { ty::BoundRegionKind::Named(def_id) => self.tcx.item_name(def_id).to_string(), diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 45357be56399..2aae5f2cde1e 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -566,13 +566,10 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) { ty, Ty::new_placeholder( self.infcx.tcx, - ty::Placeholder { - universe: self.universe, - bound: ty::BoundTy { - var: self.next_var(), - kind: ty::BoundTyKind::Anon, - }, - }, + ty::Placeholder::new( + self.universe, + ty::BoundTy { var: self.next_var(), kind: ty::BoundTyKind::Anon }, + ), ), ) else { @@ -595,10 +592,10 @@ fn visit_const(&mut self, ct: ty::Const<'tcx>) { ct, ty::Const::new_placeholder( self.infcx.tcx, - ty::Placeholder { - universe: self.universe, - bound: ty::BoundConst { var: self.next_var() }, - }, + ty::Placeholder::new( + self.universe, + ty::BoundConst { var: self.next_var() }, + ), ), ) else { @@ -626,13 +623,13 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) { r, ty::Region::new_placeholder( self.infcx.tcx, - ty::Placeholder { - universe: self.universe, - bound: ty::BoundRegion { + ty::Placeholder::new( + self.universe, + ty::BoundRegion { var: self.next_var(), kind: ty::BoundRegionKind::Anon, }, - }, + ), ), ) else { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index ccde214f6aa3..5839a8c2e295 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -756,10 +756,10 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { self.idx += 1; Ty::new_placeholder( self.tcx, - ty::PlaceholderType { - universe: ty::UniverseIndex::ROOT, - bound: ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon }, - }, + ty::PlaceholderType::new( + ty::UniverseIndex::ROOT, + ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon }, + ), ) } else { t.super_fold_with(self) @@ -772,10 +772,7 @@ fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { self.idx += 1; ty::Const::new_placeholder( self.tcx, - ty::PlaceholderConst { - universe: ty::UniverseIndex::ROOT, - bound: ty::BoundConst { var: idx }, - }, + ty::PlaceholderConst::new(ty::UniverseIndex::ROOT, ty::BoundConst { var: idx }), ) } else { c.super_fold_with(self) diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index e1d1ad1b3765..19ccf6a55bf1 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -220,9 +220,9 @@ pub fn with_replaced_escaping_bound_vars< /// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came. pub struct PlaceholderReplacer<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, - mapped_regions: FxIndexMap, - mapped_types: FxIndexMap, - mapped_consts: FxIndexMap, + mapped_regions: FxIndexMap, ty::BoundRegion>, + mapped_types: FxIndexMap, ty::BoundTy>, + mapped_consts: FxIndexMap, ty::BoundConst>, universe_indices: &'a [Option], current_index: ty::DebruijnIndex, } @@ -230,9 +230,9 @@ pub struct PlaceholderReplacer<'a, 'tcx> { impl<'a, 'tcx> PlaceholderReplacer<'a, 'tcx> { pub fn replace_placeholders>>( infcx: &'a InferCtxt<'tcx>, - mapped_regions: FxIndexMap, - mapped_types: FxIndexMap, - mapped_consts: FxIndexMap, + mapped_regions: FxIndexMap, ty::BoundRegion>, + mapped_types: FxIndexMap, ty::BoundTy>, + mapped_consts: FxIndexMap, ty::BoundConst>, universe_indices: &'a [Option], value: T, ) -> T { diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 94b950357e1e..d005ae95d6f1 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -1,3 +1,4 @@ +use std::fmt; use std::marker::PhantomData; use std::ops::{ControlFlow, Deref}; @@ -12,7 +13,7 @@ use crate::inherent::*; use crate::lift::Lift; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use crate::{self as ty, DebruijnIndex, Interner}; +use crate::{self as ty, DebruijnIndex, Interner, UniverseIndex}; /// `Binder` is a binder for higher-ranked lifetimes or types. It is part of the /// compiler's representation for things like `for<'a> Fn(&'a isize)` @@ -948,3 +949,55 @@ pub enum BoundVarIndexKind { Bound(DebruijnIndex), Canonical, } + +/// The "placeholder index" fully defines a placeholder region, type, or const. Placeholders are +/// identified by both a universe, as well as a name residing within that universe. Distinct bound +/// regions/types/consts within the same universe simply have an unknown relationship to one +/// another. +#[derive_where(Clone, PartialEq, Ord, Hash; I: Interner, T)] +#[derive_where(PartialOrd; I: Interner, T: Ord)] +#[derive_where(Copy; I: Interner, T: Copy, T)] +#[derive_where(Eq; T)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] +pub struct Placeholder { + pub universe: UniverseIndex, + pub bound: T, + #[type_foldable(identity)] + #[type_visitable(ignore)] + _tcx: PhantomData I>, +} + +impl Placeholder { + pub fn new(universe: UniverseIndex, bound: T) -> Self { + Placeholder { universe, bound, _tcx: PhantomData } + } +} + +impl fmt::Debug for ty::Placeholder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.universe == ty::UniverseIndex::ROOT { + write!(f, "!{:?}", self.bound) + } else { + write!(f, "!{}_{:?}", self.universe.index(), self.bound) + } + } +} + +impl Lift for Placeholder +where + T: Lift, +{ + type Lifted = Placeholder; + + fn lift_to_interner(self, cx: U) -> Option { + Some(Placeholder { + universe: self.universe, + bound: self.bound.lift_to_interner(cx)?, + _tcx: PhantomData, + }) + } +} diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index 82bb8791b846..5af2bd811bab 100644 --- a/compiler/rustc_type_ir/src/ir_print.rs +++ b/compiler/rustc_type_ir/src/ir_print.rs @@ -3,7 +3,8 @@ use crate::{ AliasTerm, AliasTy, Binder, ClosureKind, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig, HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, - PatternKind, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, UnevaluatedConst, + PatternKind, Placeholder, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, + UnevaluatedConst, }; pub trait IrPrint { @@ -23,15 +24,6 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { } } -impl fmt::Display for Binder -where - I: IrPrint>, -{ - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - >>::print(self, fmt) - } -} - macro_rules! define_debug_via_print { ($($ty:ident),+ $(,)?) => { $( @@ -71,6 +63,24 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { } } +impl fmt::Display for Binder +where + I: IrPrint>, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + >>::print(self, fmt) + } +} + +impl fmt::Display for Placeholder +where + I: IrPrint>, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + >>::print(self, fmt) + } +} + #[cfg(feature = "nightly")] mod into_diag_arg_impls { use rustc_error_messages::{DiagArgValue, IntoDiagArg}; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 8065db1e05dd..31fe0aac1de4 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -61,7 +61,7 @@ pub use RegionKind::*; pub use TyKind::*; pub use Variance::*; -pub use binder::*; +pub use binder::{Placeholder, *}; pub use canonical::*; pub use const_kind::*; pub use flags::*; From 4c6544b06ef037f8d0e29f1c010486609442a891 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 9 Dec 2025 12:14:28 +0100 Subject: [PATCH 422/585] Run clippy both with and without default features on the GCC backend --- src/bootstrap/src/core/build_steps/clippy.rs | 22 +++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index d8b74b43cfab..f80cf58fbb2a 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -379,15 +379,23 @@ fn run(self, builder: &Builder<'_>) -> Self::Output { let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, Mode::Codegen, target)) .with_prefix("rustc_codegen_gcc-check"); - run_cargo( + let args = lint_args(builder, &self.config, &[]); + run_cargo(builder, cargo, args.clone(), &stamp, vec![], true, false); + + // Same but we disable the features enabled by default. + let mut cargo = prepare_tool_cargo( builder, - cargo, - lint_args(builder, &self.config, &[]), - &stamp, - vec![], - true, - false, + build_compiler, + Mode::Codegen, + target, + Kind::Clippy, + "compiler/rustc_codegen_gcc", + SourceType::InTree, + &[], ); + self.build_compiler.configure_cargo(&mut cargo); + cargo.arg("--no-default-features"); + run_cargo(builder, cargo, args, &stamp, vec![], true, false); } fn metadata(&self) -> Option { From 50e9839d4849d932810ebba52a664d39baed5253 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Tue, 9 Dec 2025 00:31:56 +0800 Subject: [PATCH 423/585] Don't suggest wrapping attr in unsafe if it may come from proc macro --- compiler/rustc_attr_parsing/src/safety.rs | 19 ++++++++-- .../src/session_diagnostics.rs | 2 +- compiler/rustc_lint/src/early/diagnostics.rs | 14 +++---- compiler/rustc_lint/src/lints.rs | 2 +- compiler/rustc_lint_defs/src/lib.rs | 2 +- .../auxiliary/unsafe-attributes-pm-in-2024.rs | 29 +++++++++++++++ .../unsafe-attributes-from-pm-in-2024.rs | 18 +++++++++ .../unsafe-attributes-from-pm-in-2024.stderr | 37 +++++++++++++++++++ 8 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 tests/ui/rust-2024/unsafe-attributes/auxiliary/unsafe-attributes-pm-in-2024.rs create mode 100644 tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-from-pm-in-2024.rs create mode 100644 tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-from-pm-in-2024.stderr diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs index 52baf2136173..817785108a1e 100644 --- a/compiler/rustc_attr_parsing/src/safety.rs +++ b/compiler/rustc_attr_parsing/src/safety.rs @@ -62,16 +62,28 @@ pub fn check_attribute_safety( Some(unsafe_since) => path_span.edition() >= unsafe_since, }; + let mut not_from_proc_macro = true; + if diag_span.from_expansion() + && let Ok(mut snippet) = self.sess.source_map().span_to_snippet(diag_span) + { + snippet.retain(|c| !c.is_whitespace()); + if snippet.contains("!(") || snippet.starts_with("#[") && snippet.ends_with("]") + { + not_from_proc_macro = false; + } + } + if emit_error { self.stage.emit_err( self.sess, crate::session_diagnostics::UnsafeAttrOutsideUnsafe { span: path_span, - suggestion: + suggestion: not_from_proc_macro.then(|| { crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion { left: diag_span.shrink_to_lo(), right: diag_span.shrink_to_hi(), - }, + } + }), }, ); } else { @@ -81,7 +93,8 @@ pub fn check_attribute_safety( span: path_span, kind: AttributeLintKind::UnsafeAttrOutsideUnsafe { attribute_name_span: path_span, - sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), + sugg_spans: not_from_proc_macro + .then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi())), }, }) } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index c4f6f9c6a38c..cf3f3760d962 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -758,7 +758,7 @@ pub(crate) struct UnsafeAttrOutsideUnsafe { #[label] pub span: Span, #[subdiagnostic] - pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, + pub suggestion: Option, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 589594a3ec5e..c44e0ba67daa 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -353,14 +353,14 @@ pub fn decorate_attribute_lint( } .decorate_lint(diag) } - &AttributeLintKind::UnsafeAttrOutsideUnsafe { - attribute_name_span, - sugg_spans: (left, right), - } => lints::UnsafeAttrOutsideUnsafeLint { - span: attribute_name_span, - suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }, + &AttributeLintKind::UnsafeAttrOutsideUnsafe { attribute_name_span, sugg_spans } => { + lints::UnsafeAttrOutsideUnsafeLint { + span: attribute_name_span, + suggestion: sugg_spans + .map(|(left, right)| lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }), + } + .decorate_lint(diag) } - .decorate_lint(diag), &AttributeLintKind::UnexpectedCfgName(name, value) => { check_cfg::unexpected_cfg_name(sess, tcx, name, value).decorate_lint(diag) } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 1bec316ce45a..20262c9c6bcf 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3177,7 +3177,7 @@ pub(crate) struct UnsafeAttrOutsideUnsafeLint { #[label] pub span: Span, #[subdiagnostic] - pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, + pub suggestion: Option, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 376310838cc7..bb153afecc4c 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -729,7 +729,7 @@ pub enum AttributeLintKind { }, UnsafeAttrOutsideUnsafe { attribute_name_span: Span, - sugg_spans: (Span, Span), + sugg_spans: Option<(Span, Span)>, }, UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), diff --git a/tests/ui/rust-2024/unsafe-attributes/auxiliary/unsafe-attributes-pm-in-2024.rs b/tests/ui/rust-2024/unsafe-attributes/auxiliary/unsafe-attributes-pm-in-2024.rs new file mode 100644 index 000000000000..5f44223df90c --- /dev/null +++ b/tests/ui/rust-2024/unsafe-attributes/auxiliary/unsafe-attributes-pm-in-2024.rs @@ -0,0 +1,29 @@ +//@ edition: 2024 + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro] +pub fn missing_unsafe(_input: TokenStream) -> TokenStream { + "#[no_mangle] pub fn abc() {}".parse().unwrap() +} + +#[proc_macro_attribute] +pub fn attr_missing_unsafe(_attr: TokenStream, _input: TokenStream) -> TokenStream { + "#[no_mangle] pub fn bar() {}".parse().unwrap() +} + +#[proc_macro_derive(AttrMissingUnsafe)] +pub fn derive_attr_missing_unsafe(_input: TokenStream) -> TokenStream { + "#[no_mangle] pub fn baz() {}".parse().unwrap() +} + +#[proc_macro] +pub fn macro_rules_missing_unsafe(_input: TokenStream) -> TokenStream { + "macro_rules! make_fn { + () => { #[no_mangle] pub fn foo() { } }; + }" + .parse() + .unwrap() +} diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-from-pm-in-2024.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-from-pm-in-2024.rs new file mode 100644 index 000000000000..dca05cc27f6e --- /dev/null +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-from-pm-in-2024.rs @@ -0,0 +1,18 @@ +// Test for unsafe attributes generated by a proc-macro. + +//@ proc-macro: unsafe-attributes-pm-in-2024.rs +//@ ignore-backends: gcc + +unsafe_attributes_pm_in_2024::missing_unsafe!(); //~ ERROR unsafe attribute used without unsafe + +#[unsafe_attributes_pm_in_2024::attr_missing_unsafe] //~ ERROR unsafe attribute used without unsafe +pub fn bar() {} + +#[derive(unsafe_attributes_pm_in_2024::AttrMissingUnsafe)] //~ ERROR unsafe attribute used without unsafe +struct Baz; + +unsafe_attributes_pm_in_2024::macro_rules_missing_unsafe!(); //~ ERROR unsafe attribute used without unsafe + +make_fn!(); + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-from-pm-in-2024.stderr b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-from-pm-in-2024.stderr new file mode 100644 index 000000000000..fa36b148bf3d --- /dev/null +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-from-pm-in-2024.stderr @@ -0,0 +1,37 @@ +error: unsafe attribute used without unsafe + --> $DIR/unsafe-attributes-from-pm-in-2024.rs:6:1 + | +LL | unsafe_attributes_pm_in_2024::missing_unsafe!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ usage of unsafe attribute + | + = note: this error originates in the macro `unsafe_attributes_pm_in_2024::missing_unsafe` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unsafe attribute used without unsafe + --> $DIR/unsafe-attributes-from-pm-in-2024.rs:8:1 + | +LL | #[unsafe_attributes_pm_in_2024::attr_missing_unsafe] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ usage of unsafe attribute + | + = note: this error originates in the attribute macro `unsafe_attributes_pm_in_2024::attr_missing_unsafe` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unsafe attribute used without unsafe + --> $DIR/unsafe-attributes-from-pm-in-2024.rs:11:10 + | +LL | #[derive(unsafe_attributes_pm_in_2024::AttrMissingUnsafe)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ usage of unsafe attribute + | + = note: this error originates in the derive macro `unsafe_attributes_pm_in_2024::AttrMissingUnsafe` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unsafe attribute used without unsafe + --> $DIR/unsafe-attributes-from-pm-in-2024.rs:14:1 + | +LL | unsafe_attributes_pm_in_2024::macro_rules_missing_unsafe!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ usage of unsafe attribute +LL | +LL | make_fn!(); + | ---------- in this macro invocation + | + = note: this error originates in the macro `make_fn` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + From 4501327be4fb0aa85a6e2d8bb29c43da658e09bf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 9 Dec 2025 15:42:22 +0100 Subject: [PATCH 424/585] Fix clippy lint in `cg_gcc` --- compiler/rustc_codegen_gcc/src/builder.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 1787415b72e6..df1e64c75b96 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -500,11 +500,11 @@ impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { } fn set_rvalue_location<'a, 'gcc, 'tcx>( - bx: &mut Builder<'a, 'gcc, 'tcx>, + _bx: &mut Builder<'a, 'gcc, 'tcx>, rvalue: RValue<'gcc>, ) -> RValue<'gcc> { - if let Some(location) = bx.location { - #[cfg(feature = "master")] + #[cfg(feature = "master")] + if let Some(location) = _bx.location { rvalue.set_location(location); } rvalue From 3551aeb5c3c4570e170cd433892eaa3f2507ce2e Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 5 Dec 2025 21:02:51 +0000 Subject: [PATCH 425/585] fix: `tuple_array_conversions` FP when binded vars are used before conversion --- clippy_lints/src/tuple_array_conversions.rs | 41 +++++++++++++++------ tests/ui/tuple_array_conversions.rs | 23 ++++++++++++ tests/ui/tuple_array_conversions.stderr | 10 ++++- 3 files changed, 61 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs index 5d0945bece55..98bf9f9fea58 100644 --- a/clippy_lints/src/tuple_array_conversions.rs +++ b/clippy_lints/src/tuple_array_conversions.rs @@ -1,9 +1,9 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeResPath; -use clippy_utils::visitors::for_each_local_use_after_expr; +use clippy_utils::visitors::local_used_once; +use clippy_utils::{get_enclosing_block, is_from_proc_macro}; use itertools::Itertools; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind, Node, PatKind}; @@ -11,7 +11,6 @@ use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; use std::iter::once; -use std::ops::ControlFlow; declare_clippy_lint! { /// ### What it does @@ -86,7 +85,7 @@ fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: & ExprKind::Path(_) => Some(elements.iter().collect()), _ => None, }) - && all_bindings_are_for_conv(cx, &[ty], expr, elements, &locals, ToType::Array) + && all_bindings_are_for_conv(cx, &[ty], elements, &locals, ToType::Array) && !is_from_proc_macro(cx, expr) { span_lint_and_help( @@ -123,7 +122,7 @@ fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: & ExprKind::Path(_) => Some(elements.iter().collect()), _ => None, }) - && all_bindings_are_for_conv(cx, tys, expr, elements, &locals, ToType::Tuple) + && all_bindings_are_for_conv(cx, tys, elements, &locals, ToType::Tuple) && !is_from_proc_macro(cx, expr) { span_lint_and_help( @@ -148,7 +147,6 @@ fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: & fn all_bindings_are_for_conv<'tcx>( cx: &LateContext<'tcx>, final_tys: &[Ty<'tcx>], - expr: &Expr<'_>, elements: &[Expr<'_>], locals: &[&Expr<'_>], kind: ToType, @@ -166,13 +164,30 @@ fn all_bindings_are_for_conv<'tcx>( _ => None, }) .all_equal() - // Fix #11124, very convenient utils function! ❤️ - && locals - .iter() - .all(|&l| for_each_local_use_after_expr(cx, l, expr.hir_id, |_| ControlFlow::Break::<()>(())).is_continue()) + && locals.iter().zip(local_parents.iter()).all(|(&l, &parent)| { + if let Node::LetStmt(_) = parent { + return true; + } + + let Some(b) = get_enclosing_block(cx, l) else { + return true; + }; + local_used_once(cx, b, l).is_some() + }) && local_parents.first().is_some_and(|node| { let Some(ty) = match node { - Node::Pat(pat) => Some(pat.hir_id), + Node::Pat(pat) + if let PatKind::Tuple(pats, _) | PatKind::Slice(pats, None, []) = &pat.kind + && pats.iter().zip(locals.iter()).all(|(p, l)| { + if let PatKind::Binding(_, id, _, _) = p.kind { + id == *l + } else { + true + } + }) => + { + Some(pat.hir_id) + }, Node::LetStmt(l) => Some(l.hir_id), _ => None, } @@ -186,7 +201,9 @@ fn all_bindings_are_for_conv<'tcx>( tys.len() == elements.len() && tys.iter().chain(final_tys.iter().copied()).all_equal() }, (ToType::Tuple, ty::Array(ty, len)) => { - let Some(len) = len.try_to_target_usize(cx.tcx) else { return false }; + let Some(len) = len.try_to_target_usize(cx.tcx) else { + return false; + }; len as usize == elements.len() && final_tys.iter().chain(once(ty)).all_equal() }, _ => false, diff --git a/tests/ui/tuple_array_conversions.rs b/tests/ui/tuple_array_conversions.rs index 772c41df090e..17e6a252b266 100644 --- a/tests/ui/tuple_array_conversions.rs +++ b/tests/ui/tuple_array_conversions.rs @@ -116,3 +116,26 @@ fn msrv_juust_right() { let x = &[1, 2]; let x = (x[0], x[1]); } + +fn issue16192() { + fn do_something(tuple: (u32, u32)) {} + fn produce_array() -> [u32; 2] { + [1, 2] + } + + let [a, b] = produce_array(); + for tuple in [(a, b), (b, a)] { + do_something(tuple); + } + + let [a, b] = produce_array(); + let x = b; + do_something((a, b)); + + let [a, b] = produce_array(); + do_something((b, a)); + + let [a, b] = produce_array(); + do_something((a, b)); + //~^ tuple_array_conversions +} diff --git a/tests/ui/tuple_array_conversions.stderr b/tests/ui/tuple_array_conversions.stderr index 6dafb8d285d4..4c15769b7487 100644 --- a/tests/ui/tuple_array_conversions.stderr +++ b/tests/ui/tuple_array_conversions.stderr @@ -80,5 +80,13 @@ LL | let x = [x.0, x.1]; | = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed -error: aborting due to 10 previous errors +error: it looks like you're trying to convert an array to a tuple + --> tests/ui/tuple_array_conversions.rs:139:18 + | +LL | do_something((a, b)); + | ^^^^^^ + | + = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed + +error: aborting due to 11 previous errors From 20fabb48b90b00c59c79354dc819fb5148fa1c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 4 Nov 2025 18:00:38 +0000 Subject: [PATCH 426/585] Use return type `Span` on async fns instead of whole fn def `Span` --- compiler/rustc_ast_lowering/src/lib.rs | 5 ++--- .../ui/async-await/async-await-let-else.stderr | 2 +- .../async-fn/recurse-ice-129215.stderr | 4 ++-- ...ync-example-desugared-boxed-in-trait.stderr | 4 ++-- .../async-example-desugared-boxed.stderr | 2 +- .../async-example-desugared-manual.stderr | 2 +- .../in-trait/async-generics-and-bounds.stderr | 18 ++++++++---------- .../async-await/in-trait/async-generics.stderr | 18 ++++++++---------- ...-project-to-specializable-projection.stderr | 8 ++++---- .../inference_var_self_argument.stderr | 4 ++-- .../ui/async-await/issue-64130-3-other.stderr | 2 +- tests/ui/async-await/issues/issue-67893.stderr | 4 ++-- .../partial-drop-partial-reinit.stderr | 2 +- tests/ui/c-variadic/not-async.stderr | 12 ++++++------ .../cmse-nonsecure-entry/c-variadic.stderr | 4 ++-- .../in-trait/async-and-ret-ref.stderr | 10 +++++----- .../note-and-explain-ReVar-124973.stderr | 6 +++--- .../lifetimes/issue-76168-hr-outlives-3.stderr | 18 ++++++------------ .../type-match-with-late-bound.stderr | 13 +++++-------- .../hkl_forbidden4.stderr | 4 ++-- 20 files changed, 64 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index dff46ece6543..19e826cf18f3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1670,7 +1670,7 @@ fn lower_fn_decl( let output = match coro { Some(coro) => { let fn_def_id = self.local_def_id(fn_node_id); - self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind, fn_span) + self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind) } None => match &decl.output { FnRetTy::Ty(ty) => { @@ -1755,9 +1755,8 @@ fn lower_coroutine_fn_ret_ty( fn_def_id: LocalDefId, coro: CoroutineKind, fn_kind: FnDeclKind, - fn_span: Span, ) -> hir::FnRetTy<'hir> { - let span = self.lower_span(fn_span); + let span = self.lower_span(output.span()); let (opaque_ty_node_id, allowed_features) = match coro { CoroutineKind::Async { return_impl_trait_id, .. } => (return_impl_trait_id, None), diff --git a/tests/ui/async-await/async-await-let-else.stderr b/tests/ui/async-await/async-await-let-else.stderr index 5883f34f87de..b5b56d3242f4 100644 --- a/tests/ui/async-await/async-await-let-else.stderr +++ b/tests/ui/async-await/async-await-let-else.stderr @@ -22,7 +22,7 @@ error[E0277]: `Rc<()>` cannot be sent between threads safely --> $DIR/async-await-let-else.rs:47:13 | LL | async fn foo2(x: Option) { - | ------------------------------ within this `impl Future` + | - within this `impl Future` ... LL | is_send(foo2(Some(true))); | ------- ^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely diff --git a/tests/ui/async-await/async-fn/recurse-ice-129215.stderr b/tests/ui/async-await/async-fn/recurse-ice-129215.stderr index 98c7be2a5a3f..232246590cf1 100644 --- a/tests/ui/async-await/async-fn/recurse-ice-129215.stderr +++ b/tests/ui/async-await/async-fn/recurse-ice-129215.stderr @@ -7,10 +7,10 @@ LL | a() = help: the trait `Future` is not implemented for `()` error[E0277]: `()` is not a future - --> $DIR/recurse-ice-129215.rs:3:1 + --> $DIR/recurse-ice-129215.rs:3:13 | LL | async fn a() { - | ^^^^^^^^^^^^ `()` is not a future + | ^ `()` is not a future | = help: the trait `Future` is not implemented for `()` diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr index 54df0edf5a8e..c98df134072e 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr +++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr @@ -1,8 +1,8 @@ error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/async-example-desugared-boxed-in-trait.rs:11:5 + --> $DIR/async-example-desugared-boxed-in-trait.rs:11:28 | LL | async fn foo(&self) -> i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin>>`, found future + | ^^^ expected `Pin>>`, found future | note: type in trait --> $DIR/async-example-desugared-boxed-in-trait.rs:7:22 diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr index b7f2879727f2..d3765a7e6e6f 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr +++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr @@ -2,7 +2,7 @@ warning: impl trait in impl method signature does not match trait method signatu --> $DIR/async-example-desugared-boxed.rs:14:22 | LL | async fn foo(&self) -> i32; - | --------------------------- return type from trait method defined here + | --- return type from trait method defined here ... LL | fn foo(&self) -> Pin + '_>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr b/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr index 86546df88c17..3328dea37fe4 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr +++ b/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr @@ -2,7 +2,7 @@ warning: impl trait in impl method signature does not match trait method signatu --> $DIR/async-example-desugared-manual.rs:22:22 | LL | async fn foo(&self) -> i32; - | --------------------------- return type from trait method defined here + | --- return type from trait method defined here ... LL | fn foo(&self) -> MyFuture { | ^^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr index 183b0fa152aa..52fd887b296f 100644 --- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr @@ -1,11 +1,10 @@ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/async-generics-and-bounds.rs:8:5 + --> $DIR/async-generics-and-bounds.rs:8:28 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; - | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | the parameter type `T` must be valid for the anonymous lifetime as defined here... - | ...so that the reference type `&(T, U)` does not outlive the data it points at + | - ^^^^^^^ ...so that the reference type `&(T, U)` does not outlive the data it points at + | | + | the parameter type `T` must be valid for the anonymous lifetime as defined here... | help: consider adding an explicit lifetime bound | @@ -13,13 +12,12 @@ LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Has | ++++ ++ ++ +++++++ error[E0311]: the parameter type `U` may not live long enough - --> $DIR/async-generics-and-bounds.rs:8:5 + --> $DIR/async-generics-and-bounds.rs:8:28 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; - | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | the parameter type `U` must be valid for the anonymous lifetime as defined here... - | ...so that the reference type `&(T, U)` does not outlive the data it points at + | - ^^^^^^^ ...so that the reference type `&(T, U)` does not outlive the data it points at + | | + | the parameter type `U` must be valid for the anonymous lifetime as defined here... | help: consider adding an explicit lifetime bound | diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.stderr index 8916ef5ab683..3f44e4cdb677 100644 --- a/tests/ui/async-await/in-trait/async-generics.stderr +++ b/tests/ui/async-await/in-trait/async-generics.stderr @@ -1,11 +1,10 @@ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/async-generics.rs:5:5 + --> $DIR/async-generics.rs:5:28 | LL | async fn foo(&self) -> &(T, U); - | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^ - | | | - | | the parameter type `T` must be valid for the anonymous lifetime as defined here... - | ...so that the reference type `&(T, U)` does not outlive the data it points at + | - ^^^^^^^ ...so that the reference type `&(T, U)` does not outlive the data it points at + | | + | the parameter type `T` must be valid for the anonymous lifetime as defined here... | help: consider adding an explicit lifetime bound | @@ -13,13 +12,12 @@ LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: 'a; | ++++ ++ ++ +++++++++++ error[E0311]: the parameter type `U` may not live long enough - --> $DIR/async-generics.rs:5:5 + --> $DIR/async-generics.rs:5:28 | LL | async fn foo(&self) -> &(T, U); - | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^ - | | | - | | the parameter type `U` must be valid for the anonymous lifetime as defined here... - | ...so that the reference type `&(T, U)` does not outlive the data it points at + | - ^^^^^^^ ...so that the reference type `&(T, U)` does not outlive the data it points at + | | + | the parameter type `U` must be valid for the anonymous lifetime as defined here... | help: consider adding an explicit lifetime bound | diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr index 823d8d5b92fc..d0c11565f4e9 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr @@ -1,14 +1,14 @@ error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/dont-project-to-specializable-projection.rs:14:5 + --> $DIR/dont-project-to-specializable-projection.rs:14:35 | LL | default async fn foo(_: T) -> &'static str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found future + | ^^^^^^^^^^^^ expected associated type, found future | note: type in trait - --> $DIR/dont-project-to-specializable-projection.rs:10:5 + --> $DIR/dont-project-to-specializable-projection.rs:10:27 | LL | async fn foo(_: T) -> &'static str; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ = note: expected signature `fn(_) -> impl Future` found signature `fn(_) -> impl Future` diff --git a/tests/ui/async-await/inference_var_self_argument.stderr b/tests/ui/async-await/inference_var_self_argument.stderr index 1fccc32470ff..c4240a095e68 100644 --- a/tests/ui/async-await/inference_var_self_argument.stderr +++ b/tests/ui/async-await/inference_var_self_argument.stderr @@ -8,10 +8,10 @@ LL | async fn foo(self: &dyn Foo) { = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin